[BACK]Return to bozohttpd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / httpd

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/libexec/httpd/bozohttpd.c between version 1.32.2.1 and 1.32.2.2

version 1.32.2.1, 2013/06/23 06:28:49 version 1.32.2.2, 2014/08/20 00:02:22
Line 3 
Line 3 
 /*      $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $      */  /*      $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $      */
   
 /*  /*
  * Copyright (c) 1997-2011 Matthew R. Green   * Copyright (c) 1997-2014 Matthew R. Green
  * All rights reserved.   * All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
Line 55 
Line 55 
   
 /*  /*
  * requirements for minimal http/1.1 (at least, as documented in   * requirements for minimal http/1.1 (at least, as documented in
  * <draft-ietf-http-v11-spec-rev-06> which expired may 18, 1999):   * RFC 2616 (HTTP/1.1):
  *   *
  *      - 14.15: content-encoding handling. [1]   *      - 14.11: content-encoding handling. [1]
  *   *
  *      - 14.16: content-length handling.  this is only a SHOULD header   *      - 14.13: content-length handling.  this is only a SHOULD header
  *        thus we could just not send it ever.  [1]   *        thus we could just not send it ever.  [1]
  *   *
  *      - 14.17: content-type handling. [1]   *      - 14.17: content-type handling. [1]
  *   *
  *      - 14.25/28: if-{,un}modified-since handling.  maybe do this, but   *      - 14.28: if-unmodified-since handling.  if-modified-since is
  *        i really don't want to have to parse 3 differnet date formats   *        done since, shouldn't be too hard for this one.
  *   *
  * [1] need to revisit to ensure proper behaviour   * [1] need to revisit to ensure proper behaviour
  *   *
Line 88 
Line 88 
  *   *
  *      - 10.3.3/10.3.4/10.3.8:  just use '302' codes always.   *      - 10.3.3/10.3.4/10.3.8:  just use '302' codes always.
  *   *
  *      - 14.1/14.2/14.3/14.27: we do not support Accept: headers..   *      - 14.1/14.2/14.3/14.27: we do not support Accept: headers.
  *        just ignore them and send the request anyway.  they are   *        just ignore them and send the request anyway.  they are
  *        only SHOULD.   *        only SHOULD.
  *   *
  *      - 14.5/14.16/14.35: we don't do ranges.  from section 14.35.2   *      - 14.5/14.16/14.35: only support simple ranges: %d- and %d-%d
  *        `A server MAY ignore the Range header'.  but it might be nice.   *        would be nice to support more.
  *        since 20080301 we support simple range headers.  
  *   *
  *      - 14.9: we aren't a cache.   *      - 14.9: we aren't a cache.
  *   *
  *      - 14.15: content-md5 would be nice...   *      - 14.15: content-md5 would be nice.
  *  
  *      - 14.24/14.26/14.27: be nice to support this...  
  *   *
  *      - 14.44: not sure about this Vary: header.  ignore it for now.   *      - 14.24/14.26/14.27: if-match, if-none-match, if-range.  be
    *        nice to support this.
    *
    *      - 14.44: Vary: seems unneeded.  ignore it for now.
  */   */
   
 #ifndef INDEX_HTML  #ifndef INDEX_HTML
 #define INDEX_HTML              "index.html"  #define INDEX_HTML              "index.html"
 #endif  #endif
 #ifndef SERVER_SOFTWARE  #ifndef SERVER_SOFTWARE
 #define SERVER_SOFTWARE         "bozohttpd/20111118"  #define SERVER_SOFTWARE         "bozohttpd/20140717"
 #endif  #endif
 #ifndef DIRECT_ACCESS_FILE  #ifndef DIRECT_ACCESS_FILE
 #define DIRECT_ACCESS_FILE      ".bzdirect"  #define DIRECT_ACCESS_FILE      ".bzdirect"
Line 333  bozo_clean_request(bozo_httpreq_t *reque
Line 333  bozo_clean_request(bozo_httpreq_t *reque
         bozo_ssl_destroy(request->hr_httpd);          bozo_ssl_destroy(request->hr_httpd);
   
         /* clean up request */          /* clean up request */
 #define MF(x)   if (request->x) free(request->x)          free(request->hr_remotehost);
         MF(hr_remotehost);          free(request->hr_remoteaddr);
         MF(hr_remoteaddr);          free(request->hr_serverport);
         MF(hr_serverport);          free(request->hr_virthostname);
         MF(hr_file);          free(request->hr_file);
         MF(hr_oldfile);          free(request->hr_oldfile);
         MF(hr_query);          free(request->hr_query);
 #undef MF          free(request->hr_host);
         bozo_auth_cleanup(request);          bozo_auth_cleanup(request);
         for (hdr = SIMPLEQ_FIRST(&request->hr_headers); hdr;          for (hdr = SIMPLEQ_FIRST(&request->hr_headers); hdr;
             hdr = SIMPLEQ_NEXT(hdr, h_next)) {              hdr = SIMPLEQ_NEXT(hdr, h_next)) {
                 free(hdr->h_value);                  free(hdr->h_value);
                 free(hdr->h_header);                  free(hdr->h_header);
                 if (ohdr)                  free(ohdr);
                         free(ohdr);  
                 ohdr = hdr;                  ohdr = hdr;
         }          }
         if (ohdr)          free(ohdr);
                 free(ohdr);  
   
         free(request);          free(request);
 }  }
