/* * http_script: keeps all script-related ramblings together. * * Compliant to CGI/1.0 spec * * Rob McCool * */ #include "httpd.h" char **create_argv(char *av0, char *args, FILE *out) { register int x,n; char **av; char w[MAX_STRING_LEN]; char l[MAX_STRING_LEN]; for(x=0,n=2;args[x];x++) if(args[x] == '+') ++n; if(!(av = (char **)malloc((n+1)*sizeof(char *)))) die(NO_MEMORY,"create_argv",out); av[0] = av0; strcpy(l,args); for(x=1;xst_mode)) { strcpy(path_args,&path[strlen(t)]); strcpy(path,t); return; } } } for(x=dirs_in_alias - 1;x;--x) { make_dirstr(path,x+1,t); if(!(stat(t,finfo))) { if(S_ISREG(finfo->st_mode)) { strcpy(path_args,&path[strlen(t)]); strcpy(path,t); return; } } } unmunge_name(path); die(NOT_FOUND,path,out); } #define MAX_CGI_VARS 18 void exec_cgi_script(char *method, char *path, char *args, int in, FILE *out) { int pid, p[2]; int content, nph; char cl[MAX_STRING_LEN],t[MAX_STRING_LEN],t2[MAX_STRING_LEN]; char path_args[MAX_STRING_LEN]; char *argv0,**env; FILE *psin; struct stat finfo; register int n,x; get_path_info(path,path_args,out,&finfo); if(!can_exec(&finfo)) { unmunge_name(path); die(FORBIDDEN,path,out); } /* BAD -- method specific */ evaluate_access(path,&finfo,((!strcmp(method,"POST")) ? M_POST : M_GET), &allow,&allow_options,out); if(!allow) { log_reason("client denied by server configuration",path); unmunge_name(path); die(FORBIDDEN,path,out); } if(!(env = (char **)malloc((MAX_CGI_VARS + 2) * sizeof(char *)))) die(NO_MEMORY,"exec_cgi_script",out); n = 0; env[n++] = make_env_str("PATH",getenv("PATH"),out); env[n++] = make_env_str("SERVER_SOFTWARE",SERVER_VERSION,out); env[n++] = make_env_str("SERVER_NAME",server_hostname,out); env[n++] = make_env_str("GATEWAY_INTERFACE","CGI/1.0",out); sprintf(t,"%d",port); env[n++] = make_env_str("SERVER_PORT",t,out); env[n++] = make_env_str("SERVER_PROTOCOL", (assbackwards ? "HTTP/0.9" : "HTTP/1.0"),out); env[n++] = make_env_str("REQUEST_METHOD",method,out); env[n++] = make_env_str("HTTP_ACCEPT",http_accept,out); if(path_args[0]) { env[n++] = make_env_str("PATH_INFO",path_args,out); strcpy(t2,path_args); translate_name(t2,out); env[n++] = make_env_str("PATH_TRANSLATED",t2,out); } strcpy(t,path); unmunge_name(t); env[n++] = make_env_str("SCRIPT_NAME",t,out); env[n++] = make_env_str("QUERY_STRING",args,out); env[n++] = make_env_str("REMOTE_HOST",remote_name,out); env[n++] = make_env_str("REMOTE_ADDR",remote_ip,out); if(user[0]) env[n++] = make_env_str("REMOTE_USER",user,out); if(auth_type) env[n++] = make_env_str("AUTH_TYPE",auth_type,out); if(do_rfc931) env[n++] = make_env_str("REMOTE_IDENT",remote_logname,out); content=0; if((!strcmp(method,"POST")) || (!strcmp(method,"PUT"))) { content=1; sprintf(cl,"%d",content_length); env[n++] = make_env_str("CONTENT_TYPE",content_type,out); env[n++] = make_env_str("CONTENT_LENGTH",cl,out); } env[n] = NULL; if((argv0 = strrchr(path,'/')) != NULL) argv0++; else argv0 = path; if(pipe(p) < 0) die(SERVER_ERROR,"httpd: could not create IPC pipe",out); if((pid = fork()) < 0) die(SERVER_ERROR,"httpd: could not fork new process",out); nph = (strncmp(argv0,"nph-",4) ? 0 : 1); if(!pid) { if(content) if(in != STDIN_FILENO) { dup2(in,STDIN_FILENO); close(in); } if(nph) { if(fileno(out) != STDOUT_FILENO) { dup2(fileno(out),STDOUT_FILENO); fclose(out); } } else { if(p[1] != STDOUT_FILENO) { dup2(p[1],STDOUT_FILENO); close(p[1]); } } /* Only ISINDEX scripts get decoded arguments. */ if((!args[0]) || (ind(args,'=') >= 0)) { if(execle(path,argv0,(char *)0,env) == -1) { fprintf(stderr,"httpd: exec of %s failed, errno is %d\n", path,errno); exit(1); } } else { if(execve(path,create_argv(argv0,args,out),env) == -1) { fprintf(stderr,"httpd: exec of %s failed, errno is %d\n", path,errno); exit(1); } } } else { for(x=0;x