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

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** file.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. #include <stdio.h>
  20. #include <time.h>
  21. #include <string.h>
  22. #include <fcntl.h>
  23. #include <unistd.h>
  24. #include <errno.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/mman.h>
  28. #include <syslog.h>
  29. #define IN_DNS_C
  30. #include "phttpd.h"
  31. static hashtable_t *content_types_table = NULL;
  32. static hashtable_t *content_encodings_table = NULL;
  33. static struct table *content_header_table = NULL;
  34. static char *default_type = NULL;
  35. static int method_put = 0;
  36. static int save_as_authuser = 0;
  37. static int method_delete = 0;
  38. static int allow_root_write = 0;
  39. static int write_needs_putdir = 1;
  40. static int read_needs_homedir = 0;
  41. static int allow_rmdir = 0;
  42. static int allow_implied_mkdir =0;
  43. static int nosymlink=0;
  44. static struct options file_cfg_table[] =
  45. {
  46.     { "content-types",     T_HTABLE, &content_types_table, NULL },
  47.     { "content-encodings", T_HTABLE, &content_encodings_table, NULL },
  48.     { "content-header",    T_TABLE , &content_header_table, NULL },
  49.     
  50.     { "default-type",    T_STRING, &default_type,             NULL },
  51.     
  52.     { "method-put",        T_BOOL,   &method_put, NULL },
  53.     { "method-delete",     T_BOOL,   &method_delete, NULL },
  54.     { "allow-root-write",  T_BOOL,   &allow_root_write,         NULL },
  55.     { "write-needs-putdir", T_BOOL,  &write_needs_putdir,       NULL },
  56.     { "read-needs-homedir", T_BOOL,  &read_needs_homedir,       NULL },
  57.     { "allow-rmdir",       T_BOOL,   &allow_rmdir,              NULL },
  58.     { "allow-implied-mkdir",T_BOOL,  &allow_implied_mkdir,      NULL },
  59.     { "save-as-authuser",  T_BOOL,   &save_as_authuser,         NULL },
  60.     { "do-not-follow-symlink", T_BOOL, &nosymlink, NULL },
  61.     { NULL,                -1,       NULL, NULL }
  62. };
  63. static int get_content_type(const char *path,
  64.     const struct stat *sp,
  65.     char *type,
  66.     int typesize,
  67.     char *encoding,
  68.     int encsize)
  69. {
  70.     char *suffix;
  71.     hashentry_t *hep;
  72.     int len;
  73.     
  74.     type[0] = '';
  75.     if (encoding)
  76. encoding[0] = '';
  77.     
  78.     if (debug > 2)
  79. fprintf(stderr, "*** get_content_type("%s", ...)n", path);
  80.     
  81.     if (content_types_table == NULL)
  82.     {
  83. if (debug > 2)
  84.     fprintf(stderr, "t-> Content type unknown (NULL table).n");
  85. s_strcpy(type, typesize, default_type);
  86. return 0;
  87.     }
  88.     /* Get suffix */
  89.     suffix = strrchr(path, '.');
  90.     if (suffix == NULL)
  91.     {
  92. s_strcpy(type, typesize, default_type);
  93. return 0;
  94.     }
  95.     len = 0;
  96.     
  97.     if (encoding && content_encodings_table)
  98.     {
  99. hep = ht_lookup(content_encodings_table, suffix, len);
  100. if (hep)
  101. {
  102.     s_strcpy(encoding, encsize, hep->data);
  103.     if (debug > 2)
  104. fprintf(stderr, "t -> Encoding found: %sn", encoding);
  105.     ht_release(hep);
  106.     if (suffix > path)
  107.     {
  108. char *cp;
  109. suffix--;
  110. for (cp = suffix-1; cp > path && *cp != '.'; cp--)
  111.     ;
  112. len = suffix - cp+1 ;
  113. suffix = cp;
  114. if (debug > 1)
  115.     fprintf(stderr, "file: new suffix: len = %d, str=%.*sn",
  116.     len, len, suffix);
  117.     }
  118. }
  119.     }
  120.     hep = ht_lookup(content_types_table, suffix, len);
  121.     if (hep)
  122.     {
  123. s_strcpy(type, typesize, hep->data);
  124. ht_release(hep);
  125. if (debug > 2)
  126.     fprintf(stderr, "t -> Content-Type found: %sn", type);
  127. return 0;
  128.     }
  129.     
  130.     if (debug > 2)
  131. fprintf(stderr, "t-> Content type unknown.n");
  132.     
  133.     s_strcpy(type, typesize, default_type);
  134.     return 0;
  135. }
  136. int pm_init(const char **argv)
  137. {
  138.     char *cfg_path, *cp;
  139.     const char *name = argv[0];
  140.     char **pair;
  141.     char *p,*q;
  142.     int cfgsize;
  143.     int i;
  144.     
  145.     if (debug > 1)
  146. fprintf(stderr, "*** file/pm_init("%s") called ***n", name);
  147.     cfgsize = strlen(name)+6;
  148.     cfg_path = s_malloc(cfgsize);
  149.     s_strcpy(cfg_path, cfgsize, name);
  150.     
  151.     cp = strrchr(cfg_path, '.');
  152.     if (cp && strcmp(cp, ".so") == 0)
  153. *cp = '';
  154.     
  155.     s_strcat(cfg_path, cfgsize, ".conf");
  156.     if (config_parse_file(cfg_path, file_cfg_table, 0) < 0)
  157. return -1;
  158.     
  159.     if (config_parse_argv(argv+1, file_cfg_table) < 0)
  160. return -1;
  161.     
  162.     if (default_type == NULL)
  163. default_type = s_strdup("unknown");
  164. /* Convert meta-character to real one in value (n) -> 0x0a */
  165.     if (content_header_table != NULL)
  166.     {
  167. for(i = 0; i < content_header_table->length; ++i)
  168. {
  169.     pair = content_header_table->value[i];
  170.             p=pair[1]; q=pair[1];
  171.             while ( *p != 0x00 )
  172.     {
  173. if ( *p != 0x5c ) /* this is all beside the  */
  174.      *q=*p;
  175. else /* this is  */
  176. {
  177.   p++;
  178.   if ( *p == 0x00 ) break;
  179.   if ( *p == 'n' ) *q=0x0a;
  180.   else if ( *p == 'r' ) *q=0x0c;
  181.   else if ( *p == 't' ) *q=0x09;
  182.   else  *q=*p;     /* default is to keep */
  183. }
  184. p++; q++ ;
  185.     } /* end of while */
  186.     *q=0x00;
  187.         } /* end of for loop through table */
  188.     }
  189. /* end of converter */
  190.     return 0;
  191. }
  192. void pm_exit(void)
  193. {
  194.     if (debug > 1)
  195. fprintf(stderr, "*** file/pm_exit() called ***n");
  196.     if (content_types_table)
  197.     {
  198. ht_destroy(content_types_table);
  199. s_free(content_types_table);
  200.     }
  201.     if (content_encodings_table)
  202.     {
  203. ht_destroy(content_encodings_table);
  204. s_free(content_encodings_table);
  205.     }
  206.     if (default_type)
  207. s_free(default_type);
  208.     
  209.     if (debug > 1)
  210. fprintf(stderr, "*** file/pm_exit() done ***n");
  211. }
  212. /* Added rk@netuse.de */
  213. static void http_sendaddheader(int fd, const char *url)
  214. {
  215.     int i;
  216.     char **pair;
  217.  
  218.     if(content_header_table == NULL)
  219.         return;
  220.  
  221.     for(i = 0; i < content_header_table->length; ++i)
  222.     {
  223.         pair = content_header_table->value[i];
  224.         if(strmatch(url, pair[0]))
  225.         {
  226.             fd_puts(pair[1], fd);
  227.             fd_putc('n', fd);
  228.             break;
  229.         }
  230.     }
  231. }
  232. static int http_get_head(struct connectioninfo *cip)
  233. {
  234.     char typebuf[256], buf[256], encbuf[256], ubuf[1024], *s_since;
  235.     int i, result, head_method = 0;
  236.     int fd = cip->fd;
  237.     struct httpinfo *hip = cip->hip;
  238.     struct stat lsb;
  239.     fscentry_t *fep;
  240.     fsinfo_t *fip;
  241.     unsigned int fsc_flags = 0;
  242.     char *range;
  243.     char *hnl = NULL;
  244.     char *surl;
  245.     off_t from = 0, to = 0;   
  246.     
  247.     
  248.     if (debug > 1)
  249. fprintf(stderr, "*** file/pm_get() called ***n");
  250.     if (hip && hip->mip && (hip->mip->pragma_flags & MPF_NOCACHE))
  251. fsc_flags = FSCF_RELOAD;
  252.     
  253.     fep = fscache_lookup(hip->url, fsc_flags);
  254.     if (fep == NULL)
  255. return -1;
  256.     if (fep->fip == NULL)
  257.     {
  258. fscache_release(fep);
  259. return -1;
  260.     }
  261.     fip = fep->fip;
  262.     if (nosymlink==1)
  263.     { lstat(fip->path,&lsb);
  264.       if ( S_ISLNK(lsb.st_mode) ) return -1;
  265.     }
  266.     
  267.     if (S_ISDIR(fip->sb.st_mode))
  268.     {
  269. /* ADDED RK: we need to get the servername for corect redirects here manual :-( */
  270. if ( softvirtserver == 0 )
  271.  {if (rkmultimode==0)
  272. /* Standart mode, only copy url. */
  273.     s_strcpy(ubuf, sizeof(ubuf), cip->sip->url);
  274.   else 
  275.   {
  276. /* If we run rkmultimode, we need to do a reverse lookup to our socket, since we */
  277. /* do not have a table. For performance reasons, a reverse lookup it not done on */
  278. /* every request near the accept, but only here in case of a redirect, since */
  279. /* that case happens fewer times :-( (and DNS is not MT-Safe, */
  280. /* thus the call may block */
  281.             hnl=dns_lookup_servername(cip->server);
  282.             if ( hnl==NULL ) hnl=s_strdup(inet_ntoa(cip->server->sin.sin_addr));
  283.             surl=make_server_url(hnl,cip->sip->port);
  284.             s_strcpy(ubuf, sizeof(ubuf), surl);
  285.             s_free(surl);
  286.   }
  287.  }
  288. else
  289. /* we have softvirtserver: Easy-we got the Servername in the Request */
  290.   {
  291.     surl=make_server_url(cip->hip->svsname,cip->sip->port);
  292.     s_strcpy(ubuf, sizeof(ubuf), surl);
  293.     s_free(surl);
  294.   }
  295. /* rkmultimode hip->prelen */
  296. s_strcat(ubuf, sizeof(ubuf), hip->url+hip->prelen);
  297. s_strcat(ubuf, sizeof(ubuf), "/");
  298. fscache_release(fep);
  299. if (debug>6) 
  300.     fprintf(stderr,"IS a DIR: Redirect: %s (%s)n",ubuf,(hnl==NULL) ? "<NULL>" : hnl);
  301. return http_redirect(cip, ubuf, hip->request, NULL, 301);
  302.     }
  303.     if (get_content_type(fip->path, &fip->sb, typebuf, sizeof(typebuf),
  304.  encbuf, sizeof(encbuf)))
  305.     {
  306. fscache_release(fep);
  307. return -1;
  308.     }
  309. /* added RK, in case we want it, use the $HOME of the auth-file to limit access */
  310.     if (hip->aip != NULL && read_needs_homedir)
  311.     {
  312.        if (hip->aip == NULL ||
  313.            hip->aip->xtype != AUTH_XTYPE_FILE ||
  314.            hip->aip->xinfo == NULL)
  315.        {
  316.            fprintf(stderr,"Authfile incomplete: no homedirn");
  317.            return -403;
  318.        }
  319.  
  320.        if (strmatch(fip->path, hip->aip->xinfo) == 0)
  321.        {
  322.            fprintf(stderr,"Error: homedir does not match %s %sn",
  323.                    fip->path, (char *) hip->aip->xinfo);
  324.            return -403;
  325.        }
  326.     }
  327.  
  328.     if ((s_since = mime_getheader(hip->mip, "IF-MODIFIED-SINCE", 1)) != NULL)
  329.     {
  330.         struct tm tm_since;
  331. int t_since;
  332. if (debug > 2)
  333.     fprintf(stderr, "Got If-Modified-Since: %sn", s_since);
  334. t_since = atotm(s_since, &tm_since);
  335. if (t_since != -1)
  336. {
  337.     if (fip->sb.st_mtime <= (time_t) t_since)
  338.     {
  339. fscache_release(fep);
  340.         return http_not_modified(cip);
  341.     }
  342. }
  343. else
  344. {
  345.     /* Could not parse the date format - do a string compare */
  346.     http_time_r(&fip->sb.st_mtime, buf, sizeof(buf));
  347.     i = strlen(buf);
  348.     buf[i-1] = '';
  349.     
  350.     if (strcmp(s_since, buf) == 0)
  351.     {
  352. fscache_release(fep);
  353.         return http_not_modified(cip);
  354.     }
  355. }
  356.     }
  357.     if ((s_since = mime_getheader(hip->mip, "IF-UNMODIFIED-SINCE", 1)) != NULL)
  358.     {
  359.        int t_since;
  360.        if (debug > 2)
  361.   fprintf(stderr, "Got If-Unmodified-Since: %sn", s_since);
  362.        t_since = atotm(s_since, NULL);
  363.        if (t_since != -1)
  364.        {
  365.   if (fip->sb.st_mtime > (time_t) t_since)
  366.   {
  367.      fscache_release(fep);
  368.      return http_precondition_failed(cip);
  369.   }
  370.        }
  371.     }
  372.     /*   strtoull() is being used because of Solaris 2.6 brain damage.
  373.  Don't change it unless you know what you're doing.
  374.     */
  375.     result = 200;
  376.     if ((range = mime_getheader(hip->mip, "RANGE", 1)) != NULL)
  377.     {
  378.        if (debug > 2)
  379.   fprintf(stderr, "Got Range: %sn", range);
  380.        if(!strncmp(range, "bytes", 5))
  381.        {
  382.   char *p;
  383.   for(range += 5; s_isspace(*range); ++range);
  384.   if(*range++ != '=')
  385.      goto norange;
  386.   while(s_isspace(*range)) ++range;
  387.   if(*range == '-')
  388.   {
  389.      from = 0;
  390.      ++range;
  391.   }
  392.   else
  393.   {
  394.      from = (off_t) strtoull(range, &p, 10); 
  395.      if (from == 0 && p == range)
  396. goto norange;
  397.      while(s_isspace(*p)) ++p;
  398.      if(*p++ != '-')
  399. goto norange;
  400.      range = p;
  401.   }
  402.   while(s_isspace(*range)) ++range;
  403.   if(*range == '')
  404.      to = fip->sb.st_size;
  405.   else
  406.   {
  407.      to = (off_t) strtoull(range, &p, 10);
  408.      if (to == 0 && range == p)
  409.  goto norange;
  410.      if(to > fip->sb.st_size)
  411.  to = fip->sb.st_size;
  412.      while(s_isspace(*p)) ++p;
  413.      range = p;
  414.   }
  415.   if (to < from)
  416.      goto norange;
  417.   if (*range != '')
  418.   {
  419.      if (debug > 2)
  420. fprintf(stderr, "Can't serve multiple ranges.n");
  421.      goto norange;
  422.   }
  423.   if ((s_since = mime_getheader(hip->mip, "IF-RANGE", 1)) != NULL)
  424.   {
  425.      time_t t_since;
  426.      if(debug > 2)
  427. fprintf(stderr, "Got If-Range: %sn", s_since);
  428.      t_since = atotm(s_since, NULL);
  429.      if (t_since != -1)
  430. {if (fip->sb.st_mtime > (time_t) t_since)
  431.  {
  432.     if (debug > 2)
  433.        fprintf(stderr, "Entity changed since %sn", s_since);
  434.     goto norange;
  435.  }
  436. }
  437.      else
  438. if (debug > 2)
  439.    fprintf(stderr, "Couldn't parse If-Range value.n");
  440.   }
  441.   result = 206;
  442.        }
  443.        else
  444.   if (debug > 2)
  445.      fprintf(stderr, "Unknown range unitsn");
  446.     }
  447. norange:
  448.     if (range != NULL && debug > 2)
  449.        fprintf(stderr, "Ignoring Range header...n");
  450.     if (strcasecmp(hip->method, "HEAD") == 0)
  451. head_method = 1;
  452.     else
  453. if (fscache_getdata(fep) != 1)
  454. {
  455.     if (debug > 1)
  456. fprintf(stderr, "fscache_getdata(): failedn");
  457.     
  458.     fscache_release(fep);
  459.     return -1;
  460. }
  461.     
  462.     if (hip->mip != NULL)
  463.     {
  464. http_sendheaders(fd, cip, result, NULL);
  465. /* added RK */
  466.         http_sendaddheader(fd, hip->url);
  467. http_sendlastmodified(fd, fip->sb.st_mtime);
  468. if (typebuf[0])
  469.     fd_puts2nl("Content-Type: ", typebuf, fd);
  470. if (encbuf[0])
  471.     fd_puts2nl("Content-Encoding: ", encbuf, fd);
  472. if (result == 200)
  473.    fd_putsinl("Content-Length: ", (int) fip->sb.st_size, fd);
  474. else
  475. {
  476.    fd_putsinl("Content-Length: ", (int) (to - from + 1), fd);
  477.    fd_printf(fd, "Content-Range: bytes %d-%d/%dn",
  478.      (int) from, (int) to, (int) fip->sb.st_size);
  479. }
  480. http_sendlang(fd, hip->url);
  481. fd_putc('n', fd);
  482.     }
  483.     if (head_method)
  484.     {
  485. fscache_release(fep);
  486. if (logheadervolume)
  487.             hip->length = fd_written(fd);
  488. return result;
  489.     }
  490.     if (fd_write(fd,
  491.  fip->data.file.content + (result == 200 ? 0 : from),
  492.  result == 200 ? fip->sb.st_size : (to - from + 1)) < 0)
  493. if (debug)
  494. {
  495.     fprintf(stderr, "ERROR on #%d: ", cip->request_no);
  496.     perror("write");
  497. }
  498.     if (logheadervolume)
  499. hip->length = fd_written(fd);
  500.     else
  501. hip->length = fip->sb.st_size;
  502.     fscache_release(fep);
  503.     
  504.     if (debug > 2)
  505. fprintf(stderr, "*** file/http_get: Returningn");
  506.     
  507.     return result;
  508. }
  509. static int http_delete(struct connectioninfo *cip)
  510. {
  511.     char path[MAXPATHLEN+1];
  512.     struct stat sb;
  513.     int result;
  514.     struct httpinfo *hip = cip->hip;
  515.     
  516.     if (debug > 1)
  517.         fprintf(stderr, "*** file/pm_delete() called ***n");
  518.     if (url_expand(hip->url, path, sizeof(path), &sb, NULL, NULL) == NULL)
  519.         return -1;
  520.     
  521.     if (debug > 6)
  522. fprintf(stderr, "url-found on %sn",path);
  523.     
  524.     if (sb.st_uid==0 && !allow_root_write)
  525.     {
  526. fprintf(stderr, "SECURITY-ERROR: unlink try on %sn",path);
  527. return -403;
  528.     }
  529.     /* added virtual user access/check here .... */
  530.     if (write_needs_putdir)
  531.     { 
  532. if (hip->aip == NULL ||
  533.     hip->aip->xtype != AUTH_XTYPE_FILE ||
  534.     hip->aip->xinfo == NULL)
  535. {
  536.     fprintf(stderr,"Authfile incomplete: no putdirn");
  537.     return -403;
  538. }
  539. if (strmatch(path, hip->aip->xinfo) == 0)
  540. {
  541.     fprintf(stderr,"Error: putdir does not match %s %sn",
  542.     path, (char *) hip->aip->xinfo);
  543.     return -403;
  544. }
  545.     }
  546.     if (debug > 3)
  547. fprintf(stderr, "UNLINK: %sn",path);    
  548.     
  549.     /* do not allow rmdir ! -- may change ??? */
  550.     if ((!S_ISDIR(sb.st_mode)) && allow_rmdir == 0)
  551. return -1;
  552.     if (S_ISDIR(sb.st_mode))
  553.     {
  554. if (rmdir(path) != 0)
  555.     return -403;
  556.     }
  557.     else
  558.     {
  559. if (s_unlink(path)!=0)
  560.     return -403;
  561.     }
  562.     result=200;
  563.     if (hip->mip != NULL)
  564.     {
  565.         http_sendheaders(cip->fd, cip, result, NULL);
  566.  
  567.         http_sendlastmodified(cip->fd, sb.st_mtime);
  568.         fd_puts("Content-Type: text/htmlnn", cip->fd);
  569.     }
  570.  
  571.     html_sysheader(cip->fd, "H2", "Succeded - File removed");
  572.     fd_puts("OKn", cip->fd);
  573.     html_sysfooter(cip->fd);
  574.  
  575.     if (debug > 2)
  576.         fprintf(stderr, "*** file/http_delete: Returningn");
  577.  
  578.     return result;
  579. }
  580. static int http_put(struct connectioninfo *cip)
  581. {
  582.     char buf[2048], path[MAXPATHLEN+1];
  583.     char newpath[MAXPATHLEN+1],newfile[MAXPATHLEN+1];
  584.     char newsubpath[MAXPATHLEN+1];
  585.     char *pclen, *p;
  586.     struct stat sb;
  587.     int fd_out, len, result, clen;
  588.     int fd = cip->fd;
  589.     struct httpinfo *hip = cip->hip;
  590.     pid_t pid;
  591.     uid_t uid = -1;
  592.     gid_t gid = -1;
  593.     struct passwd *pwp, pwb;
  594.     char pbuf[1024];
  595.     
  596.     
  597.     if (debug > 1)
  598. fprintf(stderr, "*** file/pm_put() called ***n");
  599.     
  600.     if (url_expand(hip->url, path, sizeof(path), &sb, NULL, NULL) == NULL)
  601.     {
  602. /* Lets try to create a new file ....*/
  603.         s_strcpy(newpath, sizeof(newpath), hip->url);
  604.         p=newpath+strlen(newpath)-1;
  605.         if (p <= newpath)
  606.     return -1;
  607.         while (p > newpath && *p != '/')
  608.     p--;
  609.         if (p < newpath)
  610.     return -1;
  611.         p++;
  612.         s_strcpy(newfile, sizeof(newfile), p);
  613.         *p=0x00;
  614.         if (debug > 4)
  615.     fprintf(stderr, "Checking DIR %sn",newpath);
  616.         /* If this it NOT a dir, FAIL..... */
  617. /* add allow_implied_mkdir here ...RK */
  618. /* TODO..... */
  619.         if (url_expand(newpath, path, sizeof(path), &sb, NULL, NULL) == NULL)
  620.     if ( allow_implied_mkdir==0 )
  621.   return -1;
  622.     /* Lets try to create that dir, maybe later add here mkdir -p */
  623.     /* for now, only single mkdir is enabled..... */
  624.     s_strcpy(newsubpath, sizeof(newsubpath),newpath);
  625.     p=newsubpath+strlen(newsubpath)-2;
  626.     if (p <= newsubpath)
  627. return -1;
  628.     
  629.     while (p > newsubpath && *p != '/')
  630. p--;
  631.     if (p < newsubpath)
  632. return -1;
  633.     *p=0x00;
  634.     p++;
  635.     /* try again */
  636.     if (debug>4)
  637.   fprintf(stderr, "Checking 2.Dir %sn",newsubpath);
  638.     
  639.     if (url_expand(newsubpath, path, sizeof(path), &sb, NULL, NULL) == NULL)
  640. return -1;
  641.     
  642.     if (!S_ISDIR(sb.st_mode))
  643. return -1;
  644.     
  645.     if (sb.st_uid==0 && allow_root_write==0)
  646.     {
  647. fprintf(stderr, "SECURITY-ERROR: create try on %sn",path);
  648. return -403;
  649.     }
  650.     /* now try to create directory....*/
  651.     s_sprintf(path,sizeof(path),"%s/%s",path,p);
  652.     if (mkdir(path, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH )!=0 )
  653. return -1;
  654.     /* fprintf(stderr, "mkdir succeeded...n"); */
  655. /* lets try to save as the authuser ! This is tricky, since we need to be root */
  656. /* with our uid, so we will fork :-( */
  657.     if ( save_as_authuser != 0 )
  658.     {
  659.       if (debug > 2)
  660.         fprintf(stderr, "*** file/pm_put() chown - save_as_authusern" );
  661.  
  662.       if (hip->aip == NULL ||
  663.           hip->aip->type == NULL ||
  664.           strcasecmp(hip->aip->type, "basic") != 0 ||
  665.           uidgid_get(hip->aip->u.basic.username, NULL,
  666.                      &uid, &gid,
  667.                      &pwp, &pwb, pbuf, sizeof(pbuf)) < 0)
  668.       {
  669.         syslog(LOG_ERR,
  670.         "file: uidgid_get("%s") failed for save_as_authuser, using default",
  671.         (hip->aip->type &&
  672.         strcasecmp(hip->aip->type, "basic") == 0 &&
  673.           hip->aip->u.basic.username) ? hip->aip->u.basic.username : "<null>");
  674.           fprintf(stderr, "*** file/pm_put() chown - failed to get UIDn");
  675.       }
  676.       else
  677.       {
  678.         pid=fork1();
  679.         if ( pid==0 )
  680.          {  seteuid(0);
  681.             fprintf(stderr,"chown: %dn",chown(path,uid,gid));
  682.             exit(0);
  683.          }
  684. /* shall we wait for client to finish ? */
  685.         if ( pid==-1 ) fprintf(stderr,"file.so: failed to fork to chownn");
  686.       }
  687.     }
  688.  
  689.     if (url_expand(newpath, path, sizeof(path), &sb, NULL, NULL) == NULL)
  690. return -1;
  691. } /* end of sub-mkdir */
  692.         if (!S_ISDIR(sb.st_mode))
  693.     return -1;
  694.         if (sb.st_uid==0 && allow_root_write==0)
  695.         {
  696.     fprintf(stderr, "SECURITY-ERROR: create try on %sn",path);
  697.             return -403;
  698.         }
  699.         s_strcat(path, sizeof(path), "/");
  700.         s_strcat(path, sizeof(path), newfile);
  701.         if (debug > 4)
  702.     fprintf(stderr, "file/pm_put(): creating %s %sn",newpath, path);
  703.     }
  704.     if (sb.st_uid==0 && !allow_root_write)
  705.     {
  706. fprintf(stderr, "SECURITY-ERROR: write try on %sn",path);
  707.         return -403;
  708.     }
  709.     /* added virtual user access/check here .... */
  710.     if (write_needs_putdir)
  711.     { 
  712.        if (hip->aip == NULL ||
  713.    hip->aip->xtype != AUTH_XTYPE_FILE ||
  714.    hip->aip->xinfo == NULL) 
  715.        {
  716.    fprintf(stderr,"Authfile incomplete: no putdirn");
  717.    return -403;
  718.        }
  719.        
  720.        if (strmatch(path, hip->aip->xinfo) == 0)
  721.        {
  722.    fprintf(stderr,"Error: putdir does not match %s %sn",
  723.    path, (char *) hip->aip->xinfo);
  724.    return -403;
  725.        }
  726.     }
  727.     fd_out = fd_open(path, O_WRONLY+O_CREAT+O_TRUNC, 0666);
  728.     if (fd_out < 0)
  729.     {
  730. fprintf(stderr, "Unable top open/create: %sn", path);
  731. return -403;
  732.     }
  733. /* lets try to save as the authuser ! This is tricky, since we need to be root */
  734. /* with our uid, so we will fork :-( */
  735.     if ( save_as_authuser != 0 )
  736.     { 
  737.       if (debug > 2)
  738.         fprintf(stderr, "*** file/pm_put() chown - save_as_authusern" );
  739.       if (hip->aip == NULL ||
  740.           hip->aip->type == NULL ||
  741.           strcasecmp(hip->aip->type, "basic") != 0 ||
  742.           uidgid_get(hip->aip->u.basic.username, NULL,
  743.                      &uid, &gid,
  744.                      &pwp, &pwb, pbuf, sizeof(pbuf)) < 0)
  745.       {
  746.         syslog(LOG_ERR,
  747.         "file: uidgid_get("%s") failed for save_as_authuser, using default",
  748.         (hip->aip->type &&
  749.         strcasecmp(hip->aip->type, "basic") == 0 &&
  750.           hip->aip->u.basic.username) ? hip->aip->u.basic.username : "<null>");
  751.           fprintf(stderr, "*** file/pm_put() chown - failed to get UIDn");
  752.       }
  753.       else
  754.       {
  755.         pid=fork1();
  756.         if ( pid==0 )
  757.          {  seteuid(0);
  758.             fprintf(stderr,"chown: %dn",chown(path,uid,gid));
  759.             exit(0);
  760.          }
  761. /* shall we wait for client to finish ? */
  762.         if ( pid==-1 ) fprintf(stderr,"file.so: failed to fork to chownn");
  763.       }
  764.     }
  765.     pclen=mime_getheader(hip->mip, "CONTENT-LENGTH", 1);
  766.     clen= ( pclen != NULL ) ? atoi(pclen) : 0 ;
  767.     if (debug > 4)
  768. fprintf(stderr, "*** file/pm_put() Bytes %d n", clen );
  769.     if ( clen > 0 ) 
  770. while ( clen > 0 )
  771. {   
  772.     len = fd_read(fd, buf, (sizeof(buf)<clen)? sizeof(buf) : clen );
  773.     if (fd_write(fd_out, buf, len) != 0) /* BUG: must be 0, !len RK */
  774.     {
  775. fd_close(fd_out);
  776. return error_system(cip, "do_putpost(): cwrite()");
  777.     }
  778.     clen=clen-len;
  779. }
  780.     else
  781. while ((len = fd_read(fd, buf, sizeof(buf))) > 0 )
  782. {
  783.     if (fd_write(fd_out, buf, len) != len)
  784.     {
  785. fd_close(fd_out);
  786. return error_system(cip, "do_putpost(): write()");
  787.     }
  788. }
  789.     
  790.     hip->length = fd_close(fd_out);
  791.     
  792.     result = 200;
  793.     
  794.     if (hip->mip != NULL)
  795.     {
  796. http_sendheaders(fd, cip, result, NULL);
  797. http_sendlastmodified(fd, sb.st_mtime);
  798. fd_puts("Content-Type: text/htmlnn", fd);
  799.     }
  800.     
  801.     html_sysheader(fd, "H2", "Succeded");
  802.     fd_puts("OKn", fd);
  803.     html_sysfooter(fd);
  804.     if (debug > 2)
  805. fprintf(stderr, "*** file/http_put: Returningn");
  806.     
  807.     return result;
  808. }
  809. int pm_request(struct connectioninfo *cip)
  810. {
  811.     struct httpinfo *hip = cip->hip;
  812.     
  813.     if (strcasecmp(hip->method, "GET") == 0 ||
  814. strcasecmp(hip->method, "HEAD") == 0)
  815. return http_get_head(cip);
  816.     else if (strcasecmp(hip->method, "PUT") == 0 )
  817.     {
  818. if (method_put==1)
  819.     return http_put(cip);
  820. else
  821.     return -405;
  822.     }
  823.     else
  824. if (strcasecmp(hip->method, "DELETE") == 0 )
  825. {
  826.     if (method_put && method_delete)
  827. return http_delete(cip);
  828.     else
  829. return -405;
  830. }
  831. else
  832.     return -2;
  833. }