home *** CD-ROM | disk | FTP | other *** search
- /*
- * http_script: keeps all script-related ramblings together.
- *
- * Compliant to CGI/1.0 spec
- *
- * Rob McCool
- *
- */
-
- #include "httpd.h"
-
- int pid;
-
- void kill_children() {
- char errstr[MAX_STRING_LEN];
- sprintf(errstr,"killing CGI process %d",pid);
- log_error_noclose(errstr);
-
- kill(pid,SIGTERM);
- sleep(3); /* give them time to clean up */
- kill(pid,SIGKILL);
- waitpid(pid,NULL,0);
- }
-
- char **create_argv(char *av0, char *args, FILE *out) {
- register int x,n;
- char **av;
- char w[HUGE_STRING_LEN];
- char l[HUGE_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;x<n;x++) {
- getword(w,l,'+');
- unescape_url(w);
- escape_shell_cmd(w);
- if(!(av[x] = strdup(w)))
- die(NO_MEMORY,"create_argv",out);
- }
- av[n] = NULL;
- return av;
- }
-
- void get_path_info(char *path, char *path_args, FILE *out,
- struct stat *finfo)
- {
- register int x,max;
- char t[HUGE_STRING_LEN];
-
- path_args[0] = '\0';
- max=count_dirs(path);
- for(x=dirs_in_alias;x<=max;x++) {
- make_dirstr(path,x+1,t);
- if(!(stat(t,finfo))) {
- if(S_ISREG(finfo->st_mode)) {
- int l=strlen(t);
- strcpy(path_args,&path[l]);
- path[l] = '\0';
- 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_COMMON_VARS 9
- #define MAX_CGI_VARS (MAX_COMMON_VARS+9)
-
- char **add_cgi_vars(char **env,
- char *method, char *path, char *path_args, char *args,
- int *content,
- FILE *out)
- {
- int x;
- char t[HUGE_STRING_LEN],t2[HUGE_STRING_LEN];
-
- if(!(env = new_env(env,MAX_CGI_VARS,&x)))
- die(NO_MEMORY,"add_cgi_vars",out);
-
- env[x++] = make_env_str("GATEWAY_INTERFACE","CGI/1.1",out);
-
- env[x++] = make_env_str("SERVER_PROTOCOL",
- (assbackwards ? "HTTP/0.9" : "HTTP/1.0"),out);
- env[x++] = make_env_str("REQUEST_METHOD",method,out);
-
- strcpy(t,path);
- unmunge_name(t);
- env[x++] = make_env_str("SCRIPT_NAME",t,out);
- if(path_args[0]) {
- env[x++] = make_env_str("PATH_INFO",path_args,out);
- strcpy(t2,path_args);
- translate_name(t2,out);
- env[x++] = make_env_str("PATH_TRANSLATED",t2,out);
- }
- env[x++] = make_env_str("QUERY_STRING",args,out);
-
- if(content) {
- *content=0;
- if((!strcmp(method,"POST")) || (!strcmp(method,"PUT"))) {
- *content=1;
- sprintf(t,"%d",content_length);
- env[x++] = make_env_str("CONTENT_TYPE",content_type,out);
- env[x++] = make_env_str("CONTENT_LENGTH",t,out);
- }
- }
- env[x] = NULL;
- return env;
- }
-
- char **add_common_vars(char **env,FILE *out) {
- char t[HUGE_STRING_LEN],*env_path;
- int x;
-
- if(!(env = new_env(env,MAX_COMMON_VARS,&x)))
- die(NO_MEMORY,"add_common_vars",out);
-
- if(!(env_path = getenv("PATH")))
- env_path=DEFAULT_PATH;
- env[x++] = make_env_str("PATH",env_path,out);
- env[x++] = make_env_str("SERVER_SOFTWARE",SERVER_VERSION,out);
- env[x++] = make_env_str("SERVER_NAME",server_hostname,out);
- sprintf(t,"%d",port);
- env[x++] = make_env_str("SERVER_PORT",t,out);
- env[x++] = make_env_str("REMOTE_HOST",remote_name,out);
- env[x++] = make_env_str("REMOTE_ADDR",remote_ip,out);
- if(user[0])
- env[x++] = make_env_str("REMOTE_USER",user,out);
- if(auth_type)
- env[x++] = make_env_str("AUTH_TYPE",auth_type,out);
- if(do_rfc931)
- env[x++] = make_env_str("REMOTE_IDENT",remote_logname,out);
- env[x] = NULL;
- return env;
- }
-
- int cgi_stub(char *method, char *path, char *path_args, char *args,
- char **env, struct stat *finfo, int in, FILE *out)
- {
- int p[2];
- int content, nph;
- char *argv0;
- FILE *psin;
- register int x;
-
- if(!can_exec(finfo)) {
- unmunge_name(path);
- die(FORBIDDEN,path,out);
- }
-
- if((argv0 = strrchr(path,'/')) != NULL)
- argv0++;
- else argv0 = path;
-
- chdir_file(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) {
- close(p[0]);
- env = add_cgi_vars(env,method,path,path_args,args,&content,out);
- 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]);
- }
- }
- error_log2stderr();
- /* 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 {
- close(p[1]);
- }
-
- if(!nph) {
- if(!(psin = fdopen(p[0],"r")))
- die(SERVER_ERROR,"could not read from script",out);
-
- if(scan_script_header(psin,out)) {
- kill_children(); /* !!! */
- return REDIRECT_URL;
- }
-
- if(location[0] == '/') {
- char t[HUGE_STRING_LEN],a[HUGE_STRING_LEN],*argp;
-
- a[0] = '\0';
- fclose(psin);
- waitpid(pid,NULL,0);
- strcpy(t,location);
- if(argp = strchr(t,'?')) {
- *argp++ = '\0';
- strcpy(a,argp);
- }
- init_header_vars(); /* clear in_header_env and location */
- process_get(in,out,"GET",t,a);
- return 0;
- }
- content_length = -1;
- if(!assbackwards)
- send_http_header(out);
- if(!header_only)
- send_fd(psin,out,kill_children);
- else
- kill_children();
- fclose(psin);
- }
- else bytes_sent = -1;
- waitpid(pid,NULL,0);
- return 0;
- }
-
- /* Called for ScriptAliased directories */
- void exec_cgi_script(char *method, char *path, char *args, int in, FILE *out)
- {
- struct stat finfo;
- char path_args[HUGE_STRING_LEN];
- char **env;
- int m;
-
- get_path_info(path,path_args,out,&finfo);
- if((!strcmp(method,"GET")) || (!strcmp(method,"HEAD"))) m=M_GET;
- else if(!strcmp(method,"POST")) m=M_POST;
- else if(!strcmp(method,"PUT")) m=M_PUT;
- else if(!strcmp(method,"DELETE")) m=M_DELETE;
-
- evaluate_access(path,&finfo,m,&allow,&allow_options,out);
- if(!allow) {
- log_reason("client denied by server configuration",path);
- unmunge_name(path);
- die(FORBIDDEN,path,out);
- }
- if(!(env = add_common_vars(in_headers_env,out)))
- die(NO_MEMORY,"exec_cgi_script",out);
-
- bytes_sent = 0;
- if(cgi_stub(method,path,path_args,args,env,&finfo,in,out) == REDIRECT_URL)
- die(REDIRECT,location,out);
- /* cgi_stub will screw with env, but only after the fork */
- free_env(env);
- log_transaction();
- }
-
- char **set_env_NCSA(FILE *out) {
- char **env;
- int n;
- char t[MAX_STRING_LEN];
-
- if(!(env = (char **) malloc ((4+2)*sizeof(char *))))
- die(NO_MEMORY,"set_env_NCSA",out);
- n=0;
- env[n++] = make_env_str("PATH",getenv("PATH"),out);
-
- env[n++] = make_env_str("DOCUMENT_ROOT",document_root,out);
- env[n++] = make_env_str("SERVER_ROOT",server_root,out);
- env[n++] = make_env_str("REMOTE_HOST",remote_name,out);
- sprintf(t,"SERVER_NAME=%s:%d",server_hostname,port);
- if(!(env[n++] = strdup(t)))
- die(NO_MEMORY,"set_env_NCSA",out);
- env[n] = NULL;
- return env;
- }
-
- void exec_get_NCSA(char *path, char *args, int in, FILE *fd) {
- FILE *tfp;
- struct stat finfo;
- int pfd[2];
- char path_args[MAX_STRING_LEN];
- char t[MAX_STRING_LEN];
- register int n,x;
- char **env;
-
- env = set_env_NCSA(fd);
-
- path_args[0] = '\0';
- /* check if it's really a script with extra args */
- n=count_dirs(path);
- for(x=0;x<=n;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);
- goto run_script;
- }
- }
- }
- log_reason("script not found or unable to stat",path);
- unmunge_name(path);
- die(NOT_FOUND,path,fd);
- run_script:
- if(!can_exec(&finfo)) {
- log_reason("file permissions deny server execution",path);
- unmunge_name(path);
- die(FORBIDDEN,path,fd);
- }
- evaluate_access(path,&finfo,M_GET,&allow,&allow_options,fd);
- if(!allow) {
- unmunge_name(path);
- die(FORBIDDEN,path,fd);
- }
-
- if(pipe(pfd) < 0)
- die(SERVER_ERROR,"could not open pipe",fd);
-
- signal(SIGALRM,send_fd_timed_out);
- signal(SIGPIPE,send_fd_timed_out);
- alarm(timeout);
-
- if((pid = fork()) < 0)
- die(SERVER_ERROR,"could not fork",fd);
- else if(!pid) {
- char *argv0;
-
- close(pfd[0]);
- if(pfd[1] != STDOUT_FILENO) {
- dup2(pfd[1],STDOUT_FILENO);
- close(pfd[1]);
- }
- if(argv0 = strrchr(path,'/'))
- argv0++;
- else
- argv0 = path;
- if(args[0] && path_args[0]) {
- if(execle(path,argv0,path_args,args,(char *)0,env) == -1)
- exit(1);
- }
- else if(args[0]) {
- if(execle(path,argv0,args,(char *)0,env) == -1)
- exit(1);
- }
- else if(path_args[0]) {
- if(execle(path,argv0,path_args,(char *)0,env) == -1)
- exit(1);
- }
- else
- if(execle(path,argv0,(char *)0,env) == -1)
- exit(1);
- }
- else
- close(pfd[1]);
-
- tfp = fdopen(pfd[0],"r");
-
- if(scan_script_header(tfp,fd))
- die(REDIRECT,location,fd);
-
- if(location[0] == '/') {
- char *t;
- if(!(t = strdup(location)))
- die(NO_MEMORY,"exec_get_NCSA",fd);
- location[0] = '\0';
- send_node(t,"",in,fd);
- htexit(0,fd);
- }
-
- if(!assbackwards)
- send_http_header(fd);
-
- if(!header_only)
- send_fd(tfp,fd,kill_children);
- else
- kill_children();
- fclose(tfp);
- waitpid(pid,NULL,0);
- }
-
-
-
- void exec_post_NCSA(char *path, char *args, int in, FILE *out) {
- int inpipe[2],outpipe[2], x;
- char cl[MAX_STRING_LEN];
- FILE *psin,*psout;
- struct stat finfo;
- char **env;
-
- env = set_env_NCSA(out);
-
- sprintf(cl,"%d",content_length);
-
- if(stat(path,&finfo) == -1) {
- unmunge_name(path);
- if(errno == ENOENT) die(NOT_FOUND,path,out);
- die(FORBIDDEN,path,out);
- }
- evaluate_access(path,&finfo,M_POST,&allow,&allow_options,out);
- if(!allow)
- die(FORBIDDEN,path,out);
-
- if(pipe(inpipe) < 0)
- die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
- if(pipe(outpipe) < 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);
-
- if(!pid) {
- char *argv0;
-
- if(outpipe[1] != STDOUT_FILENO) {
- dup2(outpipe[1],STDOUT_FILENO);
- close(outpipe[1]);
- }
- if(in != STDIN_FILENO) {
- dup2(in,STDIN_FILENO);
- close(in);
- }
- if((argv0 = strrchr(path,'/')) != NULL)
- argv0++;
- else argv0 = path;
- if(execle(path,argv0,cl,args,(char *)0,env) == -1)
- exit(1);
- }
- else {
- close(outpipe[1]);
- close(inpipe[0]);
- }
-
- if(!(psin = fdopen(outpipe[0],"r")))
- die(SERVER_ERROR,"could not read from script",out);
-
- if(scan_script_header(psin,out))
- die(REDIRECT,location,out);
-
- if(location[0] == '/') {
- char *t;
- if(!(t = strdup(location)))
- die(NO_MEMORY,"exec_post_NCSA",out);
- location[0] = '\0';
- send_node(t,"",in,out);
- htexit(0,out);
- }
-
- content_length = -1;
- if(!assbackwards)
- send_http_header(out);
-
- send_fd(psin,out,kill_children);
- fclose(psin);
- waitpid(pid,NULL,0);
- }
-