cgi.c
上传用户:ladybrid91
上传日期:2007-01-04
资源大小:287k
文件大小:28k
源码类别:

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** cgi.c
  3. **
  4. ** Copyright (c) 1994-1997 Peter Eriksson <pen@signum.se>
  5. **
  6. ** This program is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2 of the License, or
  9. ** (at your option) any later version.
  10. **
  11. ** This program is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #define IN_DNS_C
  20. #include <stdio.h>
  21. #include <alloca.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <time.h>
  25. #include <fcntl.h>
  26. #include <unistd.h>
  27. #include <wait.h>
  28. #include <errno.h>
  29. #include <signal.h>
  30. #include <syslog.h>
  31. #include <sys/stat.h>
  32. #include <sys/wait.h>
  33. #include <sys/types.h>
  34. #include "phttpd.h"
  35. #define MAXENV 256
  36. static char *cgi_user = NULL;
  37. static char *cgi_group = NULL;
  38. static char *cgi_path = NULL;
  39. static char *copy_environ = NULL;
  40. static char *cgi_basedir = NULL;
  41. static char *cgi_database_dir = NULL;
  42. static int cgi_database_dir_len = 1;
  43. static char *cgi_run_bin_dir = NULL;
  44. static char *cgi_newroot = NULL;
  45. static struct table *cgi_newroot_table = NULL;
  46. static struct table *cgi_uidgid_table = NULL;
  47. static rlim_t cgi_niceval = 5;
  48. static rlim_t cgi_maxcputime = 0;
  49. static rlim_t cgi_vmem = 0;
  50. static rlim_t cgi_fdmax = 0;
  51. static uid_t cgi_uid = 60001; /* Nobody */
  52. static gid_t cgi_gid = 60001; /* Nobody */
  53. static int user_cgi = 1;
  54. static int run_as_authuser = 0;
  55. static int auto_newroot_mode = 0;
  56. static int max_environ = MAXENV;
  57. static int max_processes = 0;
  58. static int exec_needs_homedir = 0;
  59. static int run_as_docrootowner = 0;
  60. static uid_t min_run_uid = 100;
  61. static hashtable_t *set_environ_table = NULL;
  62. static struct options cgi_cfg_table[] = 
  63. {
  64.     { "default-user",  T_STRING, &cgi_user,   NULL },
  65.     { "default-group",  T_STRING, &cgi_group,   NULL },
  66.     { "path", T_STRING, &cgi_path,  NULL },
  67.     { "newroot",        T_STRING, &cgi_newroot,  NULL },
  68.     { "cgi-basedir", T_STRING, &cgi_basedir,  NULL },
  69.     { "cgi-database-dir",   T_STRING, &cgi_database_dir, NULL },
  70.     { "cgi-run-bin-dir", T_STRING, &cgi_run_bin_dir , NULL },
  71.     { "cgi-newroot-table", T_TABLE, &cgi_newroot_table, NULL },
  72.     { "cgi-uidgid-table", T_TABLE, &cgi_uidgid_table, NULL },
  73.     { "nicevalue", T_NUMBER, &cgi_niceval, NULL },
  74.     { "maxcputime", T_NUMBER, &cgi_maxcputime, NULL },
  75.     { "max-vmem", T_NUMBER, &cgi_vmem, NULL },
  76.     { "max-fd", T_NUMBER, &cgi_fdmax, NULL },
  77.     { "copy-environ",   T_STRING, &copy_environ, NULL },
  78.     
  79.     { "allow-user-cgi", T_BOOL,   &user_cgi,  NULL },
  80.     { "run-as-authuser", T_BOOL,   &run_as_authuser,  NULL },
  81.     { "auto-newroot-mode", T_NUMBER, &auto_newroot_mode, NULL },
  82.     { "run-as-docrootowner", T_BOOL, &run_as_docrootowner, NULL },
  83.     { "minimum-run-uid", T_NUMBER, &min_run_uid, NULL },
  84.     { "exec-needs-homedir", T_BOOL,&exec_needs_homedir, NULL },
  85.     { "max-processes",  T_NUMBER, &max_processes, NULL },
  86.     { "max-environ",    T_NUMBER, &max_environ, NULL  },
  87.     { "set-environ",    T_HTABLE, &set_environ_table, NULL },
  88.     
  89.     { NULL, -1, NULL, NULL }
  90. };
  91. static sema_t proc_sema;
  92. static char *cgi_setenv(char **envp, const char *var, const char *val)
  93. {
  94.     char *buf;
  95.     int i, len, blen;
  96.     if (debug > 5)
  97. fprintf(stderr, "cgi_setenv: var=%s, val=%sn",
  98. var, val ? val : "<null>");
  99.     
  100.     if (val == NULL)
  101. return NULL;
  102.     blen = strlen(var)+strlen(val)+2;
  103.     buf = s_malloc(blen);
  104.     
  105.     s_strcpy(buf, blen, var);
  106.     len = s_strcat(buf, blen, "=");
  107.     s_strcat(buf, blen, val);
  108.     
  109.     for (i = 0; i < max_environ && envp[i]; i++)
  110. if (strncmp(envp[i], buf, len) == 0)
  111.     break;
  112.     if (i >= max_environ)
  113. return NULL;
  114.     if (envp[i])
  115. s_free(envp[i]);
  116.     
  117.     envp[i] = buf;
  118.     return buf;
  119. }
  120. static char *cgi_setenv_i(char **envp, const char *var, int num)
  121. {
  122.     char buf[256];
  123.     s_sprintf(buf, sizeof(buf), "%d", num);
  124.     return cgi_setenv(envp, var, buf);
  125. }
  126. static int cse_header(hashentry_t *hep, void *envp)
  127. {
  128.     char *name, *cp;
  129.     int namsize;
  130.     
  131.     
  132.     if (strcmp(hep->key, "AUTHORIZATION") == 0)
  133. return 0;
  134.     namsize = strlen(hep->key)+6;
  135.     name = (char *) alloca(namsize);
  136.     s_strcpy(name, namsize, "HTTP_");
  137.     s_strcat(name, namsize, hep->key);
  138.     cp = name+5;
  139.     while (*cp)
  140.     {
  141. if (*cp == '-')
  142.     *cp = '_';
  143. ++cp;
  144.     }
  145.     cp = cgi_setenv(envp, name, hep->data);
  146.     
  147.     return 0;
  148. }
  149. static int set_env_loader(hashentry_t *hep, void *envp)
  150. {
  151.     
  152.     cgi_setenv(envp, hep->key, hep->data);
  153.     
  154.     return 0;
  155. }
  156. static char **cgi_setup_env(const char *method,
  157.     char *url,
  158.     struct connectioninfo *cip,
  159.     struct httpinfo *hip,
  160.     struct mimeinfo *mip,
  161.     const char *path,
  162.     const char *new_root,
  163.     char *path_info,
  164.     char *path_translated)
  165. {
  166.     char **envp, *buf, *request;
  167.     char server_virt_home[MAXPATHLEN];
  168.     int blen,virt_off;
  169.     
  170.     envp = s_malloc((max_environ+1) * sizeof(char *));
  171.     if (envp == NULL)
  172. return NULL;
  173.     s_strcpy(server_virt_home,MAXPATHLEN,server_home);
  174.     if ( rkmultimode !=0 )
  175.     {
  176. s_sprintf(server_virt_home, MAXPATHLEN, "%s/%08lx", server_home, cip->server->sin.sin_addr.s_addr);
  177.     }
  178.     if ( softvirtserver !=0 ) 
  179.     {
  180. s_strcat(server_virt_home,MAXPATHLEN,"/");
  181. s_strcat(server_virt_home,MAXPATHLEN,cip->hip->svsname);
  182.     }
  183.     cgi_setenv(envp, "DOCUMENT_ROOT", (new_root==NULL) ? server_virt_home : cgi_database_dir );
  184.     cgi_setenv(envp, "TZ", tzname[0]);
  185.     cgi_setenv(envp, "PATH", path);
  186.     blen = strlen(server_version) + 8;
  187.     buf = (char *) alloca(blen);
  188.     s_sprintf(buf, blen, "phttpd/%s", server_version);
  189.     
  190.     cgi_setenv(envp, "SERVER_SOFTWARE", buf);
  191.     if ( rkmultimode != 0 )
  192.       cgi_setenv(envp, "SERVER_NAME", ( softvirtserver != 0 ) ? cip->hip->svsname : s_strdup(dns_lookup_servername(cip->server)) );
  193.     else
  194.       cgi_setenv(envp, "SERVER_NAME", ( softvirtserver != 0 ) ? cip->hip->svsname : server_host);
  195.     cgi_setenv(envp, "GATEWAY_INTERFACE", "CGI/1.1");
  196.     cgi_setenv(envp, "REQUEST_METHOD", method);
  197.     cgi_setenv(envp, "PATH_INFO", path_info);
  198.     
  199.     cgi_setenv_i(envp, "SERVER_PORT", server_port);
  200. /* Set environ var's via table set-environ , added 25.11.97 rk@netuse.de */
  201.     if (set_environ_table)
  202.     {
  203. /* cgi_tbl_env_loader(set_environ_table, (void *) envp); */
  204.         ht_foreach(set_environ_table, set_env_loader, (void *) envp);
  205.     }
  206.     
  207.     if (path_translated && path_translated[0])
  208.     {
  209. if (path_translated[0] != '/')
  210. {
  211.     int blen =  strlen( (new_root==NULL) ? server_virt_home : "/" ) 
  212. + strlen(path_translated) + 2 + cgi_database_dir_len ;
  213.     
  214.     buf = (char *) alloca(blen);
  215.     if ( new_root==NULL )
  216. {
  217.   s_strcpy(buf, blen, server_virt_home );
  218. }
  219.     else
  220.           s_strcpy(buf, blen, ( cgi_database_dir==NULL ) ? "/" : cgi_database_dir );
  221.     
  222.     if (strcmp(path_translated, ".") != 0)
  223.     {
  224. if ( strcmp(buf,"/") != 0 )
  225. s_strcat(buf, blen, "/");
  226. s_strcat(buf, blen, path_translated);
  227.     }
  228.     cgi_setenv(envp, "PATH_TRANSLATED", buf);
  229. }
  230. else
  231.     cgi_setenv(envp, "PATH_TRANSLATED", path_translated);
  232.     }
  233.     if (cip)
  234.     {
  235. char *hostname, *address, *user;
  236. hostname = address = NULL;
  237. dns_get(cip->server, NULL, &hostname, &address, NULL);
  238. cgi_setenv(envp, "LOCAL_ADDR",  address);
  239. cgi_setenv(envp, "LOCAL_HOST", hostname);
  240. hostname = address = NULL;
  241. dns_get(cip->client, NULL, &hostname, &address, NULL);
  242. cgi_setenv(envp, "REMOTE_ADDR", address);
  243. cgi_setenv(envp, "REMOTE_HOST", hostname);
  244. user = NULL;
  245. ident_get(cip->ident, NULL, NULL, &user);
  246. cgi_setenv(envp, "REMOTE_IDENT", user);
  247.     }
  248.     if (hip)
  249.     {
  250. if (hip->aip)
  251. {
  252.     cgi_setenv(envp, "AUTH_TYPE", hip->aip->type);
  253.     if (hip->aip->type && strcasecmp(hip->aip->type, "basic") == 0)
  254. cgi_setenv(envp, "REMOTE_USER", hip->aip->u.basic.username);
  255. #if 0
  256.     cgi_setenv(envp, "PHTTPD_REMOTE_PASSWORD", hip->aip->password);
  257. #endif
  258.     if (hip->aip->xsetenv)
  259. (*hip->aip->xsetenv)(hip->aip->xinfo, cgi_setenv, envp);
  260. }
  261. cgi_setenv(envp, "SERVER_PROTOCOL", hip->version);
  262. /* rkmultimode hip->prelen */
  263. cgi_setenv(envp, "SCRIPT_NAME", url+hip->prelen);
  264. cgi_setenv(envp, "QUERY_STRING", hip->request);
  265.     }
  266.     
  267.     if (mip)
  268.     {
  269. cgi_setenv(envp, "CONTENT_TYPE",
  270.    mime_getheader(mip, "CONTENT-TYPE", 1));
  271. cgi_setenv(envp, "CONTENT_LENGTH",
  272.    mime_getheader(mip, "CONTENT-LENGTH", 1));
  273. ht_foreach(&mip->table, cse_header, (void *) envp);
  274.     }
  275. /* rkmultimode hip->prelen */
  276.     virt_off=hip->prelen;
  277.     if ( softvirtserver ) virt_off=virt_off-strlen(hip->svsname)-1;
  278.     cgi_setenv(envp, "PHTTPD_ORIG_URL", hip->orig_url+virt_off);
  279.     cgi_setenv(envp, "PHTTPD_ORIG_REQUEST", hip->orig_request);
  280.     
  281.     /* Non CGI/1.1 conformant extension, but very nice to have... */
  282.     if (hip->request && hip->request[0])
  283.     {
  284. char **argv;
  285. int rlen = strlen(hip->request)+1;
  286. request = (char *) alloca(rlen);
  287. s_strcpy(request, rlen, hip->request);
  288. if ((argv = strsplit(request, '&', 0)) != NULL)
  289. {
  290.     int i;
  291.     
  292.     for (i = 0; argv[i]; i++)
  293.     {
  294. char **varval, *var_name;
  295. if ((varval = strsplit(argv[i], '=', 2)) != NULL)
  296. {
  297.     if (debug > 4)
  298. fprintf(stderr, "varval[0] = %s, varval[1] = %sn",
  299. varval[0] ? varval[0] : "[null]",
  300. varval[1] ? varval[1] : "[null]");
  301.     
  302.     if (varval[0] && varval[1])
  303.     {
  304.         int vlen = strlen(varval[0])+14;
  305.       
  306. var_name = (char *) alloca(vlen);
  307. s_strcpy(var_name, vlen, "PHTTPD_QUERY_");
  308. s_strcat(var_name, vlen, varval[0]);
  309. cgi_setenv(envp, var_name, varval[1]);
  310.     }
  311.     s_free(varval);
  312. }
  313.     }
  314.     s_free(argv);
  315. }
  316.     }
  317.     if (copy_environ)
  318.     {
  319. char *var, *cp, *cea, *val;
  320. int clen = strlen(copy_environ)+1;
  321. cea = alloca(clen);
  322. s_strcpy(cea, clen, copy_environ);
  323. var = strtok_r(cea, ":", &cp);
  324. while (var)
  325. {
  326.     val = getenv(var);
  327.     cgi_setenv(envp, var, val);
  328.     
  329.     var = strtok_r(NULL, ":", &cp);
  330. }
  331.     }
  332.     
  333.     return envp;
  334. }
  335. static void cgi_free_env(char **envp)
  336. {
  337.     int i;
  338.     
  339.     if (envp == NULL)
  340. return;
  341.     for (i = 0; i < max_environ && envp[i]; i++)
  342. s_free(envp[i]);
  343.     s_free(envp);
  344. }
  345. int pm_init(const char **argv)
  346. {
  347.     struct passwd *pwp, pwb;
  348.     char pbuf[MAXPATHLEN];
  349.     char *cfg_path, *cp;
  350.     const char *name;
  351.     int nlen;
  352.     
  353.     name = argv[0];
  354.     
  355.     if (debug > 1)
  356. fprintf(stderr, "*** cgi/pm_init("%s") called ***n", name);
  357.     nlen = strlen(name)+6;
  358.     cfg_path = s_malloc(nlen);
  359.     s_strcpy(cfg_path, nlen, name);
  360.     
  361.     cp = strrchr(cfg_path, '.');
  362.     if (cp && strcmp(cp, ".so") == 0)
  363. *cp = '';
  364.     
  365.     s_strcat(cfg_path, nlen, ".conf");
  366.     if (config_parse_file(cfg_path, cgi_cfg_table, 0) < 0)
  367.     {
  368. if (debug > 1)
  369.     fprintf(stderr, "config_parse_file() failedn");
  370. return -1;
  371.     }
  372.     
  373.     if (config_parse_argv(argv+1, cgi_cfg_table) < 0)
  374.     {
  375. if (debug > 1)
  376.     fprintf(stderr, "config_parse_file() failedn");
  377. return -1;
  378.     }
  379.     
  380.     if (uidgid_get(cgi_user, cgi_group,
  381.    &cgi_uid, &cgi_gid,
  382.    &pwp, &pwb, pbuf, sizeof(pbuf)) < 0)
  383.     {
  384. syslog(LOG_ERR,
  385.        "cgi: uidgid_get("%s", "%s") failed, using default",
  386.        cgi_user, cgi_group);
  387.     }
  388.     
  389.     if (cgi_uid == -1)
  390.         cgi_uid = server_uid;
  391.     
  392.     if (cgi_gid == -1)
  393.         cgi_gid = server_gid;
  394.     
  395.     if (cgi_path == NULL)
  396. cgi_path = s_strdup("/bin:/usr/bin");
  397.     if (cgi_database_dir == NULL )
  398. cgi_database_dir="/";
  399.     if (cgi_database_dir != NULL )
  400. cgi_database_dir_len=strlen(cgi_database_dir);
  401.     if (max_processes > 0)
  402. sema_init(&proc_sema, max_processes, USYNC_THREAD, NULL);
  403.     
  404.     return 0;
  405. }
  406. void pm_exit(void)
  407. {
  408.     if (debug > 1)
  409. fprintf(stderr, "*** cgi/pm_exit() called ***n");
  410.     if (cgi_user)
  411. s_free(cgi_user);
  412.     
  413.     if (cgi_group)
  414. s_free(cgi_group);
  415.     
  416.     if (cgi_path)
  417. s_free(cgi_path);
  418.     if (set_environ_table)
  419.     {
  420. ht_destroy(set_environ_table);
  421. s_free(set_environ_table);
  422.     }
  423.     if (debug > 1)
  424.         fprintf(stderr, "*** cgi/pm_exit() done ***n");
  425. }
  426. struct relayinfo
  427. {
  428.     int read_fd;
  429.     int write_fd;
  430.     pid_t pid;
  431.     int content_length;
  432. };
  433. static void *cgi_relay_data(void *misc)
  434. {
  435.     struct relayinfo *rip = (struct relayinfo *) misc;
  436.     if (debug > 4)
  437. fprintf(stderr, "CGI: cgi_relay_data(%d -> %d, %d bytes)n",
  438. rip->read_fd, rip->write_fd, rip->content_length);
  439.     
  440.     fd_nrelay(rip->read_fd, rip->write_fd, 0, rip->content_length);
  441.     if (debug > 4)
  442. fprintf(stderr, "CGI: cgi_relay_data(), closing %dn",
  443. rip->write_fd);
  444.     
  445.     fd_close(rip->write_fd);
  446.     if (debug > 4)
  447. fprintf(stderr, "CGI: cgi_relay_data(): Stopn");
  448.     
  449.     return NULL;
  450. }
  451. int pm_request(struct connectioninfo *cip)
  452. {
  453.     pid_t pid;
  454.     int status, len, why, code;
  455.     int content_length = -1;
  456.     int headers_sent = 0;
  457.     int lineno = 0;
  458.     int p2c_pipe[2];
  459.     int c2p_pipe[2];
  460.     int flags;
  461.     int result;
  462.     char **nargv = NULL;
  463.     char buf[1024];
  464.     char *cp, *rp;
  465.     char *p1;
  466.     char **envp;
  467.     char *wdir = NULL;
  468.     uid_t uid = -1;
  469.     gid_t gid = -1;
  470.     struct passwd *pwp, pwb;
  471.     char pbuf[1024];
  472.     struct stat sb;
  473.     char path[MAXPATHLEN],path2[MAXPATHLEN];
  474.     char path_translated[MAXPATHLEN];
  475.     char rewrite_pattern[256], *rwp2;
  476.     struct relayinfo rb;
  477.     thread_t tid;
  478.     char *new_root=NULL ;
  479.     char new_root_buf[MAXPATHLEN];
  480.     char *url;
  481.     char *path_info;
  482.     int fd = cip->fd;
  483.     struct httpinfo *hip = cip->hip;
  484.     c2p_pipe[0] = c2p_pipe[1] = -1;
  485.     if (debug > 1)
  486.     {
  487. fprintf(stderr, "*** cgi/pm_request("%s") called ***n",
  488. hip->url);
  489. if (hip->request)
  490.     fprintf(stderr, "thip->request = "%s"n", hip->request);
  491. if (hip->orig_url)
  492.     fprintf(stderr, "thip->orig_url = "%s"n", hip->orig_url);
  493. if (hip->orig_request)
  494.     fprintf(stderr, "thip->orig_request = "%s"n", hip->orig_request);
  495.     }
  496.     result = 200;
  497.     len = strlen(hip->url);
  498.     url = (char *) alloca(len + 1);
  499.     s_strcpy(url, len+1, hip->url);
  500. /* first set new_root from cgi-newroot-table  and as fallback from cgi_newroot */
  501.     if ( cgi_newroot_table )
  502.     { 
  503.       if ( url_match(cgi_newroot_table,url,rewrite_pattern, sizeof(rewrite_pattern)))
  504.       { 
  505.         new_root=s_strdup(url_rewrite(url,rewrite_pattern,new_root_buf,MAXPATHLEN));
  506.         if ( debug > 6 )
  507.           fprintf (stderr,"Got newroot from table = %sn",new_root);
  508.       }
  509.     }
  510.     else
  511.     {
  512.       if ( auto_newroot_mode > 0 && server_home != NULL )
  513. {
  514. /* ###                     none|basedir|extended|svsextended|effective|withsubdir
  515.    ### auto-newroot-mode =  0      1       2         3           4         5
  516.    ###
  517.  */
  518. if ( auto_newroot_mode == 1 )
  519. new_root=s_strdup(server_home);
  520. if ( auto_newroot_mode == 2 && hip->vs_ipnr != NULL && rkmultimode )
  521. {
  522. s_sprintf(new_root_buf,MAXPATHLEN,"%s/%s",server_home,hip->vs_ipnr);
  523. new_root=s_strdup(new_root_buf);
  524. }
  525. if ( auto_newroot_mode == 3 && hip->svsname != NULL )
  526. {
  527. s_sprintf(new_root_buf,MAXPATHLEN,"%s/%s",server_home,hip->svsname);
  528. new_root=s_strdup(new_root_buf);
  529. }
  530. if ( auto_newroot_mode == 4 && hip->prefix != NULL )
  531. {
  532. s_sprintf(new_root_buf,MAXPATHLEN,"%s/%s",server_home,hip->prefix-strlen(sub_server_home));
  533. new_root=s_strdup(new_root_buf);
  534. }
  535. if ( auto_newroot_mode == 5 && hip->prefix != NULL )
  536. {
  537. s_sprintf(new_root_buf,MAXPATHLEN,"%s/%s",server_home,hip->prefix);
  538. new_root=s_strdup(new_root_buf);
  539. }
  540. if ( debug > 6 ) fprintf(stderr,"new_root=%sn",(new_root)?new_root:"<NULL>");
  541. }
  542.       else
  543. if ( cgi_newroot ) new_root=s_strdup(cgi_newroot);
  544.     }
  545.     /* Allow to RUN as userid of authuser ? */
  546.     if ( run_as_authuser == 1 )
  547.     {
  548. if (hip->aip == NULL ||
  549.     hip->aip->type == NULL ||
  550.     strcasecmp(hip->aip->type, "basic") != 0 ||
  551.     uidgid_get(hip->aip->u.basic.username, NULL,
  552.        &uid, &gid,
  553.        &pwp, &pwb, pbuf, sizeof(pbuf)) < 0)
  554. {
  555.     syslog(LOG_ERR,
  556.  "cgi: uidgid_get("%s") failed for run_as_authuser, using default",
  557.  (hip->aip->type &&
  558.   strcasecmp(hip->aip->type, "basic") == 0 &&
  559.   hip->aip->u.basic.username) ? hip->aip->u.basic.username : "<null>");
  560. }
  561.     }
  562.     else
  563. /* check uid-gid table..... */
  564.     {
  565. if ( run_as_docrootowner == 1 )
  566. {
  567. s_sprintf(path2,MAXPATHLEN,"%s/%s",server_home,hip->prefix);
  568. if ( stat(path2,&sb) == -1 ) return (-403);
  569. uid=sb.st_uid;
  570. gid=sb.st_gid;
  571. }
  572. else
  573. {
  574. if (cgi_uidgid_table)
  575. if ( debug > 4 )
  576. fprintf(stderr,"cgi2: checking....cgi_uidgid_tablen");
  577. if ( url_match(cgi_uidgid_table,url,rewrite_pattern, sizeof(rewrite_pattern)))
  578. {
  579. if ( debug > 4 ) 
  580. fprintf(stderr,"cgi2: got %sn",rewrite_pattern);
  581. rwp2=strchr(rewrite_pattern,':');
  582. if (rwp2!=NULL) 
  583. {
  584. if (strlen(rwp2)>1) {*rwp2=0x00; rwp2++; }
  585. else rwp2=NULL;
  586. }
  587. if ( uidgid_get(rewrite_pattern,rwp2,&uid,&gid,&pwp, &pwb, pbuf, sizeof(pbuf)) < 0)
  588.                { 
  589. syslog(LOG_ERR, "cgi: uidgid_get("%s") failed for cgi_newroot_table",
  590. rewrite_pattern ? rewrite_pattern : "<null>" );
  591.        }
  592.     } /* end of url_match */
  593. } /* end of if cgi_uidgid_table */
  594. } /* end of if run_as_docrootowner else-part */
  595.     } /* end of else run_as_authuser */
  596.     cp = NULL;
  597.     if (debug > 3)
  598. fprintf(stderr, "CGI: before url_expand(), url=%sn", url);
  599.     
  600.     while ((rp = url_expand(url, path, sizeof(path), &sb, &uid, &gid)) == NULL)
  601.     {
  602. if (debug > 3)
  603.     fprintf(stderr, "CGI: in url_expand(), url=%sn", url);
  604. /* Do some CGI special handling to support the use of things
  605.  * like:
  606.          *
  607.  *   /cgi-bin/imagemap/foo/bar/fubar.gif
  608.          *
  609.  *  where /cgi-bin/imagemap is the CGI program...
  610.  *
  611.  * Should perhaps be modified to try things from the beginning
  612.  * first instead of backwards. Later.
  613.  */
  614. cp = strrchr(url, '/');
  615. if (cp == NULL)
  616.     break;
  617. *cp = '';
  618.     }
  619.     if (cp == NULL && len > 0)
  620. if (url[len-1] == '/')
  621. {
  622.     cp = url+len-1;
  623.     *cp++ = 0;
  624. }
  625.     
  626.     if (debug > 3)
  627. fprintf(stderr, "CGI: after url_expand(), url=%s path=%sn", url,path);
  628. /* added RK, in case we want it, use the $HOME of the auth-file to limit access */
  629.     if (hip->aip != NULL && exec_needs_homedir)
  630.     {
  631.        if (hip->aip == NULL ||
  632.            hip->aip->xtype != AUTH_XTYPE_FILE ||
  633.            hip->aip->xinfo == NULL)
  634.        {
  635.            fprintf(stderr,"Authfile incomplete: no homedirn");
  636. /* memleak: need to free */
  637.    if ( new_root ) s_free(new_root);
  638.            return -403;
  639.        }
  640.  
  641.        if (strmatch(path, hip->aip->xinfo) == 0)
  642.        {
  643.            fprintf(stderr,"Error: homedir does not match (url : path !=~ xinfo) %s : %s : %sn", url, path, (char *) hip->aip->xinfo);
  644. /* memleak: need to free */
  645.         if ( new_root ) s_free(new_root);
  646.            return -403;
  647.        }
  648.     }
  649.  
  650.     
  651.     /* We don't allow users to run CGI scripts? */
  652.     if (user_cgi == 0 && uid != -1)
  653.         return -1;
  654.     if (rp == NULL || !S_ISREG(sb.st_mode))
  655. return -1;
  656.     if (cp)
  657.     {
  658. path_info = hip->url + (cp - url);
  659. if (*path_info == 0)
  660.     path_info = "/";
  661. path_translated[0] = '';
  662. url_expand(path_info,
  663.    path_translated, sizeof(path_translated),
  664.    NULL, NULL, NULL);
  665.     }
  666.     else
  667.     {
  668. path_info = NULL;
  669. path_translated[0] = '';
  670.     }
  671. /* RK: not sure about place to change cgi-prefix path (in case cgi-bin is */
  672. /* NOT inside serverroot, seems to be okay here ??? Update 23.11.97: works now */
  673.     if (debug > 3)
  674. fprintf(stderr, "CGI: before pathrewrite, path=%sn", path);
  675.     
  676.     if ( cgi_basedir != NULL && path[0] != '/' )
  677.     {
  678. s_strcpy(path2,sizeof(path2),path);
  679. /* rkmultimode hip->prelen */
  680. s_sprintf(path,sizeof(path),"%s/%s",cgi_basedir,path2+hip->prelen);
  681.     }
  682.     if (debug > 3)
  683. fprintf(stderr, "CGI: after pathrewrite, path=%sn", path);
  684.     status = 0;
  685.     envp = cgi_setup_env(hip->method,
  686.  url,
  687.  cip, hip, hip->mip,
  688.  cgi_path,
  689.  new_root,
  690.  path_info,
  691.  path_translated);
  692.     if (hip->mip)
  693.     {
  694. cp = mime_getheader(hip->mip, "CONTENT-LENGTH", 1);
  695. if (cp)
  696.     content_length = atoi(cp);
  697.     }
  698.     
  699.     len = strlen(hip->url);
  700.     if (pipe(p2c_pipe) < 0)
  701.     {
  702. cgi_free_env(envp);
  703. return error_system(cip, "pipe()");
  704.     }
  705.     if (debug > 6)
  706. fprintf(stderr, "CGI: pipe(p2c_pipe), [0]=%d, [1]=%dn",
  707. p2c_pipe[0], p2c_pipe[1]);
  708.     
  709.     flags = fcntl(p2c_pipe[0], F_GETFL, 0);
  710.     flags &= ~O_ACCMODE;
  711.     flags |= O_RDONLY;
  712.     fcntl(p2c_pipe[0], F_SETFL, flags);
  713.     
  714.     flags = fcntl(p2c_pipe[1], F_GETFL, 0);
  715.     flags &= ~O_ACCMODE;
  716.     flags |= O_WRONLY;
  717.     fcntl(p2c_pipe[1], F_SETFL, flags);
  718.     fd_reopen(p2c_pipe[1], O_WRONLY, FDT_PIPE);
  719.     if (pipe(c2p_pipe) < 0)
  720.     {
  721. cgi_free_env(envp);
  722. return error_system(cip, "pipe()");
  723.     }
  724.     
  725.     if (debug > 6)
  726. fprintf(stderr, "CGI: pipe(c2p_pipe), [0]=%d, [1]=%dn",
  727. c2p_pipe[0], c2p_pipe[1]);
  728.     
  729.     flags = fcntl(c2p_pipe[0], F_GETFL, 0);
  730.     flags &= ~O_ACCMODE;
  731.     flags |= O_RDONLY;
  732.     fcntl(c2p_pipe[0], F_SETFL, flags);
  733.     
  734.     flags = fcntl(c2p_pipe[1], F_GETFL, 0);
  735.     flags &= ~O_ACCMODE;
  736.     flags |= O_WRONLY;
  737.     fcntl(c2p_pipe[1], F_SETFL, flags);
  738.     /* Set up the process argv[] array */
  739.     if (hip->request == NULL || strchr(hip->request, '='))
  740.     {
  741. nargv = (char **) alloca(2 * sizeof(char *));
  742. if (nargv == NULL)
  743.     s_abort();
  744. nargv[0] = hip->url;
  745. nargv[1] = NULL;
  746.     }
  747.     else
  748.     {
  749. char *cp, *start;
  750. int i;
  751. i = 3; /* argv[0] + first arg + NULL */
  752. for (cp = hip->request; *cp; cp++)
  753.     if (*cp == '+')
  754. ++i;
  755. nargv = (char **) alloca(i * sizeof(char *));
  756. if (nargv == NULL)
  757.     s_abort();
  758. nargv[0] = hip->url;
  759. i = 1;
  760. start = hip->request;
  761. do
  762. {
  763.     nargv[i++] = start;
  764.     
  765.     cp = strchr(start, '+');
  766.     if (cp)
  767.     {
  768. *cp++ = '';
  769. start = cp;
  770.     }
  771. } while (cp);
  772. nargv[i] = NULL;
  773.     }
  774.     if (uid == -1)
  775. uid = cgi_uid;
  776.     if (gid == -1)
  777. gid = cgi_gid;
  778.     if (max_processes > 0)
  779. sema_wait(&proc_sema);
  780. /* added to enable chdir in bindir for cgi */
  781.     if ( debug > 7 )
  782.       fprintf(stderr,"workdirmode: %sn",cgi_run_bin_dir ? cgi_run_bin_dir : "DOCUMENT ROOT" );
  783.     if ( cgi_run_bin_dir != NULL && wdir == NULL && path != NULL )
  784.     {
  785.        if ( strcmp(cgi_run_bin_dir,".") != 0 ) 
  786.        { /* set a fixed path */
  787.          s_strcpy(path2,sizeof(path2),path);
  788.          if ( realpath(path2,path) == NULL )
  789.             { fprintf(stderr,"realpath expand for %s failedn",path2);
  790.               s_strcpy(path,sizeof(path),path2);
  791.             }
  792.  else
  793.               wdir=s_strdup(cgi_run_bin_dir);
  794.        }
  795.        else
  796.        {
  797.  p1=strrchr(path,'/');
  798.          if ( p1 != NULL ) { wdir=s_strndup(path,p1-path); }
  799.        }
  800.     }
  801.     if ( min_run_uid == -1 || min_run_uid <= uid )
  802.      pid = proc_run(path,
  803.    uid, gid,
  804.    new_root,
  805.    cgi_niceval, cgi_vmem, cgi_fdmax, cgi_maxcputime,
  806.    p2c_pipe[0], c2p_pipe[1], 2,
  807.    nargv, envp,
  808.    wdir,cgi_basedir);
  809.     else
  810. {
  811. pid=-1;
  812. fprintf(stderr, "cgi.c: min_run_uid > uid ! exec denied !n");
  813. }
  814.     if ( wdir ) s_free(wdir);
  815.     if (pid < 0)
  816.     {
  817. if (debug > 4)
  818.     fprintf(stderr, "cgi.c:proc_run() failedn");
  819. s_close(p2c_pipe[0]);
  820.         fd_close(p2c_pipe[1]);
  821. if (c2p_pipe[0] != -1)
  822.     s_close(c2p_pipe[0]);
  823. if (c2p_pipe[1] != -1)
  824.     s_close(c2p_pipe[1]);
  825. if (max_processes > 0)
  826.     sema_post(&proc_sema);
  827. return error_system(cip, "CGI: proc_run()");
  828.     }
  829.     if (s_close(p2c_pipe[0]) < 0)
  830.     {
  831. if (debug > 4)
  832.     fprintf(stderr, "cgi.c:s_close(p2c_pipe[0]=%d) failed",
  833.     p2c_pipe[0]);
  834.     }
  835.     rb.read_fd = fd;
  836.     rb.write_fd = p2c_pipe[1];
  837.     rb.pid = pid;
  838.     rb.content_length = content_length;
  839.     
  840.     if (thr_create(NULL,
  841.    0,
  842.    (void *(*)(void *)) cgi_relay_data,
  843.    (void *) &rb,
  844.    bound_threads ? THR_BOUND : 0,
  845.    &tid))
  846.     {
  847. if (debug > 4)
  848.     fprintf(stderr, "cgi.c:thr_create(cgi_relay_data) failedn");
  849.         fd_close(p2c_pipe[1]);
  850. if (c2p_pipe[0] != -1)
  851.     s_close(c2p_pipe[0]);
  852. if (c2p_pipe[1] != -1)
  853.     s_close(c2p_pipe[1]);
  854. if (max_processes > 0)
  855.     sema_post(&proc_sema);
  856. return -1;
  857.     }
  858.     if (debug > 4)
  859. fprintf(stderr, "cgi.c: Before s_close(c2p_pipe[1]=%d)n",
  860. c2p_pipe[1]);
  861.     
  862.     if (s_close(c2p_pipe[1]) < 0)
  863. syslog(LOG_ERR, "cgi.c: s_close(c2p_pipe[1]=%d) failed: %m",
  864.        c2p_pipe[1]);
  865.     
  866.     fd_reopen(c2p_pipe[0], O_RDONLY, FDT_PIPE);
  867.     if (debug > 4)
  868. fprintf(stderr, "CGI: After fd_reopen()n");
  869.     
  870.     while (fd_gets_nl(buf, sizeof(buf), c2p_pipe[0]))
  871.     {
  872. lineno++;
  873. if (*buf == 'r' || *buf == 'n')
  874.     break;
  875. /* This check is not according to the CGI-standard! */
  876. if (lineno == 1 && strncmp(buf, "HTTP/", 5) == 0)
  877. {
  878.     fd_puts(buf, fd);
  879.     fd_relay(c2p_pipe[0], fd, 0);
  880.     buf[0] = '';
  881.     headers_sent = 1;
  882.     lineno = 0;
  883.     break;
  884. }
  885. cp = strchr(buf, ':');
  886. if (cp == NULL)
  887.     break;
  888. *cp = '';
  889. if (strcasecmp(buf, "LOCATION") == 0)
  890. {
  891.     result = 302;
  892.     if ( headers_sent == 0 )
  893.     {  http_sendheaders(fd, cip, result, NULL);
  894.        headers_sent = 1;
  895.     }
  896.     fd_printf(fd, "Location: %s", cp+1);
  897. }
  898. else if (strcasecmp(buf, "STATUS") == 0)
  899. {
  900.     char buf2[1024], *emsg;
  901.     int rval;
  902.     
  903.     
  904.     emsg = NULL;
  905.     
  906.     rval = sscanf(cp + 1, " %d %[^nr]", &result, buf2);
  907.     if (rval < 1)
  908.     {
  909. result = http_error(cip, 500,
  910.     "Invalid response from CGI script: Too few arguments to 'STATUS:'");
  911. headers_sent = 1;
  912.     }
  913.     else
  914.     {
  915. if (rval == 2)
  916.     emsg = buf2;
  917. http_sendheaders(fd, cip, result, emsg);
  918. headers_sent = 1;
  919.     }
  920. } else
  921. {
  922.     if (headers_sent == 0)
  923.     {
  924. result = 200;
  925. http_sendheaders(fd, cip, result, NULL);
  926. headers_sent = 1;
  927.     }
  928.     
  929.     *cp = ':';
  930.     fd_puts(buf, fd);
  931. }
  932. buf[0] = '';
  933.     }
  934.     
  935.     if (debug > 4)
  936. fprintf(stderr, "CGI: before if (lineno != 0), lineno=%dn", lineno);
  937.     
  938.     if (lineno != 0)
  939.     {
  940. int len;
  941. if (debug > 4)
  942.     fprintf(stderr, "CGI: Got data from subprocessn");
  943. if (headers_sent==0)
  944. {
  945.     result = 200;
  946.     http_sendheaders(fd, cip, result, NULL);
  947.     fd_puts("Content-Type: text/plainn", fd);
  948.             headers_sent = 1;  /* Added RK */
  949. }
  950. if (cip->hip->mip)
  951.     fd_putc('n', fd);
  952. len = fd_written(fd);
  953. if (buf[0] && buf[0] != 'n' && buf[0] != 'r')
  954.     fd_puts(buf, fd);
  955. fd_relay(c2p_pipe[0], fd, 0);
  956.     }
  957. #if 0
  958.     else
  959. fd_shutdown();
  960. #endif
  961.     if (logheadervolume)
  962. hip->length = fd_written(fd) + rb.content_length;
  963.     else
  964. hip->length = fd_written(fd) - len;
  965.     
  966.     if (fd_close(c2p_pipe[0]) < 0)
  967.     {
  968. if (debug > 4)
  969.     fprintf(stderr, "CGI: fd_close(c2p_pipe[0]=%d) failedn",
  970.     c2p_pipe[0]);
  971.     }
  972.     
  973.     c2p_pipe[0] = -1;
  974.     errno = 0;
  975.     if (debug > 4)
  976. fprintf(stderr, "CGI: before proc_wait()n");
  977.     
  978.     why = proc_wait(pid, &code);
  979.     switch (why)
  980.     {
  981.       case PROC_EXIT:
  982. if (debug > 4)
  983.     fprintf(stderr, "CGI: proc_wait() returned PROC_EXIT, code=%dn",
  984.     code);
  985. if (code < 0)
  986.     result = -code;
  987. else if (code > 0)
  988.     result = http_error(cip,
  989. 500,
  990. "CGI process exited with exit code %d",
  991. code);
  992. break;
  993.       case PROC_SIGNAL:
  994. if (debug > 4)
  995.     fprintf(stderr, "CGI: proc_wait() returned PROC_SIGNAL, code=%dn",
  996.     code);
  997. result = http_error(cip, 500,
  998.     "CGI process exited due to signal %d",
  999.     code);
  1000. break;
  1001.       default:
  1002. if (debug > 4)
  1003.     fprintf(stderr, "CGI: proc_wait() returned %d, code=%dn",
  1004.     why, code);
  1005. result = http_error(cip,
  1006.     500,
  1007.     "CGI process terminated unexpectedly");
  1008.     }
  1009. /* now we do the memory cleanup... */
  1010.     cgi_free_env(envp);
  1011.     if ( new_root ) s_free(new_root);
  1012.     if (debug > 5)
  1013. fprintf(stderr, "CGI: before thr_join (cgi_relay_data)n");
  1014. /* maybe we do not need this, but it works better HACK rk@netuse.de */    
  1015.     if ( lineno > 0 ) 
  1016.      thr_join(tid, NULL, NULL);
  1017.     if (debug > 5)
  1018. fprintf(stderr, "CGI: before fd_closen");
  1019.     
  1020.     if (c2p_pipe[0] != -1)
  1021. fd_close(c2p_pipe[0]);
  1022.     if (debug > 5)
  1023. fprintf(stderr, "CGI: before sema_postn");
  1024.     
  1025.     if (max_processes > 0)
  1026. sema_post(&proc_sema);
  1027.     
  1028.     return result;
  1029. }