[BACK]Return to cgi-bozo.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/cgi-bozo.c between version 1.25.2.2.2.8 and 1.25.2.3

version 1.25.2.2.2.8, 2019/06/15 15:57:32 version 1.25.2.3, 2016/04/10 10:33:11
Line 3 
Line 3 
 /*      $eterna: cgi-bozo.c,v 1.40 2011/11/18 09:21:15 mrg Exp $        */  /*      $eterna: cgi-bozo.c,v 1.40 2011/11/18 09:21:15 mrg Exp $        */
   
 /*  /*
  * Copyright (c) 1997-2019 Matthew R. Green   * Copyright (c) 1997-2015 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 45 
Line 45 
 #include <string.h>  #include <string.h>
 #include <syslog.h>  #include <syslog.h>
 #include <unistd.h>  #include <unistd.h>
 #include <assert.h>  
   
 #include <netinet/in.h>  #include <netinet/in.h>
   
Line 63 
Line 62 
  */   */
 static const char *  static const char *
 content_cgihandler(bozohttpd_t *httpd, bozo_httpreq_t *request,  content_cgihandler(bozohttpd_t *httpd, bozo_httpreq_t *request,
                    const char *file)                  const char *file)
 {  {
         bozo_content_map_t      *map;          bozo_content_map_t      *map;
   
Line 104  parse_header(bozo_httpreq_t *request, co
Line 103  parse_header(bozo_httpreq_t *request, co
         *hdr_val = value;          *hdr_val = value;
   
         return 0;          return 0;
 }  }
   
 /*  /*
  * handle parsing a CGI header output, transposing a Status: header   * handle parsing a CGI header output, transposing a Status: header
Line 124  finish_cgi_output(bozohttpd_t *httpd, bo
Line 123  finish_cgi_output(bozohttpd_t *httpd, bo
         /* much of this code is like bozo_read_request()'s header loop. */          /* much of this code is like bozo_read_request()'s header loop. */
         SIMPLEQ_INIT(&headers);          SIMPLEQ_INIT(&headers);
         write_header = nph == 0;          write_header = nph == 0;
           /* was read(2) here - XXX - agc */
         while (nph == 0 &&          while (nph == 0 &&
                 (str = bozodgetln(httpd, in, &len, bozo_read)) != NULL) {                  (str = bozodgetln(httpd, in, &len, bozo_read)) != NULL) {
                 char    *hdr_name, *hdr_value;                  char    *hdr_name, *hdr_value;
Line 144  finish_cgi_output(bozohttpd_t *httpd, bo
Line 144  finish_cgi_output(bozohttpd_t *httpd, bo
                  */                   */
                 if (strcasecmp(hdr_name, "status") == 0) {                  if (strcasecmp(hdr_name, "status") == 0) {
                         debug((httpd, DEBUG_OBESE,                          debug((httpd, DEBUG_OBESE,
                                 "%s: writing HTTP header "                                  "bozo_process_cgi:  writing HTTP header "
                                 "from status %s ..", __func__, hdr_value));                                  "from status %s ..", hdr_value));
                         bozo_printf(httpd, "%s %s\r\n", request->hr_proto,                          bozo_printf(httpd, "%s %s\r\n", request->hr_proto,
                                     hdr_value);                                          hdr_value);
                         bozo_flush(httpd, stdout);                          bozo_flush(httpd, stdout);
                         write_header = 0;                          write_header = 0;
                         free(hdr_name);                          free(hdr_name);
Line 163  finish_cgi_output(bozohttpd_t *httpd, bo
Line 163  finish_cgi_output(bozohttpd_t *httpd, bo
   
         if (write_header) {          if (write_header) {
                 debug((httpd, DEBUG_OBESE,                  debug((httpd, DEBUG_OBESE,
                         "%s: writing HTTP header ..", __func__));                          "bozo_process_cgi:  writing HTTP header .."));
                 bozo_printf(httpd,                  bozo_printf(httpd,
                         "%s 200 OK\r\n", request->hr_proto);                          "%s 200 OK\r\n", request->hr_proto);
                 bozo_flush(httpd, stdout);                  bozo_flush(httpd, stdout);
Line 171  finish_cgi_output(bozohttpd_t *httpd, bo
Line 171  finish_cgi_output(bozohttpd_t *httpd, bo
   
         if (nheaders) {          if (nheaders) {
                 debug((httpd, DEBUG_OBESE,                  debug((httpd, DEBUG_OBESE,
                         "%s:  writing delayed HTTP headers ..", __func__));                          "bozo_process_cgi:  writing delayed HTTP headers .."));
                 SIMPLEQ_FOREACH_SAFE(hdr, &headers, h_next, nhdr) {                  SIMPLEQ_FOREACH_SAFE(hdr, &headers, h_next, nhdr) {
                         bozo_printf(httpd, "%s: %s\r\n", hdr->h_header,                          bozo_printf(httpd, "%s: %s\r\n", hdr->h_header,
                                     hdr->h_value);                                          hdr->h_value);
                         free(hdr->h_header);                          free(hdr->h_header);
                         free(hdr);                          free(hdr);
                 }                  }
Line 190  finish_cgi_output(bozohttpd_t *httpd, bo
Line 190  finish_cgi_output(bozohttpd_t *httpd, bo
   
                 while (rbytes) {                  while (rbytes) {
                         wbytes = bozo_write(httpd, STDOUT_FILENO, buf,                          wbytes = bozo_write(httpd, STDOUT_FILENO, buf,
                                             (size_t)rbytes);                                                  (size_t)rbytes);
                         if (wbytes > 0) {                          if (wbytes > 0) {
                                 rbytes -= wbytes;                                  rbytes -= wbytes;
                                 bp += wbytes;                                  bp += wbytes;
Line 212  append_index_html(bozohttpd_t *httpd, ch
Line 212  append_index_html(bozohttpd_t *httpd, ch
                 "append_index_html: url adjusted to `%s'", *url));                  "append_index_html: url adjusted to `%s'", *url));
 }  }
   
 /* This function parse search-string according to section 4.4 of RFC3875 */  
 static char **  
 parse_search_string(bozo_httpreq_t *request, const char *query, size_t *args_len)  
 {  
         struct  bozohttpd_t *httpd = request->hr_httpd;  
         size_t i;  
         char *s, *str, **args;  
   
         *args_len = 0;  
   
         /* URI MUST not contain any unencoded '=' - RFC3875, section 4.4 */  
         if (strchr(query, '='))  
                 return NULL;  
   
         str = bozostrdup(httpd, request, query);  
   
         /*  
          * there's no more arguments than '+' chars in the query string as it's  
          * the separator  
          */  
         *args_len = 1;  
         /* count '+' in str */  
         for (s = str; (s = strchr(s, '+')) != NULL; (*args_len)++)  
                 s++;  
   
         args = bozomalloc(httpd, sizeof(*args) * (*args_len + 1));  
   
         args[0] = str;  
         args[*args_len] = NULL;  
         for (s = str, i = 1; (s = strchr(s, '+')) != NULL; i++) {  
                 *s = '\0';  
                 s++;  
                 args[i] = s;  
         }  
   
         /*  
          * check if search-strings are valid:  
          *  
          * RFC3875, section 4.4:  
          *  
          * search-string = search-word *( "+" search-word )  
          * search-word   = 1*schar  
          * schar                 = unreserved | escaped | xreserved  
          * xreserved     = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "," |  
          *                 "$"  
          *  
          * section 2.3:  
          *  
          * hex        = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" |  
          *              "b" | "c" | "d" | "e" | "f"  
          * escaped    = "%" hex hex  
          * unreserved = alpha | digit | mark  
          * mark       = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"  
          *  
          * section 2.2:  
          *  
          * alpha        = lowalpha | hialpha  
          * lowalpha     = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" |  
          *                "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" |  
          *                "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" |  
          *                "y" | "z"  
          * hialpha      = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" |  
          *                "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" |  
          *                "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" |  
          *                "Y" | "Z"  
          * digit        = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |  
          *                "8" | "9"  
          */  
 #define UNRESERVED_CHAR "-_.!~*'()"  
 #define XRESERVED_CHAR  ";/?:@&=,$"  
   
         for (i = 0; i < *args_len; i++) {  
                 s = args[i];  
                 /* search-word MUST have at least one schar */  
                 if (*s == '\0')  
                         goto parse_err;  
                 while (*s) {  
                         /* check if it's unreserved */  
                         if (isalpha((int)*s) || isdigit((int)*s) ||  
                             strchr(UNRESERVED_CHAR, *s)) {  
                                 s++;  
                                 continue;  
                         }  
   
                         /* check if it's escaped */  
                         if (*s == '%') {  
                                 if (s[1] == '\0' || s[2] == '\0')  
                                         goto parse_err;  
                                 if (!isxdigit((int)s[1]) ||  
                                     !isxdigit((int)s[2]))  
                                         goto parse_err;  
                                 s += 3;  
                                 continue;  
                         }  
   
                         /* check if it's xreserved */  
   
                         if (strchr(XRESERVED_CHAR, *s)) {  
                                 s++;  
                                 continue;  
                         }  
   
                         goto parse_err;  
                 }  
         }  
   
         /* decode percent encoding */  
         for (i = 0; i < *args_len; i++) {  
                 if (bozo_decode_url_percent(request, args[i]))  
                         goto parse_err;  
         }  
   
         /* allocate each arg separately */  
         for (i = 0; i < *args_len; i++)  
                 args[i] = bozostrdup(httpd, request, args[i]);  
         free(str);  
   
         return args;  
   
 parse_err:  
   
         free(str);  
         free(args);  
         *args_len = 0;  
   
         return NULL;  
   
 }  
   
 void  void
 bozo_cgi_setbin(bozohttpd_t *httpd, const char *path)  bozo_cgi_setbin(bozohttpd_t *httpd, const char *path)
 {  {
         httpd->cgibin = bozostrdup(httpd, NULL, path);          httpd->cgibin = bozostrdup(httpd, NULL, path);
         debug((httpd, DEBUG_OBESE, "cgibin (cgi-bin directory) is %s",          debug((httpd, DEBUG_OBESE, "cgibin (cgi-bin directory) is %s",
                httpd->cgibin));                  httpd->cgibin));
 }  }
   
 /* help build up the environ pointer */  /* help build up the environ pointer */
Line 378  bozo_process_cgi(bozo_httpreq_t *request
Line 249  bozo_process_cgi(bozo_httpreq_t *request
         bozoheaders_t *headp;          bozoheaders_t *headp;
         const char *type, *clen, *info, *cgihandler;          const char *type, *clen, *info, *cgihandler;
         char    *query, *s, *t, *path, *env, *command, *file, *url;          char    *query, *s, *t, *path, *env, *command, *file, *url;
         char    **envp, **curenvp, **argv, **search_string_argv = NULL;          char    **envp, **curenvp, *argv[4];
         char    **lastenvp;  
         char    *uri;          char    *uri;
         size_t  i, len, search_string_argc = 0;          size_t  len;
         ssize_t rbytes;          ssize_t rbytes;
         pid_t   pid;          pid_t   pid;
         int     envpsize, ix, nph;          int     envpsize, ix, nph;
Line 414  bozo_process_cgi(bozo_httpreq_t *request
Line 284  bozo_process_cgi(bozo_httpreq_t *request
                      file,                       file,
                      query ? "?" : "",                       query ? "?" : "",
                      query ? query : "");                       query ? query : "");
         debug((httpd, DEBUG_NORMAL, "%s: url `%s'", __func__, url));          debug((httpd, DEBUG_NORMAL, "bozo_process_cgi: url `%s'", url));
   
         path = NULL;          path = NULL;
         envp = NULL;          envp = NULL;
Line 432  bozo_process_cgi(bozo_httpreq_t *request
Line 302  bozo_process_cgi(bozo_httpreq_t *request
                 cgihandler = content_cgihandler(httpd, request, file + 1);                  cgihandler = content_cgihandler(httpd, request, file + 1);
                 if (cgihandler == NULL) {                  if (cgihandler == NULL) {
                         debug((httpd, DEBUG_FAT,                          debug((httpd, DEBUG_FAT,
                                 "%s: no handler, returning", __func__));                                  "bozo_process_cgi: no handler, returning"));
                         goto out;                          goto out;
                 }                  }
                 if (len == 0 || file[len - 1] == '/')                  if (len == 0 || file[len - 1] == '/')
                         append_index_html(httpd, &file);                          append_index_html(httpd, &file);
                 debug((httpd, DEBUG_NORMAL, "%s: cgihandler `%s'",                  debug((httpd, DEBUG_NORMAL, "bozo_process_cgi: cgihandler `%s'",
                     __func__, cgihandler));                      cgihandler));
         } else if (len - 1 == CGIBIN_PREFIX_LEN)        /* url is "/cgi-bin/" */          } else if (len - 1 == CGIBIN_PREFIX_LEN)        /* url is "/cgi-bin/" */
                 append_index_html(httpd, &file);                  append_index_html(httpd, &file);
   
         /* RFC3875 sect. 4.4. - search-string support */  
         if (query != NULL) {  
                 search_string_argv = parse_search_string(request, query,  
                     &search_string_argc);  
         }  
   
         debug((httpd, DEBUG_NORMAL, "parse_search_string args no: %zu",  
             search_string_argc));  
         for (i = 0; i < search_string_argc; i++) {  
                 debug((httpd, DEBUG_FAT,  
                     "search_string[%zu]: `%s'", i, search_string_argv[i]));  
         }  
   
         argv = bozomalloc(httpd, sizeof(*argv) * (3 + search_string_argc));  
   
         ix = 0;          ix = 0;
         if (cgihandler) {          if (cgihandler) {
                 command = file + 1;                  command = file + 1;
                 path = bozostrdup(httpd, request, cgihandler);                  path = bozostrdup(httpd, request, cgihandler);
                   argv[ix++] = path;
                           /* argv[] = [ path, command, query, NULL ] */
         } else {          } else {
                 command = file + CGIBIN_PREFIX_LEN + 1;                  command = file + CGIBIN_PREFIX_LEN + 1;
                 if ((s = strchr(command, '/')) != NULL) {                  if ((s = strchr(command, '/')) != NULL) {
Line 472  bozo_process_cgi(bozo_httpreq_t *request
Line 329  bozo_process_cgi(bozo_httpreq_t *request
                 strcpy(path, httpd->cgibin);                  strcpy(path, httpd->cgibin);
                 strcat(path, "/");                  strcat(path, "/");
                 strcat(path, command);                  strcat(path, command);
                           /* argv[] = [ command, query, NULL ] */
         }          }
           argv[ix++] = command;
         argv[ix++] = path;          argv[ix++] = query;
   
         /* copy search-string args */  
         for (i = 0; i < search_string_argc; i++)  
                 argv[ix++] = search_string_argv[i];  
   
         argv[ix++] = NULL;          argv[ix++] = NULL;
   
         nph = strncmp(command, "nph-", 4) == 0;          nph = strncmp(command, "nph-", 4) == 0;
   
         type = request->hr_content_type;          type = request->hr_content_type;
Line 493  bozo_process_cgi(bozo_httpreq_t *request
Line 347  bozo_process_cgi(bozo_httpreq_t *request
             (clen && *clen ? 1 : 0) +              (clen && *clen ? 1 : 0) +
             (request->hr_remotehost && *request->hr_remotehost ? 1 : 0) +              (request->hr_remotehost && *request->hr_remotehost ? 1 : 0) +
             (request->hr_remoteaddr && *request->hr_remoteaddr ? 1 : 0) +              (request->hr_remoteaddr && *request->hr_remoteaddr ? 1 : 0) +
             (cgihandler ? 1 : 0) +  
             bozo_auth_cgi_count(request) +              bozo_auth_cgi_count(request) +
             (request->hr_serverport && *request->hr_serverport ? 1 : 0);              (request->hr_serverport && *request->hr_serverport ? 1 : 0);
   
         debug((httpd, DEBUG_FAT,          debug((httpd, DEBUG_FAT,
                 "%s: path `%s', cmd `%s', info `%s', "                  "bozo_process_cgi: path `%s', cmd `%s', info `%s', "
                 "query `%s', nph `%d', envpsize `%d'", __func__,                  "query `%s', nph `%d', envpsize `%d'",
                 path, command, strornull(info),                  path, command, strornull(info),
                 strornull(query), nph, envpsize));                  strornull(query), nph, envpsize));
   
Line 507  bozo_process_cgi(bozo_httpreq_t *request
Line 360  bozo_process_cgi(bozo_httpreq_t *request
         for (ix = 0; ix < envpsize; ix++)          for (ix = 0; ix < envpsize; ix++)
                 envp[ix] = NULL;                  envp[ix] = NULL;
         curenvp = envp;          curenvp = envp;
         lastenvp = envp + envpsize;  
   
         SIMPLEQ_FOREACH(headp, &request->hr_headers, h_next) {          SIMPLEQ_FOREACH(headp, &request->hr_headers, h_next) {
                 const char *s2;                  const char *s2;
Line 518  bozo_process_cgi(bozo_httpreq_t *request
Line 370  bozo_process_cgi(bozo_httpreq_t *request
                 strcpy(t, "HTTP_");                  strcpy(t, "HTTP_");
                 t += strlen(t);                  t += strlen(t);
                 for (s2 = headp->h_header; *s2; t++, s2++)                  for (s2 = headp->h_header; *s2; t++, s2++)
                         if (islower((unsigned)*s2))                          if (islower((u_int)*s2))
                                 *t = toupper((unsigned)*s2);                                  *t = toupper((u_int)*s2);
                         else if (*s2 == '-')                          else if (*s2 == '-')
                                 *t = '_';                                  *t = '_';
                         else                          else
Line 548  bozo_process_cgi(bozo_httpreq_t *request
Line 400  bozo_process_cgi(bozo_httpreq_t *request
         bozo_setenv(httpd, "REQUEST_URI", uri, curenvp++);          bozo_setenv(httpd, "REQUEST_URI", uri, curenvp++);
         bozo_setenv(httpd, "DATE_GMT", bozo_http_date(date, sizeof(date)),          bozo_setenv(httpd, "DATE_GMT", bozo_http_date(date, sizeof(date)),
                         curenvp++);                          curenvp++);
         /* RFC3875 section 4.1.7 says that QUERY_STRING MUST be defined. */  
         if (query && *query)          if (query && *query)
                 bozo_setenv(httpd, "QUERY_STRING", query, curenvp++);                  bozo_setenv(httpd, "QUERY_STRING", query, curenvp++);
         else  
                 bozo_setenv(httpd, "QUERY_STRING", "", curenvp++);  
         if (info && *info)          if (info && *info)
                 bozo_setenv(httpd, "PATH_INFO", info, curenvp++);                  bozo_setenv(httpd, "PATH_INFO", info, curenvp++);
         if (type && *type)          if (type && *type)
Line 576  bozo_process_cgi(bozo_httpreq_t *request
Line 425  bozo_process_cgi(bozo_httpreq_t *request
                 bozo_setenv(httpd, "REDIRECT_STATUS", "200", curenvp++);                  bozo_setenv(httpd, "REDIRECT_STATUS", "200", curenvp++);
         bozo_auth_cgi_setenv(request, &curenvp);          bozo_auth_cgi_setenv(request, &curenvp);
   
         debug((httpd, DEBUG_FAT, "%s: going exec %s with args:", __func__,          debug((httpd, DEBUG_FAT, "bozo_process_cgi: going exec %s, %s %s %s",
             path));              path, argv[0], strornull(argv[1]), strornull(argv[2])));
   
         for (i = 0; argv[i] != NULL; i++) {  
                 debug((httpd, DEBUG_FAT, "%s: argv[%zu] = `%s'", __func__,  
                     i, argv[i]));  
         }  
   
         if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sv) == -1)          if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sv) == -1)
                 bozoerr(httpd, 1, "child socketpair failed: %s",                  bozoerr(httpd, 1, "child socketpair failed: %s",
                                 strerror(errno));                                  strerror(errno));
   
         *curenvp = 0;  
         assert(lastenvp > curenvp);  
   
         /*          /*
          * We create 2 procs: one to become the CGI, one read from           * We create 2 procs: one to become the CGI, one read from
          * the CGI and output to the network, and this parent will           * the CGI and output to the network, and this parent will
Line 610  bozo_process_cgi(bozo_httpreq_t *request
Line 451  bozo_process_cgi(bozo_httpreq_t *request
                 closelog();                  closelog();
                 bozo_daemon_closefds(httpd);                  bozo_daemon_closefds(httpd);
   
                 if (-1 == execve(path, argv, envp)) {                  if (-1 == execve(path, argv, envp))
                         bozo_http_error(httpd, 404, request,  
                                 "Cannot execute CGI");  
                         bozoerr(httpd, 1, "child exec failed: %s: %s",                          bozoerr(httpd, 1, "child exec failed: %s: %s",
                               path, strerror(errno));                                path, strerror(errno));
                 }  
                 /* NOT REACHED */                  /* NOT REACHED */
                 bozoerr(httpd, 1, "child execve returned?!");                  bozoerr(httpd, 1, "child execve returned?!");
         }          }
Line 623  bozo_process_cgi(bozo_httpreq_t *request
Line 461  bozo_process_cgi(bozo_httpreq_t *request
         free(query);          free(query);
         free(file);          free(file);
         free(url);          free(url);
         for (i = 0; i < search_string_argc; i++)  
                 free(search_string_argv[i]);  
         free(search_string_argv);  
   
         close(sv[1]);          close(sv[1]);
   
Line 665  bozo_process_cgi(bozo_httpreq_t *request
Line 500  bozo_process_cgi(bozo_httpreq_t *request
         exit(0);          exit(0);
   
  out:   out:
   
         for (i = 0; i < search_string_argc; i++)  
                 free(search_string_argv[i]);  
         free(search_string_argv);  
         free(query);          free(query);
         free(file);          free(file);
         free(url);          free(url);

Legend:
Removed from v.1.25.2.2.2.8  
changed lines
  Added in v.1.25.2.3

CVSweb <webmaster@jp.NetBSD.org>