httpd: move data off bss.

httpd: do not realpath() for SCRIPT_FILENAME - it resolves symlinks
but it should not:

-                /* SCRIPT_FILENAME required by PHP in CGI mode */
-               if (!realpath(purl + 1, realpath_buff))
-                       goto error_execing_cgi;
-               setenv1("SCRIPT_FILENAME", realpath_buff);
+
+               /* SCRIPT_FILENAME required by PHP in CGI mode */
+               fullpath = concat_path_file(home_httpd, purl);
+               setenv1("SCRIPT_FILENAME", fullpath);
This commit is contained in:
Denis Vlasenko 2007-06-09 23:49:05 +00:00
parent 66db264a5f
commit 77e44d60e6

View File

@ -98,10 +98,8 @@
# define PIPE_BUF 4096 # define PIPE_BUF 4096
#endif #endif
static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004";
static const char default_path_httpd_conf[] = "/etc"; static const char default_path_httpd_conf[] = "/etc";
static const char httpd_conf[] = "httpd.conf"; static const char httpd_conf[] = "httpd.conf";
static const char home[] = "./";
#define TIMEOUT 60 #define TIMEOUT 60
@ -122,55 +120,85 @@ typedef struct HT_ACCESS {
} Htaccess; } Htaccess;
typedef struct HT_ACCESS_IP { typedef struct HT_ACCESS_IP {
unsigned int ip; unsigned ip;
unsigned int mask; unsigned mask;
int allow_deny; int allow_deny;
struct HT_ACCESS_IP *next; struct HT_ACCESS_IP *next;
} Htaccess_IP; } Htaccess_IP;
typedef struct { struct globals {
char buf[MAX_MEMORY_BUFF]; int server_socket;
int accepted_socket;
volatile smallint alarm_signaled;
smallint flg_deny_all;
const char *g_query;
const char *configFile;
const char *home_httpd;
unsigned rmt_ip;
USE_FEATURE_HTTPD_BASIC_AUTH(const char *realm;) const char *found_mime_type;
const char *found_moved_temporarily;
off_t ContentLength; /* -1 - unknown */
time_t last_mod;
Htaccess_IP *ip_a_d; /* config allow/deny lines */
USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
const char *query;
USE_FEATURE_HTTPD_CGI(char *referer;) USE_FEATURE_HTTPD_CGI(char *referer;)
const char *configFile;
unsigned int rmt_ip;
#if ENABLE_FEATURE_HTTPD_CGI || DEBUG #if ENABLE_FEATURE_HTTPD_CGI || DEBUG
char *rmt_ip_str; /* for set env REMOTE_ADDR */ char *rmt_ip_str; /* for set env REMOTE_ADDR */
#endif #endif
unsigned port; /* server initial port and for unsigned tcp_port; /* server initial port and for
set env REMOTE_PORT */ set env REMOTE_PORT */
const char *found_mime_type;
const char *found_moved_temporarily;
off_t ContentLength; /* -1 - unknown */
time_t last_mod;
Htaccess_IP *ip_a_d; /* config allow/deny lines */
int flg_deny_all;
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
Htaccess *auth; /* config user:password lines */ Htaccess *g_auth; /* config user:password lines */
#endif #endif
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
Htaccess *mime_a; /* config mime types */ Htaccess *mime_a; /* config mime types */
#endif #endif
int server_socket;
int accepted_socket;
volatile int alarm_signaled;
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
Htaccess *script_i; /* config script interpreters */ Htaccess *script_i; /* config script interpreters */
#endif #endif
} HttpdConfig; char iobuf[MAX_MEMORY_BUFF];
};
static HttpdConfig *config; #define G (*ptr_to_globals)
#define server_socket (G.server_socket )
#define accepted_socket (G.accepted_socket)
#define alarm_signaled (G.alarm_signaled )
#define flg_deny_all (G.flg_deny_all )
#define g_query (G.g_query )
#define configFile (G.configFile )
#define home_httpd (G.home_httpd )
#define rmt_ip (G.rmt_ip )
#define found_mime_type (G.found_mime_type)
#define found_moved_temporarily (G.found_moved_temporarily)
#define ContentLength (G.ContentLength )
#define last_mod (G.last_mod )
#define ip_a_d (G.ip_a_d )
#define g_realm (G.g_realm )
#define remoteuser (G.remoteuser )
#define referer (G.referer )
#if ENABLE_FEATURE_HTTPD_CGI || DEBUG
#define rmt_ip_str (G.rmt_ip_str )
#endif
#define tcp_port (G.tcp_port )
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
#define g_auth (G.g_auth )
#endif
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
#define mime_a (G.mime_a )
#endif
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
#define script_i (G.script_i )
#endif
#define iobuf (G.iobuf )
#define INIT_G() do { \
PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
tcp_port = 80; \
ContentLength = -1; \
} while (0)
static const char request_GET[] = "GET"; /* size algorithmic optimize */ static const char request_GET[] = "GET"; /* size algorithmic optimize */
@ -264,7 +292,7 @@ static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT";
#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) #define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
static int scan_ip(const char **ep, unsigned int *ip, unsigned char endc) static int scan_ip(const char **ep, unsigned *ip, unsigned char endc)
{ {
const char *p = *ep; const char *p = *ep;
int auto_mask = 8; int auto_mask = 8;
@ -272,7 +300,7 @@ static int scan_ip(const char **ep, unsigned int *ip, unsigned char endc)
*ip = 0; *ip = 0;
for (j = 0; j < 4; j++) { for (j = 0; j < 4; j++) {
unsigned int octet; unsigned octet;
if ((*p < '0' || *p > '9') && (*p != '/' || j == 0) && *p != 0) if ((*p < '0' || *p > '9') && (*p != '/' || j == 0) && *p != 0)
return -auto_mask; return -auto_mask;
@ -301,10 +329,10 @@ static int scan_ip(const char **ep, unsigned int *ip, unsigned char endc)
return auto_mask; return auto_mask;
} }
static int scan_ip_mask(const char *ipm, unsigned int *ip, unsigned int *mask) static int scan_ip_mask(const char *ipm, unsigned *ip, unsigned *mask)
{ {
int i; int i;
unsigned int msk; unsigned msk;
i = scan_ip(&ipm, ip, '/'); i = scan_ip(&ipm, ip, '/');
if (i < 0) if (i < 0)
@ -397,13 +425,13 @@ static void parse_conf(const char *path, int flag)
Htaccess *cur; Htaccess *cur;
#endif #endif
const char *cf = config->configFile; const char *cf = configFile;
char buf[160]; char buf[160];
char *p0 = NULL; char *p0 = NULL;
char *c, *p; char *c, *p;
/* free previous ip setup if present */ /* free previous ip setup if present */
Htaccess_IP *pip = config->ip_a_d; Htaccess_IP *pip = ip_a_d;
while (pip) { while (pip) {
Htaccess_IP *cur_ipl = pip; Htaccess_IP *cur_ipl = pip;
@ -411,9 +439,9 @@ static void parse_conf(const char *path, int flag)
pip = cur_ipl->next; pip = cur_ipl->next;
free(cur_ipl); free(cur_ipl);
} }
config->ip_a_d = NULL; ip_a_d = NULL;
config->flg_deny_all = 0; flg_deny_all = 0;
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ #if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
|| ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
@ -421,13 +449,13 @@ static void parse_conf(const char *path, int flag)
/* retain previous auth and mime config only for subdir parse */ /* retain previous auth and mime config only for subdir parse */
if (flag != SUBDIR_PARSE) { if (flag != SUBDIR_PARSE) {
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
free_config_lines(&config->auth); free_config_lines(&g_auth);
#endif #endif
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
free_config_lines(&config->mime_a); free_config_lines(&mime_a);
#endif #endif
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
free_config_lines(&config->script_i); free_config_lines(&script_i);
#endif #endif
} }
#endif #endif
@ -447,16 +475,16 @@ static void parse_conf(const char *path, int flag)
/* config file not found, no changes to config */ /* config file not found, no changes to config */
return; return;
} }
if (config->configFile && flag == FIRST_PARSE) /* if -c option given */ if (configFile && flag == FIRST_PARSE) /* if -c option given */
bb_perror_msg_and_die("%s", cf); bb_perror_msg_and_die("%s", cf);
flag = FIND_FROM_HTTPD_ROOT; flag = FIND_FROM_HTTPD_ROOT;
cf = httpd_conf; cf = httpd_conf;
} }
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
prev = config->auth; prev = g_auth;
#endif #endif
/* This could stand some work */ /* This could stand some work */
while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) { while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) {
c = NULL; c = NULL;
for (p = p0; *p0 != 0 && *p0 != '#'; p0++) { for (p = p0; *p0 != 0 && *p0 != '#'; p0++) {
@ -477,7 +505,7 @@ static void parse_conf(const char *path, int flag)
if (*c == '*') { if (*c == '*') {
if (*p0 == 'D') { if (*p0 == 'D') {
/* memorize deny all */ /* memorize deny all */
config->flg_deny_all++; flg_deny_all = 1;
} }
/* skip default other "word:*" config lines */ /* skip default other "word:*" config lines */
continue; continue;
@ -509,14 +537,14 @@ static void parse_conf(const char *path, int flag)
pip->allow_deny = *p0; pip->allow_deny = *p0;
if (*p0 == 'D') { if (*p0 == 'D') {
/* Deny:form_IP move top */ /* Deny:form_IP move top */
pip->next = config->ip_a_d; pip->next = ip_a_d;
config->ip_a_d = pip; ip_a_d = pip;
} else { } else {
/* add to bottom A:form_IP config line */ /* add to bottom A:form_IP config line */
Htaccess_IP *prev_IP = config->ip_a_d; Htaccess_IP *prev_IP = ip_a_d;
if (prev_IP == NULL) { if (prev_IP == NULL) {
config->ip_a_d = pip; ip_a_d = pip;
} else { } else {
while (prev_IP->next) while (prev_IP->next)
prev_IP = prev_IP->next; prev_IP = prev_IP->next;
@ -579,16 +607,16 @@ static void parse_conf(const char *path, int flag)
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
if (*cf == '.') { if (*cf == '.') {
/* config .mime line move top for overwrite previous */ /* config .mime line move top for overwrite previous */
cur->next = config->mime_a; cur->next = mime_a;
config->mime_a = cur; mime_a = cur;
continue; continue;
} }
#endif #endif
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
if (*cf == '*' && cf[1] == '.') { if (*cf == '*' && cf[1] == '.') {
/* config script interpreter line move top for overwrite previous */ /* config script interpreter line move top for overwrite previous */
cur->next = config->script_i; cur->next = script_i;
config->script_i = cur; script_i = cur;
continue; continue;
} }
#endif #endif
@ -596,10 +624,10 @@ static void parse_conf(const char *path, int flag)
free(p0); free(p0);
if (prev == NULL) { if (prev == NULL) {
/* first line */ /* first line */
config->auth = prev = cur; g_auth = prev = cur;
} else { } else {
/* sort path, if current lenght eq or bigger then move up */ /* sort path, if current lenght eq or bigger then move up */
Htaccess *prev_hti = config->auth; Htaccess *prev_hti = g_auth;
size_t l = strlen(cf); size_t l = strlen(cf);
Htaccess *hti; Htaccess *hti;
@ -611,7 +639,7 @@ static void parse_conf(const char *path, int flag)
prev_hti->next = cur; prev_hti->next = cur;
} else { } else {
/* insert as top */ /* insert as top */
config->auth = cur; g_auth = cur;
} }
break; break;
} }
@ -818,7 +846,7 @@ static int openServer(void)
int fd; int fd;
/* create the socket right now */ /* create the socket right now */
fd = create_and_bind_stream_or_die(NULL, config->port); fd = create_and_bind_stream_or_die(NULL, tcp_port);
xlisten(fd, 9); xlisten(fd, 9);
return fd; return fd;
} }
@ -840,7 +868,7 @@ static int openServer(void)
****************************************************************************/ ****************************************************************************/
static int sendHeaders(HttpResponseNum responseNum) static int sendHeaders(HttpResponseNum responseNum)
{ {
char *buf = config->buf; char *buf = iobuf;
const char *responseString = ""; const char *responseString = "";
const char *infoString = 0; const char *infoString = 0;
const char *mime_type; const char *mime_type;
@ -861,7 +889,7 @@ static int sendHeaders(HttpResponseNum responseNum)
} }
/* error message is HTML */ /* error message is HTML */
mime_type = responseNum == HTTP_OK ? mime_type = responseNum == HTTP_OK ?
config->found_mime_type : "text/html"; found_mime_type : "text/html";
/* emit the current date */ /* emit the current date */
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer)); strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer));
@ -874,20 +902,20 @@ static int sendHeaders(HttpResponseNum responseNum)
if (responseNum == HTTP_UNAUTHORIZED) { if (responseNum == HTTP_UNAUTHORIZED) {
len += sprintf(buf+len, len += sprintf(buf+len,
"WWW-Authenticate: Basic realm=\"%s\"\r\n", "WWW-Authenticate: Basic realm=\"%s\"\r\n",
config->realm); g_realm);
} }
#endif #endif
if (responseNum == HTTP_MOVED_TEMPORARILY) { if (responseNum == HTTP_MOVED_TEMPORARILY) {
len += sprintf(buf+len, "Location: %s/%s%s\r\n", len += sprintf(buf+len, "Location: %s/%s%s\r\n",
config->found_moved_temporarily, found_moved_temporarily,
(config->query ? "?" : ""), (g_query ? "?" : ""),
(config->query ? config->query : "")); (g_query ? g_query : ""));
} }
if (config->ContentLength != -1) { /* file */ if (ContentLength != -1) { /* file */
strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod)); strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&last_mod));
len += sprintf(buf+len, "Last-Modified: %s\r\n%s %"OFF_FMT"d\r\n", len += sprintf(buf+len, "Last-Modified: %s\r\n%s %"OFF_FMT"d\r\n",
timeStr, "Content-length:", config->ContentLength); timeStr, "Content-length:", ContentLength);
} }
strcat(buf, "\r\n"); strcat(buf, "\r\n");
len += 2; len += 2;
@ -900,7 +928,7 @@ static int sendHeaders(HttpResponseNum responseNum)
} }
if (DEBUG) if (DEBUG)
fprintf(stderr, "headers: '%s'\n", buf); fprintf(stderr, "headers: '%s'\n", buf);
i = config->accepted_socket; i = accepted_socket;
if (i == 0) i++; /* write to fd# 1 in inetd mode */ if (i == 0) i++; /* write to fd# 1 in inetd mode */
return full_write(i, buf, len); return full_write(i, buf, len);
} }
@ -919,9 +947,9 @@ static int sendHeaders(HttpResponseNum responseNum)
static int getLine(void) static int getLine(void)
{ {
int count = 0; int count = 0;
char *buf = config->buf; char *buf = iobuf;
while (read(config->accepted_socket, buf + count, 1) == 1) { while (read(accepted_socket, buf + count, 1) == 1) {
if (buf[count] == '\r') continue; if (buf[count] == '\r') continue;
if (buf[count] == '\n') { if (buf[count] == '\n') {
buf[count] = 0; buf[count] = 0;
@ -962,8 +990,8 @@ static int sendCgi(const char *url,
{ {
int fromCgi[2]; /* pipe for reading data from CGI */ int fromCgi[2]; /* pipe for reading data from CGI */
int toCgi[2]; /* pipe for sending data to CGI */ int toCgi[2]; /* pipe for sending data to CGI */
char *fullpath;
static char * argp[] = { 0, 0 }; char *argp[] = { NULL, NULL };
int pid = 0; int pid = 0;
int inFd; int inFd;
int outFd; int outFd;
@ -985,7 +1013,14 @@ static int sendCgi(const char *url,
* since httpd is run from inetd (and it can't run standalone * since httpd is run from inetd (and it can't run standalone
* in uClinux). * in uClinux).
*/ */
// FIXME: setenv leaks memory! (old values of env vars are leaked)
// Thus we have a bug on NOMMU.
// Need to use this instead:
// [malloc +] putenv + (in child: exec) + (in parent: unsetenv [+ free])
#if !BB_MMU #if !BB_MMU
fullpath = NULL;
pid = vfork(); pid = vfork();
#else #else
pid = fork(); pid = fork();
@ -997,25 +1032,19 @@ static int sendCgi(const char *url,
/* child process */ /* child process */
char *script; char *script;
char *purl; char *purl;
char realpath_buff[MAXPATHLEN];
if (config->accepted_socket > 1) if (accepted_socket > 1)
close(config->accepted_socket); close(accepted_socket);
if (config->server_socket > 1) if (server_socket > 1)
close(config->server_socket); close(server_socket);
dup2(toCgi[0], 0); // replace stdin with the pipe xmove_fd(toCgi[0], 0); /* replace stdin with the pipe */
dup2(fromCgi[1], 1); // replace stdout with the pipe xmove_fd(fromCgi[1], 1); /* replace stdout with the pipe */
/* Huh? User seeing stderr can be a security problem...
* and if CGI really wants that, it can always dup2(1,2)...
if (!DEBUG)
dup2(fromCgi[1], 2); // replace stderr with the pipe
*/
/* I think we cannot inadvertently close 0, 1 here... */
close(toCgi[0]);
close(toCgi[1]);
close(fromCgi[0]); close(fromCgi[0]);
close(fromCgi[1]); close(fromCgi[1]);
/* Huh? User seeing stderr can be a security problem...
* and if CGI really wants that, it can always dup2(1,2)...
* dup2(fromCgi[1], 2); */
/* /*
* Find PATH_INFO. * Find PATH_INFO.
@ -1036,22 +1065,21 @@ static int sendCgi(const char *url,
*script = '/'; /* is directory, find next '/' */ *script = '/'; /* is directory, find next '/' */
} }
setenv1("PATH_INFO", script); /* set /PATH_INFO or "" */ setenv1("PATH_INFO", script); /* set /PATH_INFO or "" */
/* setenv1("PATH", getenv("PATH")); redundant */
setenv1("REQUEST_METHOD", request); setenv1("REQUEST_METHOD", request);
if (config->query) { if (g_query) {
char *uri = alloca(strlen(purl) + 2 + strlen(config->query)); char *uri = alloca(strlen(purl) + 2 + strlen(g_query));
if (uri) if (uri)
sprintf(uri, "%s?%s", purl, config->query); sprintf(uri, "%s?%s", purl, g_query);
setenv1("REQUEST_URI", uri); setenv1("REQUEST_URI", uri);
} else { } else {
setenv1("REQUEST_URI", purl); setenv1("REQUEST_URI", purl);
} }
if (script != NULL) if (script != NULL)
*script = '\0'; /* cut off /PATH_INFO */ *script = '\0'; /* cut off /PATH_INFO */
/* SCRIPT_FILENAME required by PHP in CGI mode */
if (!realpath(purl + 1, realpath_buff)) /* SCRIPT_FILENAME required by PHP in CGI mode */
goto error_execing_cgi; fullpath = concat_path_file(home_httpd, purl);
setenv1("SCRIPT_FILENAME", realpath_buff); setenv1("SCRIPT_FILENAME", fullpath);
/* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
setenv1("SCRIPT_NAME", purl); setenv1("SCRIPT_NAME", purl);
/* http://hoohoo.ncsa.uiuc.edu/cgi/env.html: /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html:
@ -1061,8 +1089,8 @@ static int sendCgi(const char *url,
* should always be set when there is query information, * should always be set when there is query information,
* regardless of command line decoding. */ * regardless of command line decoding. */
/* (Older versions of bbox seem to do some decoding) */ /* (Older versions of bbox seem to do some decoding) */
setenv1("QUERY_STRING", config->query); setenv1("QUERY_STRING", g_query);
setenv1("SERVER_SOFTWARE", httpdVersion); putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER);
putenv((char*)"SERVER_PROTOCOL=HTTP/1.0"); putenv((char*)"SERVER_PROTOCOL=HTTP/1.0");
putenv((char*)"GATEWAY_INTERFACE=CGI/1.1"); putenv((char*)"GATEWAY_INTERFACE=CGI/1.1");
/* Having _separate_ variables for IP and port defeats /* Having _separate_ variables for IP and port defeats
@ -1071,15 +1099,16 @@ static int sendCgi(const char *url,
* IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense. * IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense.
* Oh well... */ * Oh well... */
{ {
char *p = config->rmt_ip_str ? : (char*)""; char *p = rmt_ip_str ? : (char*)"";
char *cp = strrchr(p, ':'); char *cp = strrchr(p, ':');
if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']')) if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']'))
cp = NULL; cp = NULL;
if (cp) *cp = '\0'; /* delete :PORT */ if (cp) *cp = '\0'; /* delete :PORT */
setenv1("REMOTE_ADDR", p); setenv1("REMOTE_ADDR", p);
if (cp) *cp = ':';
} }
#if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV #if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
setenv_long("REMOTE_PORT", config->port); setenv_long("REMOTE_PORT", tcp_port);
#endif #endif
if (bodyLen) if (bodyLen)
setenv_long("CONTENT_LENGTH", bodyLen); setenv_long("CONTENT_LENGTH", bodyLen);
@ -1088,22 +1117,22 @@ static int sendCgi(const char *url,
if (content_type) if (content_type)
setenv1("CONTENT_TYPE", content_type); setenv1("CONTENT_TYPE", content_type);
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
if (config->remoteuser) { if (remoteuser) {
setenv1("REMOTE_USER", config->remoteuser); setenv1("REMOTE_USER", remoteuser);
putenv((char*)"AUTH_TYPE=Basic"); putenv((char*)"AUTH_TYPE=Basic");
} }
#endif #endif
if (config->referer) if (referer)
setenv1("HTTP_REFERER", config->referer); setenv1("HTTP_REFERER", referer);
/* set execve argp[0] without path */ /* set execve argp[0] without path */
argp[0] = strrchr(purl, '/') + 1; argp[0] = strrchr(purl, '/') + 1;
/* but script argp[0] must have absolute path and chdiring to this */ /* but script argp[0] must have absolute path and chdiring to this */
script = strrchr(realpath_buff, '/'); script = strrchr(fullpath, '/');
if (!script) if (!script)
goto error_execing_cgi; goto error_execing_cgi;
*script = '\0'; *script = '\0';
if (chdir(realpath_buff) == 0) { if (chdir(fullpath) == 0) {
// Now run the program. If it fails, // Now run the program. If it fails,
// use _exit() so no destructors // use _exit() so no destructors
// get called and make a mess. // get called and make a mess.
@ -1113,7 +1142,7 @@ static int sendCgi(const char *url,
if (suffix) { if (suffix) {
Htaccess *cur; Htaccess *cur;
for (cur = config->script_i; cur; cur = cur->next) { for (cur = script_i; cur; cur = cur->next) {
if (strcmp(cur->before_colon + 1, suffix) == 0) { if (strcmp(cur->before_colon + 1, suffix) == 0) {
interpr = cur->after_colon; interpr = cur->after_colon;
break; break;
@ -1127,16 +1156,19 @@ static int sendCgi(const char *url,
execv(interpr, argp); execv(interpr, argp);
else else
#endif #endif
execv(realpath_buff, argp); execv(fullpath, argp);
} }
error_execing_cgi: error_execing_cgi:
/* send to stdout (even if we are not from inetd) */ /* send to stdout (even if we are not from inetd) */
config->accepted_socket = 1; accepted_socket = 1;
sendHeaders(HTTP_NOT_FOUND); sendHeaders(HTTP_NOT_FOUND);
_exit(242); _exit(242);
} /* end child */ } /* end child */
/* parent process */ /* parent process */
#if !BB_MMU
free(fullpath);
#endif
buf_count = 0; buf_count = 0;
post_read_size = 0; post_read_size = 0;
@ -1161,9 +1193,9 @@ static int sendCgi(const char *url,
FD_SET(outFd, &writeSet); FD_SET(outFd, &writeSet);
nfound = outFd > inFd ? outFd : inFd; nfound = outFd > inFd ? outFd : inFd;
if (post_read_size == 0) { if (post_read_size == 0) {
FD_SET(config->accepted_socket, &readSet); FD_SET(accepted_socket, &readSet);
if (nfound < config->accepted_socket) if (nfound < accepted_socket)
nfound = config->accepted_socket; nfound = accepted_socket;
} }
/* Now wait on the set of sockets! */ /* Now wait on the set of sockets! */
nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL); nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL);
@ -1201,13 +1233,13 @@ static int sendCgi(const char *url,
post_read_size = bodyLen = 0; /* broken pipe to CGI */ post_read_size = bodyLen = 0; /* broken pipe to CGI */
} }
} else if (bodyLen > 0 && post_read_size == 0 } else if (bodyLen > 0 && post_read_size == 0
&& FD_ISSET(config->accepted_socket, &readSet) && FD_ISSET(accepted_socket, &readSet)
) { ) {
/* We expect data, prev data portion is eaten by CGI /* We expect data, prev data portion is eaten by CGI
* and there *is* data to read from the peer * and there *is* data to read from the peer
* (POSTDATA?) */ * (POSTDATA?) */
count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen; count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen;
count = safe_read(config->accepted_socket, wbuf, count); count = safe_read(accepted_socket, wbuf, count);
if (count > 0) { if (count > 0) {
post_read_size = count; post_read_size = count;
post_read_idx = 0; post_read_idx = 0;
@ -1223,8 +1255,8 @@ static int sendCgi(const char *url,
#endif #endif
if (FD_ISSET(inFd, &readSet)) { if (FD_ISSET(inFd, &readSet)) {
/* There is something to read from CGI */ /* There is something to read from CGI */
int s = config->accepted_socket; int s = accepted_socket;
char *rbuf = config->buf; char *rbuf = iobuf;
/* Are we still buffering CGI output? */ /* Are we still buffering CGI output? */
if (buf_count >= 0) { if (buf_count >= 0) {
@ -1306,14 +1338,14 @@ static int sendFile(const char *url)
break; break;
} }
/* also, if not found, set default as "application/octet-stream"; */ /* also, if not found, set default as "application/octet-stream"; */
config->found_mime_type = table[1]; found_mime_type = table[1];
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
if (suffix) { if (suffix) {
Htaccess * cur; Htaccess * cur;
for (cur = config->mime_a; cur; cur = cur->next) { for (cur = mime_a; cur; cur = cur->next) {
if (strcmp(cur->before_colon, suffix) == 0) { if (strcmp(cur->before_colon, suffix) == 0) {
config->found_mime_type = cur->after_colon; found_mime_type = cur->after_colon;
break; break;
} }
} }
@ -1322,17 +1354,17 @@ static int sendFile(const char *url)
if (DEBUG) if (DEBUG)
fprintf(stderr, "sending file '%s' content-type: %s\n", fprintf(stderr, "sending file '%s' content-type: %s\n",
url, config->found_mime_type); url, found_mime_type);
f = open(url, O_RDONLY); f = open(url, O_RDONLY);
if (f >= 0) { if (f >= 0) {
int count; int count;
char *buf = config->buf; char *buf = iobuf;
sendHeaders(HTTP_OK); sendHeaders(HTTP_OK);
/* TODO: sendfile() */ /* TODO: sendfile() */
while ((count = full_read(f, buf, MAX_MEMORY_BUFF)) > 0) { while ((count = full_read(f, buf, MAX_MEMORY_BUFF)) > 0) {
int fd = config->accepted_socket; int fd = accepted_socket;
if (fd == 0) fd++; /* write to fd# 1 in inetd mode */ if (fd == 0) fd++; /* write to fd# 1 in inetd mode */
if (full_write(fd, buf, count) != count) if (full_write(fd, buf, count) != count)
break; break;
@ -1352,9 +1384,9 @@ static int checkPermIP(void)
Htaccess_IP * cur; Htaccess_IP * cur;
/* This could stand some work */ /* This could stand some work */
for (cur = config->ip_a_d; cur; cur = cur->next) { for (cur = ip_a_d; cur; cur = cur->next) {
#if ENABLE_FEATURE_HTTPD_CGI && DEBUG #if ENABLE_FEATURE_HTTPD_CGI && DEBUG
fprintf(stderr, "checkPermIP: '%s' ? ", config->rmt_ip_str); fprintf(stderr, "checkPermIP: '%s' ? ", rmt_ip_str);
#endif #endif
#if DEBUG #if DEBUG
fprintf(stderr, "'%u.%u.%u.%u/%u.%u.%u.%u'\n", fprintf(stderr, "'%u.%u.%u.%u/%u.%u.%u.%u'\n",
@ -1368,12 +1400,12 @@ static int checkPermIP(void)
(unsigned char)(cur->mask) (unsigned char)(cur->mask)
); );
#endif #endif
if ((config->rmt_ip & cur->mask) == cur->ip) if ((rmt_ip & cur->mask) == cur->ip)
return cur->allow_deny == 'A'; /* Allow/Deny */ return cur->allow_deny == 'A'; /* Allow/Deny */
} }
/* if unconfigured, return 1 - access from all */ /* if unconfigured, return 1 - access from all */
return !config->flg_deny_all; return !flg_deny_all;
} }
/**************************************************************************** /****************************************************************************
@ -1403,7 +1435,7 @@ static int checkPerm(const char *path, const char *request)
const char *prev = NULL; const char *prev = NULL;
/* This could stand some work */ /* This could stand some work */
for (cur = config->auth; cur; cur = cur->next) { for (cur = g_auth; cur; cur = cur->next) {
size_t l; size_t l;
p0 = cur->before_colon; p0 = cur->before_colon;
@ -1449,9 +1481,9 @@ static int checkPerm(const char *path, const char *request)
if (strcmp(p, request) == 0) { if (strcmp(p, request) == 0) {
set_remoteuser_var: set_remoteuser_var:
config->remoteuser = strdup(request); remoteuser = strdup(request);
if (config->remoteuser) if (remoteuser)
config->remoteuser[(u - request)] = 0; remoteuser[(u - request)] = 0;
return 1; /* Ok */ return 1; /* Ok */
} }
/* unauthorized */ /* unauthorized */
@ -1474,7 +1506,7 @@ set_remoteuser_var:
static void handle_sigalrm(int sig) static void handle_sigalrm(int sig)
{ {
sendHeaders(HTTP_REQUEST_TIMEOUT); sendHeaders(HTTP_REQUEST_TIMEOUT);
config->alarm_signaled = sig; alarm_signaled = 1;
} }
/**************************************************************************** /****************************************************************************
@ -1486,7 +1518,7 @@ static void handle_sigalrm(int sig)
****************************************************************************/ ****************************************************************************/
static void handleIncoming(void) static void handleIncoming(void)
{ {
char *buf = config->buf; char *buf = iobuf;
char *url; char *url;
char *purl; char *purl;
int blank = -1; int blank = -1;
@ -1556,10 +1588,10 @@ static void handleIncoming(void)
strcpy(url, buf); strcpy(url, buf);
/* extract url args if present */ /* extract url args if present */
test = strchr(url, '?'); test = strchr(url, '?');
config->query = NULL; g_query = NULL;
if (test) { if (test) {
*test++ = '\0'; *test++ = '\0';
config->query = test; g_query = test;
} }
test = decodeString(url, 0); test = decodeString(url, 0);
@ -1605,11 +1637,11 @@ static void handleIncoming(void)
/* If URL is directory, adding '/' */ /* If URL is directory, adding '/' */
if (test[-1] != '/') { if (test[-1] != '/') {
if (is_directory(url + 1, 1, &sb)) { if (is_directory(url + 1, 1, &sb)) {
config->found_moved_temporarily = url; found_moved_temporarily = url;
} }
} }
if (DEBUG) if (DEBUG)
fprintf(stderr, "url='%s', args=%s\n", url, config->query); fprintf(stderr, "url='%s', args=%s\n", url, g_query);
test = url; test = url;
ip_allowed = checkPermIP(); ip_allowed = checkPermIP();
@ -1656,7 +1688,7 @@ static void handleIncoming(void)
} else if ((STRNCASECMP(buf, "Content-Type:") == 0)) { } else if ((STRNCASECMP(buf, "Content-Type:") == 0)) {
content_type = strdup(skip_whitespace(buf + sizeof("Content-Type:")-1)); content_type = strdup(skip_whitespace(buf + sizeof("Content-Type:")-1));
} else if ((STRNCASECMP(buf, "Referer:") == 0)) { } else if ((STRNCASECMP(buf, "Referer:") == 0)) {
config->referer = strdup(skip_whitespace(buf + sizeof("Referer:")-1)); referer = strdup(skip_whitespace(buf + sizeof("Referer:")-1));
} }
#endif #endif
@ -1679,7 +1711,7 @@ static void handleIncoming(void)
} /* while extra header reading */ } /* while extra header reading */
} }
alarm(0); alarm(0);
if (config->alarm_signaled) if (alarm_signaled)
break; break;
if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || ip_allowed == 0) { if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || ip_allowed == 0) {
@ -1698,10 +1730,10 @@ static void handleIncoming(void)
} }
#endif #endif
if (config->found_moved_temporarily) { if (found_moved_temporarily) {
sendHeaders(HTTP_MOVED_TEMPORARILY); sendHeaders(HTTP_MOVED_TEMPORARILY);
/* clear unforked memory flag */ /* clear unforked memory flag */
config->found_moved_temporarily = NULL; found_moved_temporarily = NULL;
break; break;
} }
@ -1719,7 +1751,7 @@ static void handleIncoming(void)
char *suffix = strrchr(test, '.'); char *suffix = strrchr(test, '.');
if (suffix) { if (suffix) {
Htaccess *cur; Htaccess *cur;
for (cur = config->script_i; cur; cur = cur->next) { for (cur = script_i; cur; cur = cur->next) {
if (strcmp(cur->before_colon + 1, suffix) == 0) { if (strcmp(cur->before_colon + 1, suffix) == 0) {
sendCgi(url, prequest, length, cookie, content_type); sendCgi(url, prequest, length, cookie, content_type);
goto bail_out; goto bail_out;
@ -1737,8 +1769,8 @@ static void handleIncoming(void)
strcpy(purl, "index.html"); strcpy(purl, "index.html");
if (stat(test, &sb) == 0) { if (stat(test, &sb) == 0) {
/* It's a dir URL and there is index.html */ /* It's a dir URL and there is index.html */
config->ContentLength = sb.st_size; ContentLength = sb.st_size;
config->last_mod = sb.st_mtime; last_mod = sb.st_mtime;
} }
#if ENABLE_FEATURE_HTTPD_CGI #if ENABLE_FEATURE_HTTPD_CGI
else if (purl[-1] == '/') { else if (purl[-1] == '/') {
@ -1746,14 +1778,14 @@ static void handleIncoming(void)
* Try cgi-bin/index.cgi */ * Try cgi-bin/index.cgi */
if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
purl[0] = '\0'; purl[0] = '\0';
config->query = url; g_query = url;
sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type); sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
break; break;
} }
} }
#endif /* FEATURE_HTTPD_CGI */ #endif /* FEATURE_HTTPD_CGI */
sendFile(test); sendFile(test);
config->ContentLength = -1; ContentLength = -1;
} while (0); } while (0);
#if ENABLE_FEATURE_HTTPD_CGI #if ENABLE_FEATURE_HTTPD_CGI
@ -1765,28 +1797,28 @@ static void handleIncoming(void)
#if ENABLE_FEATURE_HTTPD_CGI #if ENABLE_FEATURE_HTTPD_CGI
free(cookie); free(cookie);
free(content_type); free(content_type);
free(config->referer); free(referer);
config->referer = NULL; referer = NULL;
# if ENABLE_FEATURE_HTTPD_BASIC_AUTH # if ENABLE_FEATURE_HTTPD_BASIC_AUTH
free(config->remoteuser); free(remoteuser);
config->remoteuser = NULL; remoteuser = NULL;
# endif # endif
#endif #endif
shutdown(config->accepted_socket, SHUT_WR); shutdown(accepted_socket, SHUT_WR);
/* Properly wait for remote to closed */ /* Properly wait for remote to closed */
FD_ZERO(&s_fd); FD_ZERO(&s_fd);
FD_SET(config->accepted_socket, &s_fd); FD_SET(accepted_socket, &s_fd);
do { do {
tv.tv_sec = 2; tv.tv_sec = 2;
tv.tv_usec = 0; tv.tv_usec = 0;
retval = select(config->accepted_socket + 1, &s_fd, NULL, NULL, &tv); retval = select(accepted_socket + 1, &s_fd, NULL, NULL, &tv);
} while (retval > 0 && read(config->accepted_socket, buf, sizeof(config->buf) > 0)); } while (retval > 0 && read(accepted_socket, buf, sizeof(iobuf) > 0));
shutdown(config->accepted_socket, SHUT_RD); shutdown(accepted_socket, SHUT_RD);
/* In inetd case, we close fd 1 (stdout) here. We will exit soon anyway */ /* In inetd case, we close fd 1 (stdout) here. We will exit soon anyway */
close(config->accepted_socket); close(accepted_socket);
} }
/**************************************************************************** /****************************************************************************
@ -1830,24 +1862,24 @@ static int miniHttpd(int server)
s = accept(server, &fromAddr.sa, &fromAddrLen); s = accept(server, &fromAddr.sa, &fromAddrLen);
if (s < 0) if (s < 0)
continue; continue;
config->accepted_socket = s; accepted_socket = s;
config->rmt_ip = 0; rmt_ip = 0;
config->port = 0; tcp_port = 0;
#if ENABLE_FEATURE_HTTPD_CGI || DEBUG #if ENABLE_FEATURE_HTTPD_CGI || DEBUG
free(config->rmt_ip_str); free(rmt_ip_str);
config->rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen); rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen);
#if DEBUG #if DEBUG
bb_error_msg("connection from '%s'", config->rmt_ip_str); bb_error_msg("connection from '%s'", rmt_ip_str);
#endif #endif
#endif /* FEATURE_HTTPD_CGI */ #endif /* FEATURE_HTTPD_CGI */
if (fromAddr.sa.sa_family == AF_INET) { if (fromAddr.sa.sa_family == AF_INET) {
config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
config->port = ntohs(fromAddr.sin.sin_port); tcp_port = ntohs(fromAddr.sin.sin_port);
} }
#if ENABLE_FEATURE_IPV6 #if ENABLE_FEATURE_IPV6
if (fromAddr.sa.sa_family == AF_INET6) { if (fromAddr.sa.sa_family == AF_INET6) {
//config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); //rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
config->port = ntohs(fromAddr.sin6.sin6_port); tcp_port = ntohs(fromAddr.sin6.sin6_port);
} }
#endif #endif
@ -1880,20 +1912,20 @@ static int miniHttpd_inetd(void)
socklen_t fromAddrLen = sizeof(fromAddr); socklen_t fromAddrLen = sizeof(fromAddr);
getpeername(0, &fromAddr.sa, &fromAddrLen); getpeername(0, &fromAddr.sa, &fromAddrLen);
config->rmt_ip = 0; rmt_ip = 0;
config->port = 0; tcp_port = 0;
#if ENABLE_FEATURE_HTTPD_CGI || DEBUG #if ENABLE_FEATURE_HTTPD_CGI || DEBUG
free(config->rmt_ip_str); free(rmt_ip_str);
config->rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen); rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen);
#endif #endif
if (fromAddr.sa.sa_family == AF_INET) { if (fromAddr.sa.sa_family == AF_INET) {
config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
config->port = ntohs(fromAddr.sin.sin_port); tcp_port = ntohs(fromAddr.sin.sin_port);
} }
#if ENABLE_FEATURE_IPV6 #if ENABLE_FEATURE_IPV6
if (fromAddr.sa.sa_family == AF_INET6) { if (fromAddr.sa.sa_family == AF_INET6) {
//config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); //rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
config->port = ntohs(fromAddr.sin6.sin6_port); tcp_port = ntohs(fromAddr.sin6.sin6_port);
} }
#endif #endif
handleIncoming(); handleIncoming();
@ -1942,7 +1974,6 @@ int httpd_main(int argc, char **argv);
int httpd_main(int argc, char **argv) int httpd_main(int argc, char **argv)
{ {
unsigned opt; unsigned opt;
const char *home_httpd = home;
char *url_for_decode; char *url_for_decode;
USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;) USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
const char *s_port; const char *s_port;
@ -1955,22 +1986,20 @@ int httpd_main(int argc, char **argv)
setlocale(LC_TIME, "C"); setlocale(LC_TIME, "C");
#endif #endif
config = xzalloc(sizeof(*config)); INIT_G();
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH home_httpd = xrealloc_getcwd_or_warn(NULL);
config->realm = "Web Server Authentication"; /* We do not "absolutize" path given by -h (home) opt.
#endif * If user gives relative path in -h, $SCRIPT_FILENAME can end up
config->port = 80; * relative too. */
config->ContentLength = -1;
opt = getopt32(argc, argv, "c:d:h:" opt = getopt32(argc, argv, "c:d:h:"
USE_FEATURE_HTTPD_ENCODE_URL_STR("e:") USE_FEATURE_HTTPD_ENCODE_URL_STR("e:")
USE_FEATURE_HTTPD_BASIC_AUTH("r:") USE_FEATURE_HTTPD_BASIC_AUTH("r:")
USE_FEATURE_HTTPD_AUTH_MD5("m:") USE_FEATURE_HTTPD_AUTH_MD5("m:")
USE_FEATURE_HTTPD_SETUID("u:") USE_FEATURE_HTTPD_SETUID("u:")
"p:if", "p:if",
&(config->configFile), &url_for_decode, &home_httpd &(configFile), &url_for_decode, &home_httpd
USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
USE_FEATURE_HTTPD_BASIC_AUTH(, &(config->realm)) USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
USE_FEATURE_HTTPD_AUTH_MD5(, &pass) USE_FEATURE_HTTPD_AUTH_MD5(, &pass)
USE_FEATURE_HTTPD_SETUID(, &s_ugid) USE_FEATURE_HTTPD_SETUID(, &s_ugid)
, &s_port , &s_port
@ -1992,7 +2021,7 @@ int httpd_main(int argc, char **argv)
} }
#endif #endif
if (opt & OPT_PORT) if (opt & OPT_PORT)
config->port = xatou16(s_port); tcp_port = xatou16(s_port);
#if ENABLE_FEATURE_HTTPD_SETUID #if ENABLE_FEATURE_HTTPD_SETUID
if (opt & OPT_SETUID) { if (opt & OPT_SETUID) {
@ -2005,7 +2034,7 @@ int httpd_main(int argc, char **argv)
xchdir(home_httpd); xchdir(home_httpd);
if (!(opt & OPT_INETD)) { if (!(opt & OPT_INETD)) {
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);
config->server_socket = openServer(); server_socket = openServer();
#if ENABLE_FEATURE_HTTPD_SETUID #if ENABLE_FEATURE_HTTPD_SETUID
/* drop privileges */ /* drop privileges */
if (opt & OPT_SETUID) { if (opt & OPT_SETUID) {
@ -2022,12 +2051,12 @@ int httpd_main(int argc, char **argv)
#if ENABLE_FEATURE_HTTPD_CGI #if ENABLE_FEATURE_HTTPD_CGI
{ {
char *p = getenv("PATH"); char *p = getenv("PATH");
p = xstrdup(p); /* if gets NULL, returns NULL */ /* env strings themself are not freed, no need to strdup(p): */
clearenv(); clearenv();
if (p) if (p)
setenv1("PATH", p); putenv(p - 5);
if (!(opt & OPT_INETD)) if (!(opt & OPT_INETD))
setenv_long("SERVER_PORT", config->port); setenv_long("SERVER_PORT", tcp_port);
} }
#endif #endif
@ -2042,5 +2071,5 @@ int httpd_main(int argc, char **argv)
if (!(opt & OPT_FOREGROUND)) if (!(opt & OPT_FOREGROUND))
bb_daemonize(0); /* don't change current directory */ bb_daemonize(0); /* don't change current directory */
return miniHttpd(config->server_socket); return miniHttpd(server_socket);
} }