home *** CD-ROM | disk | FTP | other *** search
/ The HTML Web Publisher's Construction Kit / HTMLWPCK.ISO / unix / servers / httpd_14 / source.z / source / httpd_1.4.1 / src / http_script.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-18  |  16.6 KB  |  592 lines

  1. /*
  2.  * http_script: keeps all script-related ramblings together.
  3.  * 
  4.  * All code contained herein is covered by the Copyright as distributed
  5.  * in the README file in the main directory of the distribution of 
  6.  * NCSA HTTPD.
  7.  *
  8.  * Based on NCSA HTTPd 1.3 by Rob McCool
  9.  *
  10.  * 03-07-95 blong
  11.  *    Added support for variable REMOTE_GROUP from access files
  12.  *
  13.  * 03-20-95 sguillory
  14.  *    Moved to more dynamic memory management of environment arrays
  15.  *
  16.  * 04-03-95 blong
  17.  *    Added support for variables DOCUMENT_ROOT, ERROR_STATUS
  18.  *    ERROR_URL, ERROR_REQUEST
  19.  *
  20.  * 04-20-95 blong
  21.  *    Added Apache patch "B18" from Rob Hartill to allow nondelayed redirects
  22.  *
  23.  * 05-02-95 blong
  24.  *    Since Apache is using REDIRECT_ as the env variables, I've decided to 
  25.  *    go with this in the interest of general Internet Harmony and Peace.
  26.  */
  27.  
  28. #include "httpd.h"
  29. #include "new.h"
  30.  
  31. int pid;
  32.  
  33. void kill_children() {
  34.     char errstr[MAX_STRING_LEN];
  35.     sprintf(errstr,"killing CGI process %d",pid);
  36.     log_error_noclose(errstr);
  37.  
  38.     kill(pid,SIGTERM);
  39.     sleep(3); /* give them time to clean up */
  40.     kill(pid,SIGKILL);
  41.     waitpid(pid,NULL,0);
  42. }
  43.  
  44. char **create_argv(char *av0, char *args, FILE *out) {
  45.     register int x,n;
  46.     char **av;
  47.     char w[HUGE_STRING_LEN];
  48.     char l[HUGE_STRING_LEN];
  49.  
  50.     for(x=0,n=2;args[x];x++)
  51.         if(args[x] == '+') ++n;
  52.  
  53.     if(!(av = (char **)malloc((n+1)*sizeof(char *))))
  54.         die(NO_MEMORY,"create_argv",out);
  55.     av[0] = av0;
  56.     strcpy(l,args);
  57.     for(x=1;x<n;x++) {
  58.         getword(w,l,'+');
  59.         unescape_url(w);
  60.         escape_shell_cmd(w);
  61.         if(!(av[x] = strdup(w)))
  62.             die(NO_MEMORY,"create_argv",out);
  63.     }
  64.     av[n] = NULL;
  65.     return av;
  66. }
  67.  
  68. void get_path_info(char *path, char *path_args, FILE *out, 
  69.                    struct stat *finfo)
  70. {
  71.     register int x,max;
  72.     char t[HUGE_STRING_LEN];
  73.  
  74.     path_args[0] = '\0';
  75.     max=count_dirs(path);
  76.     for(x=dirs_in_alias;x<=max;x++) {
  77.         make_dirstr(path,x+1,t);
  78.         if(!(stat(t,finfo))) {
  79.             if(S_ISREG(finfo->st_mode)) {
  80.                 int l=strlen(t);
  81.                 strcpy(path_args,&path[l]);
  82.                 path[l] = '\0';
  83.                 return;
  84.             }
  85.         }
  86.     }
  87.     for(x=dirs_in_alias - 1;x;--x) {
  88.         make_dirstr(path,x+1,t);
  89.         if(!(stat(t,finfo))) {
  90.             if(S_ISREG(finfo->st_mode)) {
  91.                 strcpy(path_args,&path[strlen(t)]);
  92.                 strcpy(path,t);
  93.                 return;
  94.             }
  95.         }
  96.     }
  97.     unmunge_name(path);
  98.     log_reason("script does not exist",path);
  99.     die(NOT_FOUND,path,out);
  100. }
  101.  
  102. #define MAX_COMMON_VARS 16
  103. #define MAX_CGI_VARS (MAX_COMMON_VARS+16)
  104.  
  105. char **add_cgi_vars(char **env,
  106.                     char *method, char *path, char *path_args, char *args,
  107.                     int *content,
  108.                     FILE *out)
  109. {
  110.     int x;
  111.     char t[HUGE_STRING_LEN],t2[HUGE_STRING_LEN];
  112.  
  113.     if(!(env = new_env(env,MAX_CGI_VARS,&x)))
  114.         die(NO_MEMORY,"add_cgi_vars",out);
  115.  
  116.     env[x++] = make_env_str("GATEWAY_INTERFACE","CGI/1.1",out);
  117.  
  118.     env[x++] = make_env_str("SERVER_PROTOCOL",
  119.               (assbackwards ? "HTTP/0.9" : "HTTP/1.0"),out);
  120.     env[x++] = make_env_str("DOCUMENT_ROOT",document_root,out);
  121.     env[x++] = make_env_str("REQUEST_METHOD",method,out);
  122.  
  123.     strcpy(t,path);
  124.     unmunge_name(t);
  125.     env[x++] = make_env_str("SCRIPT_NAME",t,out);
  126.     if(path_args[0]) {
  127.         env[x++] = make_env_str("PATH_INFO",path_args,out);
  128.         strcpy(t2,path_args);
  129.         translate_name(t2,out);
  130.         env[x++] = make_env_str("PATH_TRANSLATED",t2,out);
  131.     }
  132.     env[x++] = make_env_str("QUERY_STRING",args,out);
  133.  
  134.     if(content) {
  135.         *content=0;
  136.         if((!strcmp(method,"POST")) || (!strcmp(method,"PUT"))) {
  137.             *content=1;
  138.             sprintf(t,"%d",content_length);
  139.             env[x++] = make_env_str("CONTENT_TYPE",content_type,out);
  140.             env[x++] = make_env_str("CONTENT_LENGTH",t,out);
  141.         }
  142.     }
  143.     if (ErrorStat) {
  144.       if (failed_request[0]) 
  145.     env[x++] = make_env_str("REDIRECT_REQUEST",failed_request,out);
  146.       if (failed_url[0])
  147.     env[x++] = make_env_str("REDIRECT_URL",failed_url,out);
  148.       env[x++] = make_env_str("REDIRECT_STATUS",set_stat_line(),out);
  149.     }
  150.     env[x] = NULL;
  151.     return env;
  152. }
  153.  
  154. char **add_common_vars(char **env,FILE *out) {
  155.     char t[MAX_STRING_LEN],*env_path,*env_tz;
  156.     int x;
  157.  
  158.     if(!(env = new_env(env,MAX_COMMON_VARS,&x)))
  159.         die(NO_MEMORY,"add_common_vars",out);
  160.     
  161.     if(!(env_path = getenv("PATH")))
  162.         env_path=DEFAULT_PATH;
  163.     env[x++] = make_env_str("PATH",env_path,out);
  164.     if((env_tz = getenv("TZ")))
  165.     env[x++] = make_env_str("TZ",env_tz,out);
  166.     env[x++] = make_env_str("SERVER_SOFTWARE",SERVER_VERSION,out);
  167.     env[x++] = make_env_str("SERVER_NAME",server_hostname,out);
  168.     sprintf(t,"%d",port);
  169.     env[x++] = make_env_str("SERVER_PORT",t,out);
  170.     env[x++] = make_env_str("REMOTE_HOST",remote_name,out);
  171.     env[x++] = make_env_str("REMOTE_ADDR",remote_ip,out);
  172.     env[x++] = make_env_str("DOCUMENT_ROOT",document_root,out);
  173.     if(user[0])
  174.         env[x++] = make_env_str("REMOTE_USER",user,out);
  175.     if(annotation_server[0])
  176.         env[x++] = make_env_str("ANNOTATION_SERVER",annotation_server,out);
  177.     if(groupname[0])
  178.     env[x++] = make_env_str("REMOTE_GROUP",groupname,out);
  179.     if(auth_type)
  180.         env[x++] = make_env_str("AUTH_TYPE",auth_type,out);
  181.     if(do_rfc931)
  182.         env[x++] = make_env_str("REMOTE_IDENT",remote_logname,out);
  183.     if (ErrorStat) {
  184.       if (failed_request[0]) 
  185.         env[x++] = make_env_str("REDIRECT_REQUEST",failed_request,out);
  186.       if (failed_url[0]) 
  187.         env[x++] = make_env_str("REDIRECT_URL",failed_url,out);
  188.       env[x++] = make_env_str("REDIRECT_STATUS",set_stat_line(),out);
  189.     }
  190.     env[x] = NULL;
  191.     return env;
  192. }
  193.  
  194. int cgi_stub(char *method, char *path, char *path_args, char *args,
  195.              char **env, struct stat *finfo, int in, FILE *out)
  196. {
  197.     int p[2];
  198.     int content, nph;
  199.     char *argv0;
  200.     FILE *psin;
  201.     char errlog[100];
  202.  
  203.     if(!can_exec(finfo)) {
  204.         unmunge_name(path);
  205.         die(FORBIDDEN,path,out);
  206.     }
  207.  
  208.     if((argv0 = strrchr(path,'/')) != NULL)
  209.         argv0++;
  210.     else argv0 = path;
  211.  
  212.     chdir_file(path);
  213.  
  214.     if(pipe(p) < 0)
  215.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  216.     if((pid = fork()) < 0) {
  217.     sprintf(errlog,"httpd: could not fork new process: 2/%d",errno);
  218.         die(SERVER_ERROR,errlog,out);
  219.     }
  220.  
  221.     nph = (strncmp(argv0,"nph-",4) ? 0 : 1);
  222.     if(!pid) {
  223.         close(p[0]);
  224.         in_headers_env = add_cgi_vars(in_headers_env,method,path,path_args,args,&content,out);
  225.         if(content)
  226.             if(in != STDIN_FILENO) {
  227.                 dup2(in,STDIN_FILENO);
  228.                 close(in);
  229.             }
  230.         if(nph) {
  231.             if(fileno(out) != STDOUT_FILENO) {
  232.                 dup2(fileno(out),STDOUT_FILENO);
  233.                 fclose(out);
  234.             }
  235.         } else {
  236.             if(p[1] != STDOUT_FILENO) {
  237.                 dup2(p[1],STDOUT_FILENO);
  238.                 close(p[1]);
  239.             }
  240.         }
  241.         error_log2stderr();
  242. /* To make the signal handling work on HPUX, according to 
  243.    David-Michael Lincke (dlincke@bandon.unisg.ch) */
  244. #ifdef HPUX
  245.     signal(SIGCHLD, SIG_DFL);
  246. #endif
  247.         /* Only ISINDEX scripts get decoded arguments. */
  248.         if((!args[0]) || (ind(args,'=') >= 0)) {
  249.             if(execle(path,argv0,(char *)0,in_headers_env) == -1) {
  250.                 fprintf(stderr,"httpd: exec of %s failed, errno is %d\n",
  251.                         path,errno);
  252.                 exit(1);
  253.             }
  254.         }
  255.         else {
  256.             if(execve(path,create_argv(argv0,args,out),in_headers_env) == -1) {
  257.                 fprintf(stderr,"httpd: exec of %s failed, errno is %d\n",
  258.                         path,errno);
  259.                 exit(1);
  260.             }
  261.         }
  262.     }
  263.     else {
  264.     if (nph) close(p[0]);
  265.         close(p[1]);
  266.     }
  267.  
  268.     if(!nph) {
  269.         if(!(psin = fdopen(p[0],"r")))
  270.             die(SERVER_ERROR,"could not read from script",out);
  271.  
  272.         scan_script_header(psin,out);
  273.         /* we never redirect and die now 
  274.           if(scan_script_header(psin,out)) {
  275.               kill_children(); 
  276.               return REDIRECT_URL;
  277.           }
  278.         */
  279.  
  280.  
  281.         if(location[0] == '/') {
  282.             char t[HUGE_STRING_LEN],a[HUGE_STRING_LEN],*argp;
  283.  
  284.             a[0] = '\0';
  285.             fclose(psin);
  286.             waitpid(pid,NULL,0);
  287.             strcpy(t,location);
  288.             if(argp = strchr(t,'?')) {
  289.                 *argp++ = '\0';
  290.                 strcpy(a,argp);
  291.             }
  292.         status = 302;
  293.         log_transaction();
  294.         status = 200;
  295.             init_header_vars(); /* clear in_header_env and location */
  296.         sprintf(the_request,"GET ");
  297.         strncat(the_request,t,HUGE_STRING_LEN - strlen(the_request));
  298.         if (a[0] != '\0') {
  299.         strncat(the_request,"?",HUGE_STRING_LEN - strlen(the_request));
  300.         strncat(the_request,a, HUGE_STRING_LEN - strlen(the_request));
  301.         }
  302.         
  303.         strncat(the_request," ",HUGE_STRING_LEN - strlen(the_request));
  304.         strncat(the_request,protocal, HUGE_STRING_LEN - strlen(the_request));
  305.             process_get(in,out,"GET",t,a);
  306.             return REDIRECT_LOCAL;
  307.         }
  308.         content_length = -1;
  309.         if(!assbackwards)
  310.             send_http_header(out);
  311.         if(!header_only) {
  312.             /* Send a default body of text if the script
  313.                 failed to produce any, but ONLY for redirects */
  314.             if (!send_fd(psin,out,NULL) && location[0]) {
  315.                  title_html(out,"Document moved");
  316.                  fprintf(out,"This document has moved <A HREF=\"%s\">here</A>.<P>%c",location,LF); 
  317.             }
  318.         } else
  319.             kill_children();
  320.         fclose(psin);
  321.     }
  322.     else bytes_sent = -1;
  323.     waitpid(pid,NULL,0);
  324.     return 0;
  325. }
  326.  
  327. /* Called for ScriptAliased directories */
  328. void exec_cgi_script(char *method, char *path, char *args, int in, FILE *out)
  329. {
  330.     struct stat finfo;
  331.     char path_args[HUGE_STRING_LEN];
  332.     int m = M_GET;
  333.     int stub_returns;
  334.  
  335.     get_path_info(path,path_args,out,&finfo);
  336.     if((!strcmp(method,"GET")) || (!strcmp(method,"HEAD"))) m=M_GET;
  337.     else if(!strcmp(method,"POST")) m=M_POST;
  338.     else if(!strcmp(method,"PUT")) m=M_PUT;
  339.     else if(!strcmp(method,"DELETE")) m=M_DELETE;
  340.  
  341.     evaluate_access(path,&finfo,m,&allow,&allow_options,out);
  342.     if(!allow) {
  343.         log_reason("client denied by server configuration",path);
  344.         unmunge_name(path);
  345.         die(FORBIDDEN,path,out);
  346.     }
  347.     if(!(in_headers_env = add_common_vars(in_headers_env,out))) {
  348.     free_env(in_headers_env);
  349.     in_headers_env = NULL;
  350.         die(NO_MEMORY,"exec_cgi_script",out);
  351.     }
  352.  
  353.     bytes_sent = 0;
  354.     stub_returns = cgi_stub(method,path,path_args,args,in_headers_env,&finfo,in,out);
  355.     if (in_headers_env != NULL) { 
  356.       free_env(in_headers_env);
  357.       in_headers_env = NULL;
  358.     }
  359.  
  360.     switch (stub_returns) {
  361.     case REDIRECT_URL:
  362.         die(REDIRECT,location,out);
  363.         break;
  364.     case REDIRECT_LOCAL:
  365.         break;
  366.     default:
  367.         log_transaction();
  368.         break;
  369.     }
  370. }
  371.  
  372. char **set_env_NCSA(FILE *out) {
  373.     char **env;
  374.     int n;
  375.     char t[MAX_STRING_LEN];
  376.  
  377.     if(!(env = (char **) malloc ((4+2)*sizeof(char *))))
  378.         die(NO_MEMORY,"set_env_NCSA",out);
  379.     n=0;
  380.     env[n++] = make_env_str("PATH",getenv("PATH"),out);
  381.  
  382.     env[n++] = make_env_str("DOCUMENT_ROOT",document_root,out);
  383.     env[n++] = make_env_str("SERVER_ROOT",server_root,out);
  384.     env[n++] = make_env_str("REMOTE_HOST",remote_name,out);
  385.     sprintf(t,"SERVER_NAME=%s:%d",server_hostname,port);
  386.     if(!(env[n++] = strdup(t)))
  387.         die(NO_MEMORY,"set_env_NCSA",out);
  388.     env[n] = NULL;
  389.     return env;
  390. }
  391.  
  392. void exec_get_NCSA(char *path, char *args, int in, FILE *fd) {
  393.     FILE *tfp;
  394.     struct stat finfo;
  395.     int pfd[2];
  396.     char path_args[MAX_STRING_LEN];
  397.     char t[MAX_STRING_LEN];
  398.     register int n,x;
  399.     char **env;
  400.  
  401.     env = set_env_NCSA(fd);
  402.  
  403.     path_args[0] = '\0';
  404.     /* check if it's really a script with extra args */
  405.     n=count_dirs(path);
  406.     for(x=0;x<=n;x++) {
  407.         make_dirstr(path,x+1,t);
  408.         if(!(stat(t,&finfo))) {
  409.             if(S_ISREG(finfo.st_mode)) {
  410.                 strcpy(path_args,&path[strlen(t)]);
  411.                 strcpy(path,t);
  412.                 goto run_script;
  413.             }
  414.         }
  415.     }
  416.     log_reason("script not found or unable to stat",path);
  417.     unmunge_name(path);
  418.     die(NOT_FOUND,path,fd);
  419.   run_script:
  420.     if(!can_exec(&finfo)) {
  421.         log_reason("file permissions deny server execution",path);
  422.         unmunge_name(path);
  423.         die(FORBIDDEN,path,fd);
  424.     }
  425.     evaluate_access(path,&finfo,M_GET,&allow,&allow_options,fd);
  426.     if(!allow) {
  427.         unmunge_name(path);
  428.         die(FORBIDDEN,path,fd);
  429.     }
  430.  
  431.     if(pipe(pfd) < 0)
  432.         die(SERVER_ERROR,"could not open pipe",fd);
  433.  
  434.     signal(SIGALRM,send_fd_timed_out);
  435.     signal(SIGPIPE,send_fd_timed_out);
  436.     alarm(timeout);
  437.  
  438.     if((pid = fork()) < 0)
  439.         die(SERVER_ERROR,"could not fork",fd);
  440.     else if(!pid) {
  441.         char *argv0;
  442.  
  443.         close(pfd[0]);
  444.         if(pfd[1] != STDOUT_FILENO) {
  445.             dup2(pfd[1],STDOUT_FILENO);
  446.             close(pfd[1]);
  447.         }
  448.         if(argv0 = strrchr(path,'/'))
  449.             argv0++;
  450.         else
  451.             argv0 = path;
  452.         if(args[0] && path_args[0]) {
  453.             if(execle(path,argv0,path_args,args,(char *)0,env) == -1)
  454.                 exit(1);
  455.         }
  456.         else if(args[0]) {
  457.             if(execle(path,argv0,args,(char *)0,env) == -1)
  458.                 exit(1);
  459.         }
  460.         else if(path_args[0]) {
  461.             if(execle(path,argv0,path_args,(char *)0,env) == -1)
  462.                 exit(1);
  463.         }
  464.         else
  465.             if(execle(path,argv0,(char *)0,env) == -1)
  466.                 exit(1);
  467.     }
  468.     else
  469.         close(pfd[1]);
  470.  
  471.     tfp = fdopen(pfd[0],"r");
  472.  
  473.  
  474.     scan_script_header(tfp,fd);
  475.     /*  don't force the redirect.. it'll happen
  476.     if(scan_script_header(tfp,fd))
  477.         die(REDIRECT,location,fd);
  478.     */
  479.  
  480.     if(location[0] == '/') {
  481.         char *t;
  482.         if(!(t = strdup(location)))
  483.             die(NO_MEMORY,"exec_get_NCSA",fd);
  484.         location[0] = '\0';
  485.         send_node(t,"",in,fd);
  486.     fclose(tfp);
  487.         htexit(0,fd);
  488.     }
  489.  
  490.     if(!assbackwards)
  491.         send_http_header(fd);
  492.  
  493.     if(!header_only) {
  494.         /* Send a default body of text if the script
  495.             failed to produce any, but ONLY for redirects */
  496.         if (!send_fd(tfp,fd,NULL) &&  location[0]) {
  497.            title_html(fd,"Document moved");
  498.            fprintf(fd,"This document has moved <A HREF=\"%s\">here</A>.<P>%c",location,LF);
  499.         }
  500.     } else
  501.         kill_children();
  502.     fclose(tfp);
  503.     waitpid(pid,NULL,0);
  504. }
  505.  
  506.  
  507.  
  508. void exec_post_NCSA(char *path, char *args, int in, FILE *out) {
  509.     int inpipe[2],outpipe[2];
  510.     char cl[MAX_STRING_LEN];
  511.     FILE *psin;
  512.     struct stat finfo;
  513.     char **env;
  514.     char errlog[100];
  515.  
  516.     env = set_env_NCSA(out);
  517.  
  518.     sprintf(cl,"%d",content_length);
  519.  
  520.     if(stat(path,&finfo) == -1) {
  521.         unmunge_name(path);
  522.         if(errno == ENOENT) die(NOT_FOUND,path,out);
  523.         die(FORBIDDEN,path,out);
  524.     }
  525.     evaluate_access(path,&finfo,M_POST,&allow,&allow_options,out);
  526.     if(!allow)
  527.         die(FORBIDDEN,path,out);
  528.  
  529.     if(pipe(inpipe) < 0)
  530.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  531.     if(pipe(outpipe) < 0)
  532.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  533.     if((pid = fork()) < 0) {
  534.     sprintf(errlog,"httpd: could not fork new process 1/%d",errno);
  535.         die(SERVER_ERROR,errlog,out);
  536.     }
  537.     if(!pid) {
  538.         char *argv0;
  539.  
  540.         if(outpipe[1] != STDOUT_FILENO) {
  541.             dup2(outpipe[1],STDOUT_FILENO);
  542.             close(outpipe[1]);
  543.         }
  544.         if(in != STDIN_FILENO) {
  545.             dup2(in,STDIN_FILENO);
  546.             close(in);
  547.         }
  548.         if((argv0 = strrchr(path,'/')) != NULL)
  549.             argv0++;
  550.         else argv0 = path;
  551.         if(execle(path,argv0,cl,args,(char *)0,env) == -1)
  552.             exit(1);
  553.     }
  554.     else {
  555.         close(outpipe[1]);
  556.         close(inpipe[0]);
  557.     }
  558.  
  559.     if(!(psin = fdopen(outpipe[0],"r")))
  560.         die(SERVER_ERROR,"could not read from script",out);
  561.  
  562.  
  563.     scan_script_header(psin,out);
  564.     /* don't force the redirect, it'll happen 
  565.     if(scan_script_header(psin,out))
  566.         die(REDIRECT,location,out);
  567.     */
  568.  
  569.     if(location[0] == '/') {
  570.         char *t;
  571.         if(!(t = strdup(location)))
  572.             die(NO_MEMORY,"exec_post_NCSA",out);
  573.         location[0] = '\0';
  574.         send_node(t,"",in,out);
  575.     fclose(psin);
  576.         htexit(0,out);
  577.     }
  578.  
  579.     content_length = -1;
  580.     if(!assbackwards)
  581.         send_http_header(out);
  582.  
  583.     /* send a default body of text if the script
  584.        failed to produce any, but ONLY for redirects */
  585.     if (!send_fd(psin,out,NULL) && location[0]) {
  586.            title_html(out,"Document moved");
  587.            fprintf(out,"This document has moved <A HREF=\"%s\">here</A>.<P>%c",location,LF);
  588.     }
  589.     fclose(psin);
  590.     waitpid(pid,NULL,0);
  591. }
  592.