version 1.1.1.2, 2008/03/03 22:03:05 |
version 1.1.1.3, 2009/04/18 07:09:27 |
|
|
/* $eterna: cgi-bozo.c,v 1.18 2008/03/03 03:36:11 mrg Exp $ */ |
/* $eterna: cgi-bozo.c,v 1.28 2009/04/18 05:36:04 mrg Exp $ */ |
|
|
/* |
/* |
* Copyright (c) 1997-2008 Matthew R. Green |
* Copyright (c) 1997-2009 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 |
|
|
* notice, this list of conditions and the following disclaimer and |
* notice, this list of conditions and the following disclaimer and |
* dedication in the documentation and/or other materials provided |
* dedication in the documentation and/or other materials provided |
* with the distribution. |
* with the distribution. |
* 3. The name of the author may not be used to endorse or promote products |
|
* derived from this software without specific prior written permission. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
Line 58 static int Cflag; /* added a cgi handle |
|
Line 56 static int Cflag; /* added a cgi handle |
|
static const char * content_cgihandler(http_req *, const char *); |
static const char * content_cgihandler(http_req *, const char *); |
static void finish_cgi_output(http_req *request, int, int); |
static void finish_cgi_output(http_req *request, int, int); |
static int parse_header(const char *, ssize_t, char **, char **); |
static int parse_header(const char *, ssize_t, char **, char **); |
|
static void append_index_html(char **); |
|
|
void |
void |
set_cgibin(char *path) |
set_cgibin(char *path) |
Line 82 spsetenv(const char *env, const char *va |
|
Line 81 spsetenv(const char *env, const char *va |
|
/* |
/* |
* Checks if the request has asked for a cgi-bin. Should only be called if |
* Checks if the request has asked for a cgi-bin. Should only be called if |
* cgibin is set. If it starts CGIBIN_PREFIX or has a ncontent handler, |
* cgibin is set. If it starts CGIBIN_PREFIX or has a ncontent handler, |
* process the cgi, otherwise just return. |
* process the cgi, otherwise just return. Returns 0 if it did not handle |
|
* the request. |
*/ |
*/ |
void |
int |
process_cgi(http_req *request) |
process_cgi(http_req *request) |
{ |
{ |
char buf[WRSZ]; |
char buf[WRSZ]; |
struct headers *headp; |
struct headers *headp; |
const char *type, *clen, *info, *cgihandler; |
const char *type, *clen, *info, *cgihandler; |
char *query, *s, *t, *path, *env, *command, *url; |
char *query, *s, *t, *path, *env, *command, *file, *url; |
char **envp, **curenvp, *argv[4]; |
char **envp, **curenvp, *argv[4]; |
size_t len; |
size_t len; |
ssize_t rbytes; |
ssize_t rbytes; |
Line 99 process_cgi(http_req *request) |
|
Line 99 process_cgi(http_req *request) |
|
int sv[2]; |
int sv[2]; |
|
|
if (!cgibin && !Cflag) |
if (!cgibin && !Cflag) |
return; |
return 0; |
|
|
debug((DEBUG_NORMAL, "process_cgi: url `%s'", request->hr_url)); |
|
|
|
url = bozostrdup(request->hr_url); |
asprintf(&file, "/%s", request->hr_file); |
if ((s = strchr(url, '?')) != NULL) { |
if (file == NULL) |
*s++ = '\0'; |
return 0; |
query = s; |
if (request->hr_query && strlen(request->hr_query)) |
} else |
query = bozostrdup(request->hr_query); |
|
else |
query = NULL; |
query = NULL; |
|
|
|
asprintf(&url, "%s%s%s", file, query ? "?" : "", query ? query : ""); |
|
if (url == NULL) |
|
goto out; |
|
debug((DEBUG_NORMAL, "process_cgi: url `%s'", url)); |
|
|
path = NULL; |
path = NULL; |
envp = NULL; |
envp = NULL; |
cgihandler = NULL; |
cgihandler = NULL; |
Line 116 process_cgi(http_req *request) |
|
Line 121 process_cgi(http_req *request) |
|
info = NULL; |
info = NULL; |
|
|
len = strlen(url); |
len = strlen(url); |
if (len == 0 || url[len - 1] == '/') { /* append index.html */ |
|
debug((DEBUG_FAT, "appending index.html")); |
|
url = bozorealloc(url, len + strlen(index_html) + 1); |
|
strcat(url, index_html); |
|
debug((DEBUG_NORMAL, "process_cgi: url adjusted to `%s'", url)); |
|
} |
|
|
|
auth_check(request, url + 1); |
if (auth_check(request, url + 1)) |
|
goto out; |
|
|
if (!cgibin || strncmp(url + 1, CGIBIN_PREFIX, CGIBIN_PREFIX_LEN) != 0) { |
if (!cgibin || strncmp(url + 1, CGIBIN_PREFIX, CGIBIN_PREFIX_LEN) != 0) { |
cgihandler = content_cgihandler(request, url + 1); |
cgihandler = content_cgihandler(request, file + 1); |
if (cgihandler == NULL) { |
if (cgihandler == NULL) { |
free(url); |
debug((DEBUG_FAT, "process_cgi: no handler, returning")); |
return; |
goto out; |
} |
} |
|
if (len == 0 || file[len - 1] == '/') |
|
append_index_html(&file); |
debug((DEBUG_NORMAL, "process_cgi: cgihandler `%s'", |
debug((DEBUG_NORMAL, "process_cgi: cgihandler `%s'", |
cgihandler)); |
cgihandler)); |
} |
} else if (len - 1 == CGIBIN_PREFIX_LEN) /* url is "/cgi-bin/" */ |
|
append_index_html(&file); |
|
|
ix = 0; |
ix = 0; |
if (cgihandler) { |
if (cgihandler) { |
command = url + 1; |
command = file + 1; |
path = bozostrdup(cgihandler); |
path = bozostrdup(cgihandler); |
argv[ix++] = path; |
argv[ix++] = path; |
/* argv[] = [ path, command, query, NULL ] */ |
/* argv[] = [ path, command, query, NULL ] */ |
} else { |
} else { |
command = url + CGIBIN_PREFIX_LEN + 1; |
command = file + CGIBIN_PREFIX_LEN + 1; |
if ((s = strchr(command, '/')) != NULL) { |
if ((s = strchr(command, '/')) != NULL) { |
info = bozostrdup(s); |
info = bozostrdup(s); |
*s = '\0'; |
*s = '\0'; |
Line 213 process_cgi(http_req *request) |
|
Line 216 process_cgi(http_req *request) |
|
spsetenv("GATEWAY_INTERFACE", "CGI/1.1", curenvp++); |
spsetenv("GATEWAY_INTERFACE", "CGI/1.1", curenvp++); |
spsetenv("SERVER_PROTOCOL", request->hr_proto, curenvp++); |
spsetenv("SERVER_PROTOCOL", request->hr_proto, curenvp++); |
spsetenv("REQUEST_METHOD", request->hr_methodstr, curenvp++); |
spsetenv("REQUEST_METHOD", request->hr_methodstr, curenvp++); |
spsetenv("SCRIPT_NAME", url, curenvp++); |
spsetenv("SCRIPT_NAME", file, curenvp++); |
spsetenv("SCRIPT_FILENAME", url + 1, curenvp++); |
spsetenv("SCRIPT_FILENAME", file + 1, curenvp++); |
spsetenv("SERVER_SOFTWARE", server_software, curenvp++); |
spsetenv("SERVER_SOFTWARE", server_software, curenvp++); |
spsetenv("REQUEST_URI", request->hr_url, curenvp++); |
spsetenv("REQUEST_URI", request->hr_file, curenvp++); |
spsetenv("DATE_GMT", http_date(), curenvp++); |
spsetenv("DATE_GMT", http_date(), curenvp++); |
if (query && *query) |
if (query && *query) |
spsetenv("QUERY_STRING", query, curenvp++); |
spsetenv("QUERY_STRING", query, curenvp++); |
Line 234 process_cgi(http_req *request) |
|
Line 237 process_cgi(http_req *request) |
|
spsetenv("REMOTE_ADDR", request->hr_remoteaddr, curenvp++); |
spsetenv("REMOTE_ADDR", request->hr_remoteaddr, curenvp++); |
auth_cgi_setenv(request, &curenvp); |
auth_cgi_setenv(request, &curenvp); |
|
|
|
free(file); |
|
free(url); |
|
|
debug((DEBUG_FAT, "process_cgi: going exec %s, %s %s %s", |
debug((DEBUG_FAT, "process_cgi: going exec %s, %s %s %s", |
path, argv[0], strornull(argv[1]), strornull(argv[2]))); |
path, argv[0], strornull(argv[1]), strornull(argv[2]))); |
|
|
Line 295 process_cgi(http_req *request) |
|
Line 301 process_cgi(http_req *request) |
|
} |
} |
debug((DEBUG_FAT, "done processing cgi input")); |
debug((DEBUG_FAT, "done processing cgi input")); |
exit(0); |
exit(0); |
|
|
|
out: |
|
if (query) |
|
free(query); |
|
if (file) |
|
free(file); |
|
if (url) |
|
free(url); |
|
return 0; |
} |
} |
|
|
/* |
/* |
Line 309 finish_cgi_output(http_req *request, int |
|
Line 324 finish_cgi_output(http_req *request, int |
|
ssize_t len; |
ssize_t len; |
ssize_t rbytes; |
ssize_t rbytes; |
SIMPLEQ_HEAD(, headers) headers; |
SIMPLEQ_HEAD(, headers) headers; |
struct headers *hdr; |
struct headers *hdr, *nhdr; |
int write_header, nheaders = 0; |
int write_header, nheaders = 0; |
|
|
/* much of this code is like read_request()'s header loop. hmmm... */ |
/* much of this code is like read_request()'s header loop. hmmm... */ |
SIMPLEQ_INIT(&headers); |
SIMPLEQ_INIT(&headers); |
write_header = nph == 0; |
write_header = nph == 0; |
while (nph == 0 && (str = bozodgetln(in, &len, read)) != NULL) { |
while (nph == 0 && (str = bozodgetln(in, &len, read)) != NULL) { |
char * hdr_name, * hdr_value; |
char *hdr_name, *hdr_value; |
|
|
if (parse_header(str, len, &hdr_name, &hdr_value)) |
if (parse_header(str, len, &hdr_name, &hdr_value)) |
break; |
break; |
Line 358 finish_cgi_output(http_req *request, int |
|
Line 373 finish_cgi_output(http_req *request, int |
|
if (nheaders) { |
if (nheaders) { |
debug((DEBUG_OBESE, "process_cgi: writing delayed HTTP " |
debug((DEBUG_OBESE, "process_cgi: writing delayed HTTP " |
"headers ..")); |
"headers ..")); |
SIMPLEQ_FOREACH(hdr, &headers, h_next) { |
SIMPLEQ_FOREACH_SAFE(hdr, &headers, h_next, nhdr) { |
bozoprintf("%s: %s\r\n", hdr->h_header, hdr->h_value); |
bozoprintf("%s: %s\r\n", hdr->h_header, hdr->h_value); |
free(hdr->h_header); |
free(hdr->h_header); |
free(hdr); |
free(hdr); |
Line 386 finish_cgi_output(http_req *request, int |
|
Line 401 finish_cgi_output(http_req *request, int |
|
} |
} |
|
|
static int |
static int |
parse_header(const char * str, ssize_t len, char ** hdr_str, char ** hdr_val) |
parse_header(const char *str, ssize_t len, char **hdr_str, char **hdr_val) |
{ |
{ |
char * name, * value; |
char *name, *value; |
|
|
/* if the string passed is zero-length bail out */ |
/* if the string passed is zero-length bail out */ |
if (*str == '\0') |
if (*str == '\0') |
return -1; |
return -1; |
|
|
name = value = bozostrdup(str); |
value = bozostrdup(str); |
|
|
/* locate the ':' separator in the header/value */ |
/* locate the ':' separator in the header/value */ |
name = bozostrnsep(&value, ":", &len); |
name = bozostrnsep(&value, ":", &len); |
Line 422 content_cgihandler(http_req *request, co |
|
Line 437 content_cgihandler(http_req *request, co |
|
{ |
{ |
struct content_map *map; |
struct content_map *map; |
|
|
|
debug((DEBUG_FAT, "content_cgihandler: trying file %s", file)); |
map = match_content_map(file, 0); |
map = match_content_map(file, 0); |
if (map) |
if (map) |
return (map->cgihandler); |
return (map->cgihandler); |
return (NULL); |
return (NULL); |
} |
} |
|
|
|
static void |
|
append_index_html(char **url) |
|
{ |
|
*url = bozorealloc(*url, strlen(*url) + strlen(index_html) + 1); |
|
strcat(*url, index_html); |
|
debug((DEBUG_NORMAL, "append_index_html: url adjusted to `%s'", *url)); |
|
} |
|
|
#ifndef NO_DYNAMIC_CONTENT |
#ifndef NO_DYNAMIC_CONTENT |
/* cgi maps are simple ".postfix /path/to/prog" */ |
/* cgi maps are simple ".postfix /path/to/prog" */ |
void |
void |