Newer
Older
session->req.keep_alive=FALSE;
session->req.send_location=NO_LOCATION;
SAFECOPY(error_code,message);
sprintf(session->req.physical_path,"%s%s.html",error_dir,error_code);
session->req.mime_type=get_mime_type(strrchr(session->req.physical_path,'.'));
send_headers(session,message);
if(!stat(session->req.physical_path,&sb)) {
int snt=0;
snt=sock_sendfile(session->socket,session->req.physical_path);
if(snt<0)
snt=0;
if(session->req.ld!=NULL)
session->req.ld->size=snt;
}
else {
lprintf(LOG_NOTICE,"%04d Error message file %s doesn't exist"
,session->socket,session->req.physical_path);
,"<HTML><HEAD><TITLE>%s Error</TITLE></HEAD>"
"<BODY><H1>%s Error</H1><BR><H3>In addition, "
"I can't seem to find the %s error file</H3><br>"
"please notify <a href=\"mailto:sysop@%s\">"
"%s</a></BODY></HTML>"
,error_code,error_code,error_code,scfg.sys_inetaddr,scfg.sys_op);
sockprint(session->socket,sbuf);
if(session->req.ld!=NULL)
session->req.ld->size=strlen(sbuf);
}
close_request(session);
}
static BOOL check_ars(http_session_t * session)
{
char *username;
char *password;
uchar *ar;
BOOL authorized;
if(session->req.auth[0]==0) {
if(startup->options&WEB_OPT_DEBUG_RX)
lprintf(LOG_NOTICE,"%04d !No authentication information",session->socket);
return(FALSE);
}
SAFECOPY(auth_req,session->req.auth);
username=strtok(auth_req,":");
if(username==NULL)
username="";
password=strtok(NULL,":");
/* Require a password */
if(password==NULL)
password="";
session->user.number=matchuser(&scfg, username, FALSE);
if(session->user.number==0) {
if(scfg.sys_misc&SM_ECHO_PW)
lprintf(LOG_NOTICE,"%04d !UNKNOWN USER: %s, Password: %s"
,session->socket,username,password);
else
lprintf(LOG_NOTICE,"%04d !UNKNOWN USER: %s"
,session->socket,username);
return(FALSE);
}
getuserdat(&scfg, &session->user);
if(session->user.pass[0] && stricmp(session->user.pass,password)) {
/* Should go to the hack log? */
if(scfg.sys_misc&SM_ECHO_PW)
lprintf(LOG_WARNING,"%04d !PASSWORD FAILURE for user %s: '%s' expected '%s'"
,session->socket,username,password,session->user.pass);
else
lprintf(LOG_WARNING,"%04d !PASSWORD FAILURE for user %s"
,session->socket,username);
session->user.number=0;
return(FALSE);
ar = arstr(NULL,session->req.ars,&scfg);
authorized=chk_ar(&scfg,ar,&session->user);
if(ar!=NULL && ar!=nular)
if(session->req.dynamic==IS_SSJS) {
if(!js_CreateUserObjects(session->js_cx, session->js_glob, &scfg, &session->user
,NULL /* ftp index file */, NULL /* subscan */))
lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user objects",session->socket);
if(session->req.dynamic==IS_CGI || session->req.dynamic==IS_STATIC) {
add_env(session,"AUTH_TYPE","Basic");
/* Should use real name if set to do so somewhere ToDo */
add_env(session,"REMOTE_USER",session->user.alias);
}
if(session->req.ld!=NULL)
session->req.ld->user=strdup(username);
SAFECOPY(session->username,username);
return(TRUE);
SAFECOPY(session->username,unknown);
/* Should go to the hack log? */
lprintf(LOG_WARNING,"%04d !AUTHORIZATION FAILURE for user %s, ARS: %s"
,session->socket,username,session->req.ars);
return(FALSE);
}
static BOOL read_mime_types(char* fname)
{
char str[1024];
char * ext;
char * type;
FILE* mime_config;
if((mime_config=fopen(fname,"r"))==NULL)
while (!feof(mime_config)&&mime_count<MAX_MIME_TYPES) {
if(fgets(str,sizeof(str),mime_config)!=NULL) {
truncsp(str);
ext=strtok(str," \t");
if(ext!=NULL) {
while(*ext && *ext<=' ') ext++;
if(*ext!=';') {
type=strtok(NULL," \t");
if(type!=NULL) {
while(*type && *type<=' ') type++;
if(strlen(ext)>0 && strlen(type)>0) {
SAFECOPY((mime_types[mime_count]).ext,ext);
SAFECOPY((mime_types[mime_count++]).type,type);
}
}
}
}
}
}
fclose(mime_config);
lprintf(LOG_DEBUG,"Loaded %d mime types", mime_count);
return(mime_count>0);
}
static int sockreadline(http_session_t * session, char *buf, size_t length)
{
char ch;
DWORD i;
BOOL rd;
if(!socket_check(session->socket,&rd,NULL,60000) || !rd || recv(session->socket, &ch, 1, 0)!=1) {
session->req.keep_alive=FALSE;
close_request(session);
session->socket=INVALID_SOCKET;
return(-1); /* time-out */
}
if(ch=='\n')
break;
if(i<length)
buf[i++]=ch;
}
/* Terminate at length if longer */
if(i>length)
i=length;
if(i>0 && buf[i-1]=='\r')
else
buf[i]=0;
if(startup->options&WEB_OPT_DEBUG_RX)
lprintf(LOG_DEBUG,"%04d RX: %s",session->socket,buf);
}
static int pipereadline(int pipe, char *buf, size_t length)
{
char ch;
DWORD i;
time_t start;
for(i=0;TRUE;) {
if(time(NULL)-start>startup->max_cgi_inactivity) {
return(-1);
}
if(read(pipe, &ch, 1)==1) {
if(ch=='\n')
break;
if(i<length)
buf[i++]=ch;
}
}
/* Terminate at length if longer */
if(i>length)
i=length;
if(i>0 && buf[i-1]=='\r')
else
buf[i]=0;
int recvbufsocket(int sock, char *buf, long count)
{
int rd=0;
if(count<1) {
errno=ERANGE;
return(0);
}
while(rd<count && socket_check(sock,NULL,NULL,60000)) {
if(i<=0) {
*buf=0;
return(0);
}
rd+=i;
start=time(NULL);
}
if(rd==count) {
return(rd);
}
*buf=0;
}
/* Wasn't this done up as a JS thing too? ToDo */
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
static void unescape(char *p)
{
char * dst;
char code[3];
dst=p;
for(;*p;p++) {
if(*p=='%' && isxdigit(*(p+1)) && isxdigit(*(p+2))) {
sprintf(code,"%.2s",p+1);
*(dst++)=(char)strtol(code,NULL,16);
p+=2;
}
else {
if(*p=='+') {
*(dst++)=' ';
}
else {
*(dst++)=*p;
}
}
}
*(dst)=0;
}
static void js_parse_post(http_session_t * session)
{
char *p;
char *key;
char *value;
JSString* js_str;
if(session->req.post_data == NULL)
return;
p=session->req.post_data;
while((key=strtok(p,"="))!=NULL) {
p=NULL;
if(key == NULL)
continue;
value=strtok(NULL,"&");
if(value == NULL)
continue;
unescape(value);
unescape(key);
if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL)
return;
JS_DefineProperty(session->js_cx, session->js_query, key, STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
}
}
static void js_add_header(http_session_t * session, char *key, char *value)
{
JSString* js_str;
if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL)
return;
JS_DefineProperty(session->js_cx, session->js_header, key, STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
}
static BOOL parse_headers(http_session_t * session)
{
char next_char[2];
char *value;
char *p;
int i;
size_t content_len=0;
while(sockreadline(session,req_line,sizeof(req_line)-1)>0) {
while((recvfrom(session->socket,next_char,1,MSG_PEEK,NULL,0)>0)
&& (next_char[0]=='\t' || next_char[0]==' ')) {
i=strlen(req_line);
sockreadline(session,req_line+i,sizeof(req_line)-i-1);
}
strtok(req_line,":");
if((value=strtok(NULL,""))!=NULL) {
i=get_header_type(req_line);
while(*value && *value<=' ') value++;
if(session->req.dynamic==IS_SSJS)
js_add_header(session,req_line,value);
switch(i) {
case HEAD_AUTH:
strtok(value," ");
p=strtok(NULL," ");
if(p==NULL)
break;
while(*p && *p<' ') p++;
b64_decode(session->req.auth,sizeof(session->req.auth),p,strlen(p));
break;
case HEAD_LENGTH:
if(session->req.dynamic==IS_CGI || session->req.dynamic==IS_STATIC)
add_env(session,"CONTENT_LENGTH",value);
break;
case HEAD_TYPE:
if(session->req.dynamic==IS_CGI || session->req.dynamic==IS_STATIC)
add_env(session,"CONTENT_TYPE",value);
break;
case HEAD_IFMODIFIED:
session->req.if_modified_since=decode_date(value);
break;
case HEAD_CONNECTION:
if(!stricmp(value,"Keep-Alive")) {
session->req.keep_alive=TRUE;
}
if(!stricmp(value,"Close")) {
session->req.keep_alive=FALSE;
}
break;
case HEAD_HOST:
if(session->req.host[0]==0) {
SAFECOPY(session->req.host,value);
if(startup->options&WEB_OPT_DEBUG_RX)
lprintf(LOG_INFO,"%04d Grabbing from virtual host: %s"
,session->socket,value);
break;
case HEAD_REFERER:
if(session->req.ld!=NULL)
session->req.ld->referrer=strdup(value);
break;
case HEAD_AGENT:
if(session->req.ld!=NULL)
session->req.ld->agent=strdup(value);
break;
default:
break;
}
if(session->req.dynamic==IS_CGI || session->req.dynamic==IS_STATIC) {
sprintf(env_name,"HTTP_%s",req_line);
add_env(session,env_name,value);
}
if(content_len) {
if((session->req.post_data=malloc(content_len+1)) != NULL) {
recvbufsocket(session->socket,session->req.post_data,content_len);
session->req.post_len=content_len;
if(session->req.dynamic==IS_SSJS) {
js_parse_post(session);
}
session->req.post_data[content_len]=0;
}
else {
lprintf(LOG_CRIT,"%04d !ERROR Allocating %d bytes of memory",session->socket,content_len);
if(session->req.dynamic==IS_CGI || session->req.dynamic==IS_STATIC)
add_env(session,"SERVER_NAME",session->req.host[0] ? session->req.host : startup->host_name );
return TRUE;
}
static int get_version(char *p)
{
int i;
if(p==NULL)
return(0);
while(*p && *p<' ') p++;
if(*p==0)
return(0);
for(i=1;http_vers[i]!=NULL;i++) {
if(!stricmp(p,http_vers[i])) {
return(i);
}
}
return(i-1);
}
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
static void js_parse_query(http_session_t * session, char *p) {
char *key;
char *value;
JSString* js_str;
while((key=strtok(p,"="))!=NULL) {
p=NULL;
if(key != NULL) {
value=strtok(NULL,"&");
if(value != NULL) {
unescape(value);
unescape(key);
if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL)
return;
JS_DefineProperty(session->js_cx, session->js_query, key, STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
}
}
}
}
static int is_dynamic_req(http_session_t* session)
{
char drive[4];
char dir[MAX_PATH+1];
char fname[MAX_PATH+1];
char ext[MAX_PATH+1];
char path[MAX_PATH+1];
_splitpath(session->req.physical_path, drive, dir, fname, ext);
if(!(startup->options&BBS_OPT_NO_JAVASCRIPT) && stricmp(ext,startup->ssjs_ext)==0) {
lprintf(LOG_INFO,"%04d Setting up JavaScript support", session->socket);
if(!js_setup(session)) {
lprintf(LOG_ERR,"%04d !ERROR setting up JavaScript support", session->socket);
return(IS_STATIC);
}
sprintf(path,"%s/SBBS_SSJS.%d.html",startup->cgi_temp_dir,session->socket);
if((session->req.fp=fopen(path,"w"))==NULL) {
lprintf(LOG_ERR,"%04d !ERROR %d opening/creating %s", session->socket, errno, path);
return(IS_STATIC);
}
return(IS_SSJS);
}
init_enviro(session);
if(!(startup->options&WEB_OPT_NO_CGI)) {
for(i=0; startup->cgi_ext!=NULL && startup->cgi_ext[i]!=NULL; i++) {
if(stricmp(ext,startup->cgi_ext[i])==0) {
return(IS_CGI);
}
}
/* It would be more secure if this was a true physical directory comparision */
sprintf(path,"/%s/",cgi_dir);
if(stricmp(dir,path)==0) {
return(IS_CGI);
}
}
return(IS_STATIC);
}
static char *get_request(http_session_t * session, char *req_line)
char* p;
char* retval;
SKIP_WHITESPACE(req_line);
SAFECOPY(session->req.virtual_path,req_line);
strtok(session->req.virtual_path," \t");
retval=strtok(NULL," \t");
strtok(session->req.virtual_path,"?");
query=strtok(NULL,"");
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
/* Must initialize physical_path before calling is_dynamic_req() */
SAFECOPY(session->req.physical_path,session->req.virtual_path);
unescape(session->req.physical_path);
if(!strnicmp(session->req.physical_path,http_scheme,http_scheme_len)) {
/* Set HOST value... ignore HOST header */
SAFECOPY(session->req.host,session->req.physical_path+http_scheme_len);
strtok(session->req.physical_path,"/");
p=strtok(NULL,"/");
if(p==NULL) {
/* Do not allow host values larger than 128 bytes */
session->req.host[0]=0;
p=session->req.physical_path+http_scheme_len;
}
offset=p-session->req.physical_path;
memmove(session->req.physical_path
,session->req.physical_path+offset
,strlen(session->req.physical_path+offset)+1 /* move '\0' terminator too */
);
}
session->req.dynamic=is_dynamic_req(session);
SAFECOPY(session->req.query_str,query);
if(query!=NULL) {
switch(session->req.dynamic) {
case IS_CGI:
add_env(session,"QUERY_STRING",query);
break;
case IS_SSJS:
break;
}
}
return(retval);
}
static char *get_method(http_session_t * session, char *req_line)
{
int i;
for(i=0;methods[i]!=NULL;i++) {
if(!strnicmp(req_line,methods[i],strlen(methods[i]))) {
session->req.method=i;
if(strlen(req_line)<strlen(methods[i])+2) {
send_error(session,"400 Bad Request");
return(NULL);
}
return(req_line+strlen(methods[i])+1);
}
}
if(req_line!=NULL && *req_line>=' ')
send_error(session,"501 Not Implemented");
return(NULL);
}
static BOOL get_req(http_session_t * session, char *request_line)
req_line[0]=0;
if(request_line == NULL) {
if(sockreadline(session,req_line,sizeof(req_line)-1)<0)
req_line[0]=0;
}
else {
lprintf(LOG_DEBUG,"%04d Handling Internal Redirect to: %s",session->socket,request_line);
SAFECOPY(req_line,request_line);
}
if(session->req.ld!=NULL)
session->req.ld->request=strdup(req_line);
if(req_line[0]) {
if(startup->options&WEB_OPT_DEBUG_RX)
lprintf(LOG_DEBUG,"%04d Got request line: %s",session->socket,req_line);
p=NULL;
p=get_method(session,req_line);
if(p!=NULL) {
p=get_request(session,p);
session->http_ver=get_version(p);
if(session->http_ver>=HTTP_1_1)
session->req.keep_alive=TRUE;
if(session->req.dynamic==IS_CGI || session->req.dynamic==IS_STATIC) {
add_env(session,"REQUEST_METHOD",methods[session->req.method]);
add_env(session,"SERVER_PROTOCOL",session->http_ver ?
http_vers[session->http_ver] : "HTTP/0.9");
close_request(session);
return FALSE;
}
/* This may exist somewhere else - ToDo */
static char *find_last_slash(char *str)
{
#ifdef _WIN32
char * LastFSlash;
char * LastBSlash;
LastFSlash=strrchr(str,'/');
LastBSlash=strrchr(str,'\\');
if(LastFSlash==NULL)
return(LastBSlash);
if(LastBSlash==NULL)
return(LastFSlash);
if(LastBSlash < LastFSlash)
return(LastFSlash);
return(LastBSlash);
#else
return(strrchr(str,'/'));
#endif
}
/* This may exist somewhere else - ToDo */
static char *find_first_slash(char *str)
{
#ifdef _WIN32
char * FirstFSlash;
char * FirstBSlash;
FirstFSlash=strchr(str,'/');
FirstBSlash=strchr(str,'\\');
if(FirstFSlash==NULL)
return(FirstBSlash);
if(FirstBSlash==NULL)
return(FirstFSlash);
if(FirstBSlash > FirstFSlash)
return(FirstFSlash);
return(FirstBSlash);
#else
return(strchr(str,'/'));
#endif
}
static BOOL check_extra_path(http_session_t * session, char *path)
{
char *p;
char rpath[MAX_PATH+1];
char vpath[MAX_PATH+1];
char epath[MAX_PATH+1];
char str[MAX_PATH+1];
struct stat sb;
epath[0]=0;
if(((stat(session->req.physical_path,&sb))==-1) /* && errno==ENOTDIR */)
{
SAFECOPY(vpath,session->req.virtual_path);
SAFECOPY(rpath,path);
while((p=find_last_slash(vpath))!=NULL)
{
*p=0;
if((p=find_last_slash(rpath))==NULL)
return(FALSE);
*p=0;
SAFECOPY(str,epath);
sprintf(epath,"/%s%s",(p+1),str);
if(stat(rpath,&sb)!=-1 && (!(sb.st_mode&S_IFDIR)))
{
SAFECOPY(session->req.extra_path_info,epath);
SAFECOPY(session->req.virtual_path,vpath);
/* This is dependent on the size of path in check_request() */
sprintf(path,"%.*s",MAX_PATH,rpath);
session->req.dynamic=IS_CGI;
return(TRUE);
}
}
}
return(FALSE);
}
static BOOL check_request(http_session_t * session)
{
char path[MAX_PATH+1];
char str[MAX_PATH+1];
char last_ch;
char* last_slash;
if(!(startup->options&WEB_OPT_VIRTUAL_HOSTS))
session->req.host[0]=0;
if(session->req.host[0]) {
sprintf(str,"%s/%s",root_dir,session->req.host);
if(isdir(str))
sprintf(str,"%s/%s%s",root_dir,session->req.host,session->req.physical_path);
sprintf(str,"%s%s",root_dir,session->req.physical_path);
if(FULLPATH(path,str,sizeof(session->req.physical_path))==NULL) {
return(FALSE);
}
lprintf(LOG_DEBUG,"%04d Path is: %s",session->socket,path);
if(isdir(path)) {
last_ch=*lastchar(path);
if(!IS_PATH_DELIM(last_ch)) {
last_ch=*lastchar(session->req.virtual_path);
if(!IS_PATH_DELIM(last_ch)) {
strcat(session->req.virtual_path,"/");
}
last_slash=find_last_slash(path);
last_slash++;
for(i=0; startup->index_file_name!=NULL && startup->index_file_name[i]!=NULL ;i++) {
*last_slash=0;
strcat(path,startup->index_file_name[i]);
lprintf(LOG_DEBUG,"%04d Checking for %s",session->socket,path);
if(startup->index_file_name[i] == NULL) {
return(FALSE);
}
strcat(session->req.virtual_path,startup->index_file_name[i]);
if(session->req.send_location != MOVED_PERM)
session->req.send_location=MOVED_STAT;
if(strnicmp(path,root_dir,strlen(root_dir))) {
session->req.keep_alive=FALSE;
send_error(session,"400 Bad Request");
lprintf(LOG_NOTICE,"%04d !ERROR Request for %s is outside of web root %s"
,session->socket,path,root_dir);
return(FALSE);
}
/* Check if sneaky CGI script */
if(!check_extra_path(session,path))
{
if(startup->options&WEB_OPT_DEBUG_TX)
lprintf(LOG_DEBUG,"%04d 404 - %s does not exist",session->socket,path);
send_error(session,error_404);
return(FALSE);
}
SAFECOPY(session->req.physical_path,path);
if(session->req.dynamic==IS_CGI) {
add_env(session,"SCRIPT_NAME",session->req.virtual_path);
}
SAFECOPY(str,session->req.virtual_path);
last_slash=find_last_slash(str);
if(last_slash!=NULL)
*(last_slash+1)=0;
if(session->req.dynamic==IS_CGI && *(session->req.extra_path_info))
{
sprintf(str,"%s%s",startup->root_dir,session->req.extra_path_info);
add_env(session,"PATH_TRANSLATED",str);
add_env(session,"PATH_INFO",session->req.extra_path_info);
}
/* Set default ARS to a 0-length string */
session->req.ars[0]=0;
/* Walk up from root_dir checking for access.ars */
SAFECOPY(str,path);
last_slash=str+strlen(root_dir)-1;
/* Loop while there's more /s in path*/
while((last_slash=find_first_slash(p+1))!=NULL) {
/* Terminate the path after the slash */
*(last_slash+1)=0;
strcat(str,"access.ars");
if(!strcmp(path,str)) {
send_error(session,"403 Forbidden");
return(FALSE);
}
/* Read access.ars file */
if((file=fopen(str,"r"))!=NULL) {
fgets(session->req.ars,sizeof(session->req.ars),file);
fclose(file);
}
else {
/* If cannot open access.ars, only allow sysop access */
SAFECOPY(session->req.ars,"LEVEL 90");
break;
}
/* Truncate at \r or \n - can use last_slash since I'm done with it.*/
truncsp(session->req.ars);
}
SAFECOPY(str,path);
}
if(session->req.ars[0]) {
if(!check_ars(session)) {
/* No authentication provided */
sprintf(str,"401 Unauthorized%s%s: Basic realm=\"%s\""
,newline,get_header(HEAD_WWWAUTH),scfg.sys_name);
send_error(session,str);
return(FALSE);
else
SAFECOPY(session->username,unknown);
return(TRUE);
}
static BOOL exec_cgi(http_session_t *session)
{
char cmdline[MAX_PATH+256];
#ifdef __unix__
/* ToDo: Damn, that's WAY too many variables */
int i=0;
int status=0;
pid_t child=0;
int in_pipe[2];
int out_pipe[2];
int err_pipe[2];
fd_set read_set;
fd_set write_set;
size_t post_offset=0;
BOOL done_parsing_headers=FALSE;
BOOL done_reading=FALSE;
char cgi_status[MAX_REQUEST_LINE+1];
char header[MAX_REQUEST_LINE+1];
char *directive=NULL;
char *value=NULL;
BOOL done_wait=FALSE;
BOOL got_valid_headers=FALSE;
time_t start;
char cgipath[MAX_PATH+1];
char *p;
SAFECOPY(cmdline,session->req.physical_path);
lprintf(LOG_INFO,"%04d Executing %s",session->socket,cmdline);
/* ToDo: Should only do this if the Content-Length header was NOT sent */
session->req.keep_alive=FALSE;
/* Set up I/O pipes */
if(pipe(in_pipe)!=0) {
lprintf(LOG_ERR,"%04d Can't create in_pipe",session->socket,buf);
return(FALSE);
}
if(pipe(out_pipe)!=0) {
lprintf(LOG_ERR,"%04d Can't create out_pipe",session->socket,buf);
return(FALSE);
}
if(pipe(err_pipe)!=0) {
lprintf(LOG_ERR,"%04d Can't create err_pipe",session->socket,buf);
return(FALSE);
}
if((child=fork())==0) {
/* Do a full suid thing. */
if(startup->setuid!=NULL)
startup->setuid(TRUE);
/* Set up environment */
while(session->req.cgi_env != NULL) {
putenv(session->req.cgi_env->val);
session->req.cgi_env=session->req.cgi_env->next;
}
/* Set up STDIO */
close(in_pipe[1]); /* close write-end of pipe */
dup2(in_pipe[0],0); /* redirect stdin */
close(in_pipe[0]); /* close excess file descriptor */
close(out_pipe[0]); /* close read-end of pipe */
dup2(out_pipe[1],1); /* stdout */
close(out_pipe[1]); /* close excess file descriptor */
close(err_pipe[0]); /* close read-end of pipe */
dup2(err_pipe[1],2); /* stderr */
close(err_pipe[1]); /* close excess file descriptor */
SAFECOPY(cgipath,cmdline);
if((p=strrchr(cgipath,'/'))!=NULL)
{
*p=0;
chdir(cgipath);
}
/* Execute command */
execl(cmdline,cmdline,NULL);
lprintf(LOG_ERR,"%04d !FAILED! execl()",session->socket);
exit(EXIT_FAILURE); /* Should never happen */
}
close(in_pipe[0]); /* close excess file descriptor */
close(out_pipe[1]); /* close excess file descriptor */
close(err_pipe[1]); /* close excess file descriptor */
if(child==0) {
close(in_pipe[1]); /* close write-end of pipe */
close(out_pipe[0]); /* close read-end of pipe */
close(err_pipe[0]); /* close read-end of pipe */
return(FALSE);
}
post_offset+=write(in_pipe[1],
session->req.post_data+post_offset,
session->req.post_len-post_offset);
high_fd=out_pipe[0];
if(err_pipe[0]>high_fd)
high_fd=err_pipe[0];
if(in_pipe[1]>high_fd)
high_fd=in_pipe[1];
if(session->socket>high_fd)
high_fd=session->socket;
/* ToDo: Magically set done_parsing_headers for nph-* scripts */
cgi_status[0]=0;
while(!done_reading) {
if(!done_wait)
done_wait = (waitpid(child,&status,WNOHANG)==child);
tv.tv_sec=startup->max_cgi_inactivity;
tv.tv_usec=0;
FD_ZERO(&read_set);
FD_SET(out_pipe[0],&read_set);
FD_SET(err_pipe[0],&read_set);
FD_SET(session->socket,&read_set);
FD_ZERO(&write_set);
if(post_offset < session->req.post_len)
FD_SET(in_pipe[1],&write_set);
if(!done_reading && (select(high_fd+1,&read_set,&write_set,NULL,&tv)>0)) {
if(FD_ISSET(session->socket,&read_set)) {
if(recv(session->socket,&ch,1,MSG_PEEK) < 1) /* Is there no data waiting? */
{
done_reading=TRUE;
}
}
if(FD_ISSET(in_pipe[1],&write_set)) {
if(post_offset < session->req.post_len) {
session->req.post_data+post_offset,
session->req.post_len-post_offset);
post_offset += i;
if(i<0)
done_reading=TRUE;
else if(post_offset>=session->req.post_len)
close(in_pipe[1]);
else if(i!=post_offset)
start=time(NULL);
}
if(FD_ISSET(out_pipe[0],&read_set)) {
if(done_parsing_headers && got_valid_headers) {
if(i>0) {
int snt=0;
start=time(NULL);
if(session->req.method!=HTTP_HEAD) {
snt=write(session->socket,buf,i);
if(session->req.ld!=NULL && snt>0) {
session->req.ld->size+=snt;
done_reading=TRUE;
}
else {
/* This is the tricky part */
i=pipereadline(out_pipe[0],buf,sizeof(buf));
if(i<0) {
done_reading=TRUE;
got_valid_headers=FALSE;
}
start=time(NULL);
if(!done_parsing_headers && *buf) {
SAFECOPY(header,buf);