Line 529  bozo_read_request(bozohttpd_t *httpd)
Line 527  bozo_read_request(bozohttpd_t *httpd)
          */           */
         if (bozo_daemon_fork(httpd))          if (bozo_daemon_fork(httpd))
                 return NULL;                  return NULL;
         bozo_ssl_accept(httpd);          if (bozo_ssl_accept(httpd))
                   return NULL;
   
         request = bozomalloc(httpd, sizeof(*request));          request = bozomalloc(httpd, sizeof(*request));
         memset(request, 0, sizeof(*request));          memset(request, 0, sizeof(*request));
Line 539  bozo_read_request(bozohttpd_t *httpd)
Line 538  bozo_read_request(bozohttpd_t *httpd)
         request->hr_range = NULL;          request->hr_range = NULL;
         request->hr_last_byte_pos = -1;          request->hr_last_byte_pos = -1;
         request->hr_if_modified_since = NULL;          request->hr_if_modified_since = NULL;
           request->hr_virthostname = NULL;
         request->hr_file = NULL;          request->hr_file = NULL;
         request->hr_oldfile = NULL;          request->hr_oldfile = NULL;
   
Line 681  bozo_read_request(bozohttpd_t *httpd)
Line 681  bozo_read_request(bozohttpd_t *httpd)
                         else if (strcasecmp(hdr->h_header, "content-length") == 0)                          else if (strcasecmp(hdr->h_header, "content-length") == 0)
                                 request->hr_content_length = hdr->h_value;                                  request->hr_content_length = hdr->h_value;
                         else if (strcasecmp(hdr->h_header, "host") == 0)                          else if (strcasecmp(hdr->h_header, "host") == 0)
                                 request->hr_host = hdr->h_value;                                  request->hr_host = bozostrdup(httpd, hdr->h_value);
                         /* HTTP/1.1 rev06 draft spec: 14.20 */                          /* RFC 2616 (HTTP/1.1): 14.20 */
                         else if (strcasecmp(hdr->h_header, "expect") == 0) {                          else if (strcasecmp(hdr->h_header, "expect") == 0) {
                                 (void)bozo_http_error(httpd, 417, request,                                  (void)bozo_http_error(httpd, 417, request,
                                                 "we don't support Expect:");                                                  "we don't support Expect:");
Line 719  next_header:
Line 719  next_header:
                 goto cleanup;                  goto cleanup;
         }          }
   
         /* HTTP/1.1 draft rev-06, 14.23 & 19.6.1.1 */          /* RFC 2616 (HTTP/1.1), 14.23 & 19.6.1.1 */
         if (request->hr_proto == httpd->consts.http_11 &&          if (request->hr_proto == httpd->consts.http_11 &&
               /*(strncasecmp(request->hr_file, "http://", 7) != 0) &&*/
             request->hr_host == NULL) {              request->hr_host == NULL) {
                 (void)bozo_http_error(httpd, 400, request,                  (void)bozo_http_error(httpd, 400, request,
                                 "missing Host header");                                  "missing Host header");
Line 852  parse_http_date(const char *val, time_t 
Line 853  parse_http_date(const char *val, time_t 
  * to be updated for any sort of parallel processing.   * to be updated for any sort of parallel processing.
  */   */
 char *  char *
 escape_rfc3986(bozohttpd_t *httpd, const char *url)  bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url)
 {  {
         static char *buf;          static char *buf;
         static size_t buflen = 0;          static size_t buflen = 0;
Line 865  escape_rfc3986(bozohttpd_t *httpd, const
Line 866  escape_rfc3986(bozohttpd_t *httpd, const
                 buflen = len * 3 + 1;                  buflen = len * 3 + 1;
                 buf = bozorealloc(httpd, buf, buflen);                  buf = bozorealloc(httpd, buf, buflen);
         }          }
   
         if (url == NULL) {          if (url == NULL) {
                 buf[0] = 0;                  buf[0] = 0;
                 return buf;                  return buf;
Line 922  check_direct_access(bozo_httpreq_t *requ
Line 923  check_direct_access(bozo_httpreq_t *requ
         char dir[MAXPATHLEN], dirfile[MAXPATHLEN], *basename;          char dir[MAXPATHLEN], dirfile[MAXPATHLEN], *basename;
   
         snprintf(dir, sizeof(dir), "%s", request->hr_file + 1);          snprintf(dir, sizeof(dir), "%s", request->hr_file + 1);
         debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir));          debug((request->hr_httpd, DEBUG_FAT, "check_direct_access: dir %s", dir));
         basename = strrchr(dir, '/');          basename = strrchr(dir, '/');
   
         if ((!basename || basename[1] != '\0') &&          if ((!basename || basename[1] != '\0') &&
Line 935  check_direct_access(bozo_httpreq_t *requ
Line 936  check_direct_access(bozo_httpreq_t *requ
                 bozo_check_special_files(request, basename);                  bozo_check_special_files(request, basename);
         }          }
   
         snprintf(dirfile, sizeof(dirfile), "%s/%s", dir, DIRECT_ACCESS_FILE);          if ((size_t)snprintf(dirfile, sizeof(dirfile), "%s/%s", dir,
             DIRECT_ACCESS_FILE) >= sizeof(dirfile)) {
                   bozo_http_error(request->hr_httpd, 404, request,
                     "directfile path too long");
                   return 0;
           }
         if (stat(dirfile, &sb) < 0 ||          if (stat(dirfile, &sb) < 0 ||
             (fp = fopen(dirfile, "r")) == NULL)              (fp = fopen(dirfile, "r")) == NULL)
                 return 0;                  return 0;
Line 954  handle_redirect(bozo_httpreq_t *request,
Line 960  handle_redirect(bozo_httpreq_t *request,
         bozohttpd_t *httpd = request->hr_httpd;          bozohttpd_t *httpd = request->hr_httpd;
         char *urlbuf;          char *urlbuf;
         char portbuf[20];          char portbuf[20];
           const char *hostname = BOZOHOST(httpd, request);
         int query = 0;          int query = 0;
   
         if (url == NULL) {          if (url == NULL) {
                 if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0)                  if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0)
                         bozo_err(httpd, 1, "asprintf");                          bozo_err(httpd, 1, "asprintf");
                 url = urlbuf;                  url = urlbuf;
         } else          } else
                 urlbuf = NULL;                  urlbuf = NULL;
         url = escape_rfc3986(request->hr_httpd, url);          url = bozo_escape_rfc3986(request->hr_httpd, url);
   
         if (request->hr_query && strlen(request->hr_query))          if (request->hr_query && strlen(request->hr_query))
                 query = 1;                  query = 1;
Line 972  handle_redirect(bozo_httpreq_t *request,
Line 979  handle_redirect(bozo_httpreq_t *request,
                     request->hr_serverport);                      request->hr_serverport);
         else          else
                 portbuf[0] = '\0';                  portbuf[0] = '\0';
         bozo_warn(httpd, "redirecting %s%s%s", httpd->virthostname, portbuf, url);          if (absolute)
                   bozo_warn(httpd, "redirecting %s", url);
           else
                   bozo_warn(httpd, "redirecting %s%s%s", hostname, portbuf, url);
         debug((httpd, DEBUG_FAT, "redirecting %s", url));          debug((httpd, DEBUG_FAT, "redirecting %s", url));
         bozo_printf(httpd, "%s 301 Document Moved\r\n", request->hr_proto);          bozo_printf(httpd, "%s 301 Document Moved\r\n", request->hr_proto);
         if (request->hr_proto != httpd->consts.http_09)          if (request->hr_proto != httpd->consts.http_09)
                 bozo_print_header(request, NULL, "text/html", NULL);                  bozo_print_header(request, NULL, "text/html", NULL);
         if (request->hr_proto != httpd->consts.http_09) {          if (request->hr_proto != httpd->consts.http_09) {
                 bozo_printf(httpd, "Location: http://");                  bozo_printf(httpd, "Location: http://");
                 if (absolute == 0)                  if (absolute == 0)
                         bozo_printf(httpd, "%s%s", httpd->virthostname, portbuf);                          bozo_printf(httpd, "%s%s", hostname, portbuf);
                 if (query) {                  if (query) {
                         bozo_printf(httpd, "%s?%s\r\n", url, request->hr_query);                          bozo_printf(httpd, "%s?%s\r\n", url, request->hr_query);
                 } else {                  } else {
Line 997  handle_redirect(bozo_httpreq_t *request,
Line 1007  handle_redirect(bozo_httpreq_t *request,
                 if (absolute)                  if (absolute)
                         bozo_printf(httpd, "%s?%s", url, request->hr_query);                          bozo_printf(httpd, "%s?%s", url, request->hr_query);
                 else                  else
                         bozo_printf(httpd, "%s%s%s?%s", httpd->virthostname,                          bozo_printf(httpd, "%s%s%s?%s", hostname,
                                     portbuf, url, request->hr_query);                                      portbuf, url, request->hr_query);
         } else {          } else {
                 if (absolute)                  if (absolute)
                         bozo_printf(httpd, "%s", url);                          bozo_printf(httpd, "%s", url);
                 else                  else
                         bozo_printf(httpd, "%s%s%s", httpd->virthostname,                          bozo_printf(httpd, "%s%s%s", hostname,
                                     portbuf, url);                                      portbuf, url);
         }          }
         bozo_printf(httpd, "\">here</a>\n");          bozo_printf(httpd, "\">here</a>\n");
         bozo_printf(httpd, "</body></html>\n");          bozo_printf(httpd, "</body></html>\n");
 head:  head:
         bozo_flush(httpd, stdout);          bozo_flush(httpd, stdout);
         if (urlbuf)          free(urlbuf);
                 free(urlbuf);  
 }  }
   
 /*  /*
Line 1039  check_virtual(bozo_httpreq_t *request)
Line 1048  check_virtual(bozo_httpreq_t *request)
         if (strncasecmp(file, "http://", 7) == 0) {          if (strncasecmp(file, "http://", 7) == 0) {
                 /* we would do virtual hosting here? */                  /* we would do virtual hosting here? */
                 file += 7;                  file += 7;
                   /* RFC 2616 (HTTP/1.1), 5.2: URI takes precedence over Host: */
                   free(request->hr_host);
                   request->hr_host = bozostrdup(request->hr_httpd, file);
                   if ((s = strchr(request->hr_host, '/')) != NULL)
                           *s = '\0';
                 s = strchr(file, '/');                  s = strchr(file, '/');
                 /* HTTP/1.1 draft rev-06, 5.2: URI takes precedence over Host: */                  free(request->hr_file);
                 request->hr_host = file;  
                 request->hr_file = bozostrdup(request->hr_httpd, s ? s : "/");                  request->hr_file = bozostrdup(request->hr_httpd, s ? s : "/");
                 debug((httpd, DEBUG_OBESE, "got host ``%s'' file is now ``%s''",                  debug((httpd, DEBUG_OBESE, "got host ``%s'' file is now ``%s''",
                     request->hr_host, request->hr_file));                      request->hr_host, request->hr_file));
Line 1049  check_virtual(bozo_httpreq_t *request)
Line 1062  check_virtual(bozo_httpreq_t *request)
                 goto use_slashdir;                  goto use_slashdir;
   
         /*          /*
          * ok, we have a virtual host, use scandir(3) to find a case           * canonicalise hr_host - that is, remove any :80.
            */
           len = strlen(request->hr_host);
           if (len > 3 && strcmp(request->hr_host + len - 3, ":80") == 0) {
                   request->hr_host[len - 3] = '\0';
                   len = strlen(request->hr_host);
           }
   
           /*
            * ok, we have a virtual host, use opendir(3) to find a case
          * insensitive match for the virtual host we are asked for.           * insensitive match for the virtual host we are asked for.
          * note that if the virtual host is the same as the master,           * note that if the virtual host is the same as the master,
          * we don't need to do anything special.           * we don't need to do anything special.
          */           */
         len = strlen(request->hr_host);  
         debug((httpd, DEBUG_OBESE,          debug((httpd, DEBUG_OBESE,
             "check_virtual: checking host `%s' under httpd->virtbase `%s' "              "check_virtual: checking host `%s' under httpd->virtbase `%s' "
             "for file `%s'",              "for file `%s'",
Line 1076  check_virtual(bozo_httpreq_t *request)
Line 1097  check_virtual(bozo_httpreq_t *request)
                                     len) == 0) {                                      len) == 0) {
                                         /* found it, punch it */                                          /* found it, punch it */
                                         debug((httpd, DEBUG_OBESE, "found it punch it"));                                          debug((httpd, DEBUG_OBESE, "found it punch it"));
                                         httpd->virthostname = d->d_name;                                          request->hr_virthostname =
                                               bozostrdup(httpd, d->d_name);
                                         if (asprintf(&s, "%s/%s", httpd->virtbase,                                          if (asprintf(&s, "%s/%s", httpd->virtbase,
                                             httpd->virthostname) < 0)                                              request->hr_virthostname) < 0)
                                                 bozo_err(httpd, 1, "asprintf");                                                  bozo_err(httpd, 1, "asprintf");
                                         break;                                          break;
                                 }                                  }
Line 1110  use_slashdir:
Line 1132  use_slashdir:
   
 /*  /*
  * checks to see if this request has a valid .bzredirect file.  returns   * checks to see if this request has a valid .bzredirect file.  returns
  * 0 on failure and 1 on success.   * 0 when no redirection happend, or 1 when handle_redirect() has been
    * called, -1 on error.
  */   */
 static void  static int
 check_bzredirect(bozo_httpreq_t *request)  check_bzredirect(bozo_httpreq_t *request)
 {  {
         struct stat sb;          struct stat sb;
         char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1];          char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1],
               path[MAXPATHLEN];
         char *basename, *finalredir;          char *basename, *finalredir;
         int rv, absolute;          int rv, absolute;
   
Line 1124  check_bzredirect(bozo_httpreq_t *request
Line 1148  check_bzredirect(bozo_httpreq_t *request
          * if this pathname is really a directory, but doesn't end in /,           * if this pathname is really a directory, but doesn't end in /,
          * use it as the directory to look for the redir file.           * use it as the directory to look for the redir file.
          */           */
         snprintf(dir, sizeof(dir), "%s", request->hr_file + 1);          if((size_t)snprintf(dir, sizeof(dir), "%s", request->hr_file + 1) >=
             sizeof(dir)) {
                   bozo_http_error(request->hr_httpd, 404, request,
                     "file path too long");
                   return -1;
           }
         debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir));          debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir));
         basename = strrchr(dir, '/');          basename = strrchr(dir, '/');
   
Line 1138  check_bzredirect(bozo_httpreq_t *request
Line 1167  check_bzredirect(bozo_httpreq_t *request
                 bozo_check_special_files(request, basename);                  bozo_check_special_files(request, basename);
         }          }
   
         snprintf(redir, sizeof(redir), "%s/%s", dir, REDIRECT_FILE);          if ((size_t)snprintf(redir, sizeof(redir), "%s/%s", dir,
             REDIRECT_FILE) >= sizeof(redir)) {
                   bozo_http_error(request->hr_httpd, 404, request,
                     "redirectfile path too long");
                   return -1;
           }
         if (lstat(redir, &sb) == 0) {          if (lstat(redir, &sb) == 0) {
                 if (!S_ISLNK(sb.st_mode))                  if (!S_ISLNK(sb.st_mode))
                         return;                          return 0;
                 absolute = 0;                  absolute = 0;
         } else {          } else {
                 snprintf(redir, sizeof(redir), "%s/%s", dir, ABSREDIRECT_FILE);                  if((size_t)snprintf(redir, sizeof(redir), "%s/%s", dir,
                     ABSREDIRECT_FILE) >= sizeof(redir)) {
                           bozo_http_error(request->hr_httpd, 404, request,
                             "redirectfile path too long");
                           return -1;
                   }
                 if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode))                  if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode))
                         return;                          return 0;
                 absolute = 1;                  absolute = 1;
         }          }
         debug((request->hr_httpd, DEBUG_FAT,          debug((request->hr_httpd, DEBUG_FAT,
Line 1154  check_bzredirect(bozo_httpreq_t *request
Line 1193  check_bzredirect(bozo_httpreq_t *request
         rv = readlink(redir, redirpath, sizeof redirpath - 1);          rv = readlink(redir, redirpath, sizeof redirpath - 1);
         if (rv == -1 || rv == 0) {          if (rv == -1 || rv == 0) {
                 debug((request->hr_httpd, DEBUG_FAT, "readlink failed"));                  debug((request->hr_httpd, DEBUG_FAT, "readlink failed"));
                 return;                  return 0;
         }          }
         redirpath[rv] = '\0';          redirpath[rv] = '\0';
         debug((request->hr_httpd, DEBUG_FAT,          debug((request->hr_httpd, DEBUG_FAT,
                "readlink returned \"%s\"", redirpath));                 "readlink returned \"%s\"", redirpath));
   
           /* check if we need authentication */
           snprintf(path, sizeof(path), "%s/", dir);
           if (bozo_auth_check(request, path))
                   return 1;
   
         /* now we have the link pointer, redirect to the real place */          /* now we have the link pointer, redirect to the real place */
         if (absolute)          if (absolute)
                 finalredir = redirpath;                  finalredir = redirpath;
         else          else {
                 snprintf(finalredir = redir, sizeof(redir), "/%s/%s", dir,                  if ((size_t)snprintf(finalredir = redir, sizeof(redir), "/%s/%s",
                          redirpath);                    dir, redirpath) >= sizeof(redir)) {
                           bozo_http_error(request->hr_httpd, 404, request,
                             "redirect path too long");
                           return -1;
                   }
           }
   
         debug((request->hr_httpd, DEBUG_FAT,          debug((request->hr_httpd, DEBUG_FAT,
                "check_bzredirect: new redir %s", finalredir));                 "check_bzredirect: new redir %s", finalredir));
         handle_redirect(request, finalredir, absolute);          handle_redirect(request, finalredir, absolute);
           return 1;
 }  }
   
 /* this fixes the %HH hack that RFC2396 requires.  */  /* this fixes the %HH hack that RFC2396 requires.  */
 static void  static int
 fix_url_percent(bozo_httpreq_t *request)  fix_url_percent(bozo_httpreq_t *request)
 {  {
         bozohttpd_t *httpd = request->hr_httpd;          bozohttpd_t *httpd = request->hr_httpd;
Line 1186  fix_url_percent(bozo_httpreq_t *request)
Line 1236  fix_url_percent(bozo_httpreq_t *request)
   
         /* fast forward to the first % */          /* fast forward to the first % */
         if ((s = strchr(url, '%')) == NULL)          if ((s = strchr(url, '%')) == NULL)
                 return;                  return 0;
   
         t = s;          t = s;
         do {          do {
Line 1203  fix_url_percent(bozo_httpreq_t *request)
Line 1253  fix_url_percent(bozo_httpreq_t *request)
                 if (s[1] == '\0' || s[2] == '\0') {                  if (s[1] == '\0' || s[2] == '\0') {
                         (void)bozo_http_error(httpd, 400, request,                          (void)bozo_http_error(httpd, 400, request,
                             "percent hack missing two chars afterwards");                              "percent hack missing two chars afterwards");
                         goto copy_rest;                          return 1;
                 }                  }
                 if (s[1] == '0' && s[2] == '0') {                  if (s[1] == '0' && s[2] == '0') {
                         (void)bozo_http_error(httpd, 404, request,                          (void)bozo_http_error(httpd, 404, request,
                                         "percent hack was %00");                                          "percent hack was %00");
                         goto copy_rest;                          return 1;
                 }                  }
                 if (s[1] == '2' && s[2] == 'f') {                  if (s[1] == '2' && s[2] == 'f') {
                         (void)bozo_http_error(httpd, 404, request,                          (void)bozo_http_error(httpd, 404, request,
                                         "percent hack was %2f (/)");                                          "percent hack was %2f (/)");
                         goto copy_rest;                          return 1;
                 }                  }
   
                 buf[0] = *++s;                  buf[0] = *++s;
                 buf[1] = *++s;                  buf[1] = *++s;
                 buf[2] = '\0';                  buf[2] = '\0';
Line 1226  fix_url_percent(bozo_httpreq_t *request)
Line 1276  fix_url_percent(bozo_httpreq_t *request)
                 if (*t++ == '\0') {                  if (*t++ == '\0') {
                         (void)bozo_http_error(httpd, 400, request,                          (void)bozo_http_error(httpd, 400, request,
                                         "percent hack got a 0 back");                                          "percent hack got a 0 back");
                         goto copy_rest;                          return 1;
                 }                  }
   
                 while (*s && *s != '%') {                  while (*s && *s != '%') {
Line 1235  fix_url_percent(bozo_httpreq_t *request)
Line 1285  fix_url_percent(bozo_httpreq_t *request)
                         *t++ = *s++;                          *t++ = *s++;
                 }                  }
         } while (*s);          } while (*s);
 copy_rest:  
         while (*s) {  
                 if (s >= end)  
                         break;  
                 *t++ = *s++;  
         }  
         *t = '\0';          *t = '\0';
   
         debug((httpd, DEBUG_FAT, "fix_url_percent returns %s in url",          debug((httpd, DEBUG_FAT, "fix_url_percent returns %s in url",
                         request->hr_file));                          request->hr_file));
   
           return 0;
 }  }
   
 /*  /*
Line 1252  copy_rest:
Line 1299  copy_rest:
  *      - punt if it doesn't start with /   *      - punt if it doesn't start with /
  *      - check httpd->untrustedref / referrer   *      - check httpd->untrustedref / referrer
  *      - look for "http://myname/" and deal with it.   *      - look for "http://myname/" and deal with it.
  *      - maybe call bozo_process_cgi()   *      - maybe call bozo_process_cgi()
  *      - check for ~user and call bozo_user_transform() if so   *      - check for ~user and call bozo_user_transform() if so
  *      - if the length > 1, check for trailing slash.  if so,   *      - if the length > 1, check for trailing slash.  if so,
  *        add the index.html file   *        add the index.html file
Line 1268  transform_request(bozo_httpreq_t *reques
Line 1315  transform_request(bozo_httpreq_t *reques
         bozohttpd_t *httpd = request->hr_httpd;          bozohttpd_t *httpd = request->hr_httpd;
         char    *file, *newfile = NULL;          char    *file, *newfile = NULL;
         size_t  len;          size_t  len;
           const char *hostname = BOZOHOST(httpd, request);
   
         file = NULL;          file = NULL;
         *isindex = 0;          *isindex = 0;
         debug((httpd, DEBUG_FAT, "tf_req: file %s", request->hr_file));          debug((httpd, DEBUG_FAT, "tf_req: file %s", request->hr_file));
         fix_url_percent(request);          if (fix_url_percent(request)) {
                   goto bad_done;
           }
         if (check_virtual(request)) {          if (check_virtual(request)) {
                 goto bad_done;                  goto bad_done;
         }          }
Line 1283  transform_request(bozo_httpreq_t *reques
Line 1333  transform_request(bozo_httpreq_t *reques
                 goto bad_done;                  goto bad_done;
         }          }
   
         check_bzredirect(request);          switch(check_bzredirect(request)) {
           case -1:
                   goto bad_done;
           case 1:
                   return 0;
           }
   
         if (httpd->untrustedref) {          if (httpd->untrustedref) {
                 int to_indexhtml = 0;                  int to_indexhtml = 0;
   
 #define TOP_PAGE(x)     (strcmp((x), "/") == 0 || \  #define TOP_PAGE(x)     (strcmp((x), "/") == 0 || \
                          strcmp((x) + 1, httpd->index_html) == 0 || \                           strcmp((x) + 1, httpd->index_html) == 0 || \
                          strcmp((x) + 1, "favicon.ico") == 0)                           strcmp((x) + 1, "favicon.ico") == 0)
   
                 debug((httpd, DEBUG_EXPLODING, "checking httpd->untrustedref"));                  debug((httpd, DEBUG_EXPLODING, "checking httpd->untrustedref"));
                 /*                  /*
                  * first check that this path isn't allowed via .bzdirect file,                   * first check that this path isn't allowed via .bzdirect file,
Line 1306  transform_request(bozo_httpreq_t *reques
Line 1361  transform_request(bozo_httpreq_t *reques
   
                         debug((httpd, DEBUG_FAT,                          debug((httpd, DEBUG_FAT,
                                 "checking referrer \"%s\" vs virthostname %s",                                  "checking referrer \"%s\" vs virthostname %s",
                                 r, httpd->virthostname));                                  r, hostname));
                         if (strncmp(r, "http://", 7) != 0 ||                          if (strncmp(r, "http://", 7) != 0 ||
                             (strncasecmp(r + 7, httpd->virthostname,                              (strncasecmp(r + 7, hostname,
                                          strlen(httpd->virthostname)) != 0 &&                                           strlen(hostname)) != 0 &&
                              !TOP_PAGE(file)))                               !TOP_PAGE(file)))
                                 to_indexhtml = 1;                                  to_indexhtml = 1;
                 } else {                  } else {
Line 1318  transform_request(bozo_httpreq_t *reques
Line 1373  transform_request(bozo_httpreq_t *reques
                         debug((httpd, DEBUG_FAT, "url has no referrer at all"));                          debug((httpd, DEBUG_FAT, "url has no referrer at all"));
                         /* if there's no referrer, let / or /index.html past */                          /* if there's no referrer, let / or /index.html past */
                         if (!TOP_PAGE(file) ||                          if (!TOP_PAGE(file) ||
                             (h && strncasecmp(h, httpd->virthostname,                              (h && strncasecmp(h, hostname,
                                         strlen(httpd->virthostname)) != 0))                                          strlen(hostname)) != 0))
                                 to_indexhtml = 1;                                  to_indexhtml = 1;
                 }                  }
   
Line 1386  transform_request(bozo_httpreq_t *reques
Line 1441  transform_request(bozo_httpreq_t *reques
          */           */
   
         /*          /*
          * stop traversing outside our domain           * stop traversing outside our domain
          *           *
          * XXX true security only comes from our parent using chroot(2)           * XXX true security only comes from our parent using chroot(2)
          * before execve(2)'ing us.  or our own built in chroot(2) support.           * before execve(2)'ing us.  or our own built in chroot(2) support.
Line 1408  transform_request(bozo_httpreq_t *reques
Line 1463  transform_request(bozo_httpreq_t *reques
         if (bozo_process_cgi(request))          if (bozo_process_cgi(request))
                 return 0;                  return 0;
   
           if (bozo_process_lua(request))
                   return 0;
   
         debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile));          debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile));
         return 1;          return 1;
 bad_done:  bad_done:
         debug((httpd, DEBUG_FAT, "transform_request returning: 0"));          debug((httpd, DEBUG_FAT, "transform_request returning: 0"));
         if (newfile)          free(newfile);
                 free(newfile);  
         return 0;          return 0;
 }  }
   
Line 1506  bozo_process_request(bozo_httpreq_t *req
Line 1563  bozo_process_request(bozo_httpreq_t *req
   
         if (fd < 0) {          if (fd < 0) {
                 debug((httpd, DEBUG_FAT, "open failed: %s", strerror(errno)));                  debug((httpd, DEBUG_FAT, "open failed: %s", strerror(errno)));
                 if (errno == EPERM)                  switch(errno) {
                   case EPERM:
                         (void)bozo_http_error(httpd, 403, request,                          (void)bozo_http_error(httpd, 403, request,
                                                 "no permission to open file");                                                  "no permission to open file");
                 else if (errno == ENOENT) {                          break;
                         if (!bozo_dir_index(request, file, isindex))                  case ENAMETOOLONG:
                           /*FALLTHROUGH*/
                   case ENOENT:
                           if (!bozo_dir_index(request, file, isindex))
                                 (void)bozo_http_error(httpd, 404, request,                                  (void)bozo_http_error(httpd, 404, request,
                                                         "no file");                                                          "no file");
                 } else                          break;
                   default:
                         (void)bozo_http_error(httpd, 500, request, "open file");                          (void)bozo_http_error(httpd, 500, request, "open file");
                   }
                 goto cleanup_nofd;                  goto cleanup_nofd;
         }          }
         if (fstat(fd, &sb) < 0) {          if (fstat(fd, &sb) < 0) {
Line 1673  debug__(bozohttpd_t *httpd, int level, c
Line 1736  debug__(bozohttpd_t *httpd, int level, c
 {  {
         va_list ap;          va_list ap;
         int savederrno;          int savederrno;
   
         /* only log if the level is low enough */          /* only log if the level is low enough */
         if (httpd->debug < level)          if (httpd->debug < level)
                 return;                  return;
Line 1722  bozo_err(bozohttpd_t *httpd, int code, c
Line 1785  bozo_err(bozohttpd_t *httpd, int code, c
         exit(code);          exit(code);
 }  }
   
 /* this escape HTML tags */  /*
 static void   * this escapes HTML tags.  returns allocated escaped
 escape_html(bozo_httpreq_t *request)   * string if needed, or NULL on allocation failure or
    * lack of escape need.
    * call with NULL httpd in error paths, to avoid recursive
    * malloc failure.  call with valid httpd in normal paths
    * to get automatic allocation failure handling.
    */
   char *
   bozo_escape_html(bozohttpd_t *httpd, const char *url)
 {  {
         int     i, j;          int     i, j;
         char    *url = request->hr_file, *tmp;          char    *tmp;
           size_t  len;
   
         for (i = 0, j = 0; url[i]; i++) {          for (i = 0, j = 0; url[i]; i++) {
                 switch (url[i]) {                  switch (url[i]) {
Line 1742  escape_html(bozo_httpreq_t *request)
Line 1813  escape_html(bozo_httpreq_t *request)
         }          }
   
         if (j == 0)          if (j == 0)
                 return;                  return NULL;
   
         if ((tmp = (char *) malloc(strlen(url) + j)) == 0)          /*
                 /*           * we need to handle being called from different
                  * ouch, but we are only called from an error context, and           * pathnames.
                  * most paths here come from malloc(3) failures anyway...           */
                  * we could completely punt and just exit, but isn't returning          len = strlen(url) + j;
                  * an not-quite-correct error better than nothing at all?          if (httpd)
                  */                  tmp = bozomalloc(httpd, len);
                 return;          else if ((tmp = malloc(len)) == 0)
                           return NULL;
   
         for (i = 0, j = 0; url[i]; i++) {          for (i = 0, j = 0; url[i]; i++) {
                 switch (url[i]) {                  switch (url[i]) {
Line 1773  escape_html(bozo_httpreq_t *request)
Line 1845  escape_html(bozo_httpreq_t *request)
         }          }
         tmp[j] = 0;          tmp[j] = 0;
   
         free(request->hr_file);          return tmp;
         request->hr_file = tmp;  
 }  }
   
 /* short map between error code, and short/long messages */  /* short map between error code, and short/long messages */
Line 1847  bozo_http_error(bozohttpd_t *httpd, int 
Line 1918  bozo_http_error(bozohttpd_t *httpd, int 
                 portbuf[0] = '\0';                  portbuf[0] = '\0';
   
         if (request && request->hr_file) {          if (request && request->hr_file) {
                 escape_html(request);                  char *file = NULL;
                   const char *hostname = BOZOHOST(httpd, request);
   
                   /* bozo_escape_html() failure here is just too bad. */
                   file = bozo_escape_html(NULL, request->hr_file);
                   if (file == NULL)
                           file = request->hr_file;
                 size = snprintf(httpd->errorbuf, BUFSIZ,                  size = snprintf(httpd->errorbuf, BUFSIZ,
                     "<html><head><title>%s</title></head>\n"                      "<html><head><title>%s</title></head>\n"
                     "<body><h1>%s</h1>\n"                      "<body><h1>%s</h1>\n"
                     "%s: <pre>%s</pre>\n"                      "%s: <pre>%s</pre>\n"
                     "<hr><address><a href=\"http://%s%s/\">%s%s</a></address>\n"                      "<hr><address><a href=\"http://%s%s/\">%s%s</a></address>\n"
                     "</body></html>\n",                      "</body></html>\n",
                     header, header, request->hr_file, reason,                      header, header, file, reason,
                     httpd->virthostname, portbuf, httpd->virthostname, portbuf);                      hostname, portbuf, hostname, portbuf);
                 if (size >= (int)BUFSIZ) {                  if (size >= (int)BUFSIZ) {
                         bozo_warn(httpd,                          bozo_warn(httpd,
                                 "bozo_http_error buffer too small, truncated");                                  "bozo_http_error buffer too small, truncated");
Line 1874  bozo_http_error(bozohttpd_t *httpd, int 
Line 1951  bozo_http_error(bozohttpd_t *httpd, int 
         if (request && request->hr_allow)          if (request && request->hr_allow)
                 bozo_printf(httpd, "Allow: %s\r\n", request->hr_allow);                  bozo_printf(httpd, "Allow: %s\r\n", request->hr_allow);
         bozo_printf(httpd, "\r\n");          bozo_printf(httpd, "\r\n");
         if (size)          /* According to the RFC 2616 sec. 9.4 HEAD method MUST NOT return a
            * message-body in the response */
           if (size && request && request->hr_method != HTTP_HEAD)
                 bozo_printf(httpd, "%s", httpd->errorbuf);                  bozo_printf(httpd, "%s", httpd->errorbuf);
         bozo_flush(httpd, stdout);          bozo_flush(httpd, stdout);
   
Line 2055  bozo_init_httpd(bozohttpd_t *httpd)
Line 2134  bozo_init_httpd(bozohttpd_t *httpd)
                         "bozohttpd: memory_allocation failure\n");                          "bozohttpd: memory_allocation failure\n");
                 return 0;                  return 0;
         }          }
   #ifndef NO_LUA_SUPPORT
           SIMPLEQ_INIT(&httpd->lua_states);
   #endif
         return 1;          return 1;
 }  }
   

Legend:
Removed from v.1.32.2.1  
changed lines
  Added in v.1.32.2.2

CVSweb <webmaster@jp.NetBSD.org>