home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / CONTRIB / HTTPD / HTTPD_SO.TAR / httpd_1.3 / src / http_script.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-07  |  12.8 KB  |  485 lines

  1. /*
  2.  * http_script: keeps all script-related ramblings together.
  3.  * 
  4.  * Compliant to CGI/1.0 spec
  5.  * 
  6.  * Rob McCool
  7.  *
  8.  */
  9.  
  10. #include "httpd.h"
  11.  
  12. int pid;
  13.  
  14. void kill_children() {
  15.     char errstr[MAX_STRING_LEN];
  16.     sprintf(errstr,"killing CGI process %d",pid);
  17.     log_error_noclose(errstr);
  18.  
  19.     kill(pid,SIGTERM);
  20.     sleep(3); /* give them time to clean up */
  21.     kill(pid,SIGKILL);
  22.     waitpid(pid,NULL,0);
  23. }
  24.  
  25. char **create_argv(char *av0, char *args, FILE *out) {
  26.     register int x,n;
  27.     char **av;
  28.     char w[HUGE_STRING_LEN];
  29.     char l[HUGE_STRING_LEN];
  30.  
  31.     for(x=0,n=2;args[x];x++)
  32.         if(args[x] == '+') ++n;
  33.  
  34.     if(!(av = (char **)malloc((n+1)*sizeof(char *))))
  35.         die(NO_MEMORY,"create_argv",out);
  36.     av[0] = av0;
  37.     strcpy(l,args);
  38.     for(x=1;x<n;x++) {
  39.         getword(w,l,'+');
  40.         unescape_url(w);
  41.         escape_shell_cmd(w);
  42.         if(!(av[x] = strdup(w)))
  43.             die(NO_MEMORY,"create_argv",out);
  44.     }
  45.     av[n] = NULL;
  46.     return av;
  47. }
  48.  
  49. void get_path_info(char *path, char *path_args, FILE *out, 
  50.                    struct stat *finfo)
  51. {
  52.     register int x,max;
  53.     char t[HUGE_STRING_LEN];
  54.  
  55.     path_args[0] = '\0';
  56.     max=count_dirs(path);
  57.     for(x=dirs_in_alias;x<=max;x++) {
  58.         make_dirstr(path,x+1,t);
  59.         if(!(stat(t,finfo))) {
  60.             if(S_ISREG(finfo->st_mode)) {
  61.                 int l=strlen(t);
  62.                 strcpy(path_args,&path[l]);
  63.                 path[l] = '\0';
  64.                 return;
  65.             }
  66.         }
  67.     }
  68.     for(x=dirs_in_alias - 1;x;--x) {
  69.         make_dirstr(path,x+1,t);
  70.         if(!(stat(t,finfo))) {
  71.             if(S_ISREG(finfo->st_mode)) {
  72.                 strcpy(path_args,&path[strlen(t)]);
  73.                 strcpy(path,t);
  74.                 return;
  75.             }
  76.         }
  77.     }
  78.     unmunge_name(path);
  79.     die(NOT_FOUND,path,out);
  80. }
  81.  
  82. #define MAX_COMMON_VARS 9
  83. #define MAX_CGI_VARS (MAX_COMMON_VARS+9)
  84.  
  85. char **add_cgi_vars(char **env,
  86.                     char *method, char *path, char *path_args, char *args,
  87.                     int *content,
  88.                     FILE *out)
  89. {
  90.     int x;
  91.     char t[HUGE_STRING_LEN],t2[HUGE_STRING_LEN];
  92.  
  93.     if(!(env = new_env(env,MAX_CGI_VARS,&x)))
  94.         die(NO_MEMORY,"add_cgi_vars",out);
  95.  
  96.     env[x++] = make_env_str("GATEWAY_INTERFACE","CGI/1.1",out);
  97.  
  98.     env[x++] = make_env_str("SERVER_PROTOCOL",
  99.               (assbackwards ? "HTTP/0.9" : "HTTP/1.0"),out);
  100.     env[x++] = make_env_str("REQUEST_METHOD",method,out);
  101.  
  102.     strcpy(t,path);
  103.     unmunge_name(t);
  104.     env[x++] = make_env_str("SCRIPT_NAME",t,out);
  105.     if(path_args[0]) {
  106.         env[x++] = make_env_str("PATH_INFO",path_args,out);
  107.         strcpy(t2,path_args);
  108.         translate_name(t2,out);
  109.         env[x++] = make_env_str("PATH_TRANSLATED",t2,out);
  110.     }
  111.     env[x++] = make_env_str("QUERY_STRING",args,out);
  112.  
  113.     if(content) {
  114.         *content=0;
  115.         if((!strcmp(method,"POST")) || (!strcmp(method,"PUT"))) {
  116.             *content=1;
  117.             sprintf(t,"%d",content_length);
  118.             env[x++] = make_env_str("CONTENT_TYPE",content_type,out);
  119.             env[x++] = make_env_str("CONTENT_LENGTH",t,out);
  120.         }
  121.     }
  122.     env[x] = NULL;
  123.     return env;
  124. }
  125.  
  126. char **add_common_vars(char **env,FILE *out) {
  127.     char t[HUGE_STRING_LEN],*env_path;
  128.     int x;
  129.  
  130.     if(!(env = new_env(env,MAX_COMMON_VARS,&x)))
  131.         die(NO_MEMORY,"add_common_vars",out);
  132.     
  133.     if(!(env_path = getenv("PATH")))
  134.         env_path=DEFAULT_PATH;
  135.     env[x++] = make_env_str("PATH",env_path,out);
  136.     env[x++] = make_env_str("SERVER_SOFTWARE",SERVER_VERSION,out);
  137.     env[x++] = make_env_str("SERVER_NAME",server_hostname,out);
  138.     sprintf(t,"%d",port);
  139.     env[x++] = make_env_str("SERVER_PORT",t,out);
  140.     env[x++] = make_env_str("REMOTE_HOST",remote_name,out);
  141.     env[x++] = make_env_str("REMOTE_ADDR",remote_ip,out);
  142.     if(user[0])
  143.         env[x++] = make_env_str("REMOTE_USER",user,out);
  144.     if(auth_type)
  145.         env[x++] = make_env_str("AUTH_TYPE",auth_type,out);
  146.     if(do_rfc931)
  147.         env[x++] = make_env_str("REMOTE_IDENT",remote_logname,out);
  148.     env[x] = NULL;
  149.     return env;
  150. }
  151.  
  152. int cgi_stub(char *method, char *path, char *path_args, char *args,
  153.              char **env, struct stat *finfo, int in, FILE *out)
  154. {
  155.     int p[2];
  156.     int content, nph;
  157.     char *argv0;
  158.     FILE *psin;
  159.     register int x;
  160.  
  161.     if(!can_exec(finfo)) {
  162.         unmunge_name(path);
  163.         die(FORBIDDEN,path,out);
  164.     }
  165.  
  166.     if((argv0 = strrchr(path,'/')) != NULL)
  167.         argv0++;
  168.     else argv0 = path;
  169.  
  170.     chdir_file(path);
  171.  
  172.     if(pipe(p) < 0)
  173.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  174.     if((pid = fork()) < 0)
  175.         die(SERVER_ERROR,"httpd: could not fork new process",out);
  176.  
  177.     nph = (strncmp(argv0,"nph-",4) ? 0 : 1);
  178.     if(!pid) {
  179.         close(p[0]);
  180.         env = add_cgi_vars(env,method,path,path_args,args,&content,out);
  181.         if(content)
  182.             if(in != STDIN_FILENO) {
  183.                 dup2(in,STDIN_FILENO);
  184.                 close(in);
  185.             }
  186.         if(nph) {
  187.             if(fileno(out) != STDOUT_FILENO) {
  188.                 dup2(fileno(out),STDOUT_FILENO);
  189.                 fclose(out);
  190.             }
  191.         } else {
  192.             if(p[1] != STDOUT_FILENO) {
  193.                 dup2(p[1],STDOUT_FILENO);
  194.                 close(p[1]);
  195.             }
  196.         }
  197.         error_log2stderr();
  198.         /* Only ISINDEX scripts get decoded arguments. */
  199.         if((!args[0]) || (ind(args,'=') >= 0)) {
  200.             if(execle(path,argv0,(char *)0,env) == -1) {
  201.                 fprintf(stderr,"httpd: exec of %s failed, errno is %d\n",
  202.                         path,errno);
  203.                 exit(1);
  204.             }
  205.         }
  206.         else {
  207.             if(execve(path,create_argv(argv0,args,out),env) == -1) {
  208.                 fprintf(stderr,"httpd: exec of %s failed, errno is %d\n",
  209.                         path,errno);
  210.                 exit(1);
  211.             }
  212.         }
  213.     }
  214.     else {
  215.         close(p[1]);
  216.     }
  217.  
  218.     if(!nph) {
  219.         if(!(psin = fdopen(p[0],"r")))
  220.             die(SERVER_ERROR,"could not read from script",out);
  221.  
  222.         if(scan_script_header(psin,out)) {
  223.             kill_children(); /* !!! */
  224.             return REDIRECT_URL;
  225.         }
  226.  
  227.         if(location[0] == '/') {
  228.             char t[HUGE_STRING_LEN],a[HUGE_STRING_LEN],*argp;
  229.  
  230.             a[0] = '\0';
  231.             fclose(psin);
  232.             waitpid(pid,NULL,0);
  233.             strcpy(t,location);
  234.             if(argp = strchr(t,'?')) {
  235.                 *argp++ = '\0';
  236.                 strcpy(a,argp);
  237.             }
  238.             init_header_vars(); /* clear in_header_env and location */
  239.             process_get(in,out,"GET",t,a);
  240.             return 0;
  241.         }
  242.         content_length = -1;
  243.         if(!assbackwards)
  244.             send_http_header(out);
  245.         if(!header_only)
  246.             send_fd(psin,out,kill_children);
  247.         else
  248.             kill_children();
  249.         fclose(psin);
  250.     }
  251.     else bytes_sent = -1;
  252.     waitpid(pid,NULL,0);
  253.     return 0;
  254. }
  255.  
  256. /* Called for ScriptAliased directories */
  257. void exec_cgi_script(char *method, char *path, char *args, int in, FILE *out)
  258. {
  259.     struct stat finfo;
  260.     char path_args[HUGE_STRING_LEN];
  261.     char **env;
  262.     int m;
  263.  
  264.     get_path_info(path,path_args,out,&finfo);
  265.     if((!strcmp(method,"GET")) || (!strcmp(method,"HEAD"))) m=M_GET;
  266.     else if(!strcmp(method,"POST")) m=M_POST;
  267.     else if(!strcmp(method,"PUT")) m=M_PUT;
  268.     else if(!strcmp(method,"DELETE")) m=M_DELETE;
  269.  
  270.     evaluate_access(path,&finfo,m,&allow,&allow_options,out);
  271.     if(!allow) {
  272.         log_reason("client denied by server configuration",path);
  273.         unmunge_name(path);
  274.         die(FORBIDDEN,path,out);
  275.     }
  276.     if(!(env = add_common_vars(in_headers_env,out)))
  277.         die(NO_MEMORY,"exec_cgi_script",out);
  278.  
  279.     bytes_sent = 0;
  280.     if(cgi_stub(method,path,path_args,args,env,&finfo,in,out) == REDIRECT_URL)
  281.         die(REDIRECT,location,out);
  282.     /* cgi_stub will screw with env, but only after the fork */
  283.     free_env(env);
  284.     log_transaction();
  285. }
  286.  
  287. char **set_env_NCSA(FILE *out) {
  288.     char **env;
  289.     int n;
  290.     char t[MAX_STRING_LEN];
  291.  
  292.     if(!(env = (char **) malloc ((4+2)*sizeof(char *))))
  293.         die(NO_MEMORY,"set_env_NCSA",out);
  294.     n=0;
  295.     env[n++] = make_env_str("PATH",getenv("PATH"),out);
  296.  
  297.     env[n++] = make_env_str("DOCUMENT_ROOT",document_root,out);
  298.     env[n++] = make_env_str("SERVER_ROOT",server_root,out);
  299.     env[n++] = make_env_str("REMOTE_HOST",remote_name,out);
  300.     sprintf(t,"SERVER_NAME=%s:%d",server_hostname,port);
  301.     if(!(env[n++] = strdup(t)))
  302.         die(NO_MEMORY,"set_env_NCSA",out);
  303.     env[n] = NULL;
  304.     return env;
  305. }
  306.  
  307. void exec_get_NCSA(char *path, char *args, int in, FILE *fd) {
  308.     FILE *tfp;
  309.     struct stat finfo;
  310.     int pfd[2];
  311.     char path_args[MAX_STRING_LEN];
  312.     char t[MAX_STRING_LEN];
  313.     register int n,x;
  314.     char **env;
  315.  
  316.     env = set_env_NCSA(fd);
  317.  
  318.     path_args[0] = '\0';
  319.     /* check if it's really a script with extra args */
  320.     n=count_dirs(path);
  321.     for(x=0;x<=n;x++) {
  322.         make_dirstr(path,x+1,t);
  323.         if(!(stat(t,&finfo))) {
  324.             if(S_ISREG(finfo.st_mode)) {
  325.                 strcpy(path_args,&path[strlen(t)]);
  326.                 strcpy(path,t);
  327.                 goto run_script;
  328.             }
  329.         }
  330.     }
  331.     log_reason("script not found or unable to stat",path);
  332.     unmunge_name(path);
  333.     die(NOT_FOUND,path,fd);
  334.   run_script:
  335.     if(!can_exec(&finfo)) {
  336.         log_reason("file permissions deny server execution",path);
  337.         unmunge_name(path);
  338.         die(FORBIDDEN,path,fd);
  339.     }
  340.     evaluate_access(path,&finfo,M_GET,&allow,&allow_options,fd);
  341.     if(!allow) {
  342.         unmunge_name(path);
  343.         die(FORBIDDEN,path,fd);
  344.     }
  345.  
  346.     if(pipe(pfd) < 0)
  347.         die(SERVER_ERROR,"could not open pipe",fd);
  348.  
  349.     signal(SIGALRM,send_fd_timed_out);
  350.     signal(SIGPIPE,send_fd_timed_out);
  351.     alarm(timeout);
  352.  
  353.     if((pid = fork()) < 0)
  354.         die(SERVER_ERROR,"could not fork",fd);
  355.     else if(!pid) {
  356.         char *argv0;
  357.  
  358.         close(pfd[0]);
  359.         if(pfd[1] != STDOUT_FILENO) {
  360.             dup2(pfd[1],STDOUT_FILENO);
  361.             close(pfd[1]);
  362.         }
  363.         if(argv0 = strrchr(path,'/'))
  364.             argv0++;
  365.         else
  366.             argv0 = path;
  367.         if(args[0] && path_args[0]) {
  368.             if(execle(path,argv0,path_args,args,(char *)0,env) == -1)
  369.                 exit(1);
  370.         }
  371.         else if(args[0]) {
  372.             if(execle(path,argv0,args,(char *)0,env) == -1)
  373.                 exit(1);
  374.         }
  375.         else if(path_args[0]) {
  376.             if(execle(path,argv0,path_args,(char *)0,env) == -1)
  377.                 exit(1);
  378.         }
  379.         else
  380.             if(execle(path,argv0,(char *)0,env) == -1)
  381.                 exit(1);
  382.     }
  383.     else
  384.         close(pfd[1]);
  385.  
  386.     tfp = fdopen(pfd[0],"r");
  387.  
  388.     if(scan_script_header(tfp,fd))
  389.         die(REDIRECT,location,fd);
  390.  
  391.     if(location[0] == '/') {
  392.         char *t;
  393.         if(!(t = strdup(location)))
  394.             die(NO_MEMORY,"exec_get_NCSA",fd);
  395.         location[0] = '\0';
  396.         send_node(t,"",in,fd);
  397.         htexit(0,fd);
  398.     }
  399.  
  400.     if(!assbackwards)
  401.         send_http_header(fd);
  402.  
  403.     if(!header_only)
  404.         send_fd(tfp,fd,kill_children);
  405.     else
  406.         kill_children();
  407.     fclose(tfp);
  408.     waitpid(pid,NULL,0);
  409. }
  410.  
  411.  
  412.  
  413. void exec_post_NCSA(char *path, char *args, int in, FILE *out) {
  414.     int inpipe[2],outpipe[2], x;
  415.     char cl[MAX_STRING_LEN];
  416.     FILE *psin,*psout;
  417.     struct stat finfo;
  418.     char **env;
  419.     
  420.     env = set_env_NCSA(out);
  421.  
  422.     sprintf(cl,"%d",content_length);
  423.  
  424.     if(stat(path,&finfo) == -1) {
  425.         unmunge_name(path);
  426.         if(errno == ENOENT) die(NOT_FOUND,path,out);
  427.         die(FORBIDDEN,path,out);
  428.     }
  429.     evaluate_access(path,&finfo,M_POST,&allow,&allow_options,out);
  430.     if(!allow)
  431.         die(FORBIDDEN,path,out);
  432.  
  433.     if(pipe(inpipe) < 0)
  434.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  435.     if(pipe(outpipe) < 0)
  436.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  437.     if((pid = fork()) < 0)
  438.         die(SERVER_ERROR,"httpd: could not fork new process",out);
  439.  
  440.     if(!pid) {
  441.         char *argv0;
  442.  
  443.         if(outpipe[1] != STDOUT_FILENO) {
  444.             dup2(outpipe[1],STDOUT_FILENO);
  445.             close(outpipe[1]);
  446.         }
  447.         if(in != STDIN_FILENO) {
  448.             dup2(in,STDIN_FILENO);
  449.             close(in);
  450.         }
  451.         if((argv0 = strrchr(path,'/')) != NULL)
  452.             argv0++;
  453.         else argv0 = path;
  454.         if(execle(path,argv0,cl,args,(char *)0,env) == -1)
  455.             exit(1);
  456.     }
  457.     else {
  458.         close(outpipe[1]);
  459.         close(inpipe[0]);
  460.     }
  461.  
  462.     if(!(psin = fdopen(outpipe[0],"r")))
  463.         die(SERVER_ERROR,"could not read from script",out);
  464.  
  465.     if(scan_script_header(psin,out))
  466.         die(REDIRECT,location,out);
  467.  
  468.     if(location[0] == '/') {
  469.         char *t;
  470.         if(!(t = strdup(location)))
  471.             die(NO_MEMORY,"exec_post_NCSA",out);
  472.         location[0] = '\0';
  473.         send_node(t,"",in,out);
  474.         htexit(0,out);
  475.     }
  476.  
  477.     content_length = -1;
  478.     if(!assbackwards)
  479.         send_http_header(out);
  480.  
  481.     send_fd(psin,out,kill_children);
  482.     fclose(psin);
  483.     waitpid(pid,NULL,0);
  484. }
  485.