Exemple #1
0
int init_cgi(request * req)
{
	int child_pid;
	int pipes[2];
	int use_pipes = 0;

	SQUASH_KA(req);

	if (req->is_cgi) {
		if (complete_env(req) == 0) {
			return 0;
		}
	}

	if (req->is_cgi == CGI || 1) {
		use_pipes = 1;
		if (pipe(pipes) == -1) {
			log_error_time();
			perror("pipe");
			return 0;
		}

		/* set the read end of the socket to non-blocking */
		if (set_nonblock_fd(pipes[0]) == -1) {
			log_error_time();
			perror("cgi-fcntl");
			close(pipes[0]);
			close(pipes[1]);
			return 0;
		}
	}

	child_pid = fork();
	switch(child_pid) {
		case -1:
			/* fork unsuccessful */
			log_error_time();
			perror("fork");

			if (use_pipes) {
				close(pipes[0]);
				close(pipes[1]);
			}
			send_r_error(req);
			/* FIXME: There is aproblem here. send_r_error would work
			   for NPH and CGI, but not for GUNZIP.  Fix that. */
			/* i'd like to send_r_error, but.... */
			return 0;
			break;
		case 0:
			/* child */
			if (req->is_cgi == CGI || req->is_cgi == NPH) {
				char *foo = strdup(req->pathname);
				char *c;

				if (!foo) {
					WARN("unable to strdup pathname for req->pathname");
					_exit(1);
				}
				c = strrchr(foo, '/');
				if (c) {
					++c;
					*c = '\0';
				} else {
					/* we have a serious problem */
					log_error_time();
					perror("chdir");
					if (use_pipes)
						close(pipes[1]);
					_exit(1);
				}
				if (chdir(foo) != 0) {
					log_error_time();
					perror("chdir");
					if (use_pipes)
						close(pipes[1]);
					_exit(1);
				}
			}
			if (use_pipes) {
				close(pipes[0]);
				/* tie cgi's STDOUT to it's write end of pipe */
				if (dup2(pipes[1], STDOUT_FILENO) == -1) {
					log_error_time();
					perror("dup2 - pipes");
					close(pipes[1]);
					_exit(1);
				}
				close(pipes[1]);
				if (set_block_fd(STDOUT_FILENO) == -1) {
					log_error_time();
					perror("cgi-fcntl");
					_exit(1);
				}
			} else {
				/* tie stdout to socket */
				if (dup2(req->fd, STDOUT_FILENO) == -1) {
					log_error_time();
					perror("dup2 - fd");
					_exit(1);
				}
				/* Switch socket flags back to blocking */
				if (set_block_fd(req->fd) == -1) {
					log_error_time();
					perror("cgi-fcntl");
					_exit(1);
				}
			}
			/* tie post_data_fd to POST stdin */
			if (req->method == M_POST) { /* tie stdin to file */
				lseek(req->post_data_fd, SEEK_SET, 0);
				dup2(req->post_data_fd, STDIN_FILENO);
				close(req->post_data_fd);
			}
			/* Close access log, so CGI program can't scribble
			 * where it shouldn't
			 */
			close_access_log();

			/*
			 * tie STDERR to cgi_log_fd
			 * cgi_log_fd will automatically close, close-on-exec rocks!
			 * if we don't tied STDERR (current log_error) to cgi_log_fd,
			 *  then we ought to close it.
			 */
			//if (!cgi_log_fd)
			//	dup2(devnullfd, STDERR_FILENO);
			//else
			//	dup2(cgi_log_fd, STDERR_FILENO);

			if (req->is_cgi) {
				char *aargv[CGI_ARGC_MAX + 1];
				create_argv(req, aargv);
				execve(req->pathname, aargv, req->cgi_env);
			} else {
				if (req->pathname[strlen(req->pathname) - 1] == '/')
					execl(dirmaker, dirmaker, req->pathname, req->request_uri,
							NULL);
#ifdef GUNZIP
				else
					execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
							req->pathname, NULL);
#endif
			}
			/* execve failed */
			WARN(req->pathname);
			_exit(1);
			break;

		default:
			/* parent */
			/* if here, fork was successful */
			if (verbose_cgi_logs) {
				log_error_time();
				fprintf(stderr, "Forked child \"%s\" pid %d\n",
						req->pathname, child_pid);
			}

			if (req->method == M_POST) {
				close(req->post_data_fd); /* child closed it too */
				req->post_data_fd = 0;
			}

			/* NPH, GUNZIP, etc... all go straight to the fd */
			if (!use_pipes)
				return 0;

			close(pipes[1]);
			req->data_fd = pipes[0];

			req->status = PIPE_READ;
			if (req->is_cgi == CGI) {
				req->cgi_status = CGI_PARSE; /* got to parse cgi header */
				/* for cgi_header... I get half the buffer! */
				req->header_line = req->header_end =
					(req->buffer + BUFFER_SIZE / 2);
			} else {
				req->cgi_status = CGI_BUFFER;
				/* I get all the buffer! */
				req->header_line = req->header_end = req->buffer;
			}

			/* reset req->filepos for logging (it's used in pipe.c) */
			/* still don't know why req->filesize might be reset though */
			req->filepos = 0;
			break;
	}

	return 1;
}
Exemple #2
0
int init_cgi(request * req)
{
#ifndef EXCLUDE_CGI
    int child_pid;
    int pipes[2];
    int use_pipes = 0;
#endif

    SQUASH_KA(req);

#ifndef EXCLUDE_CGI
    if (req->cgi_type) {
        if (complete_env(req) == 0) {
            return 0;
        }
    }
    DEBUG(DEBUG_CGI_ENV) {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            log_error_time();
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }

    /* we want to use pipes whenever it's a CGI or directory */
    /* otherwise (NPH, gunzip) we want no pipes */
    if (req->cgi_type == CGI ||
        (!req->cgi_type &&
         (req->pathname[strlen(req->pathname) - 1] == '/'))) {
        use_pipes = 1;
        if (pipe(pipes) == -1) {
            log_error_doc(req);
            perror("pipe");
            return 0;
        }

        /* set the read end of the socket to non-blocking */
        if (set_nonblock_fd(pipes[0]) == -1) {
            log_error_doc(req);
            perror("cgi-fcntl");
            close(pipes[0]);
            close(pipes[1]);
            return 0;
        }
    }

    child_pid = fork();
    switch (child_pid) {
    case -1:
        /* fork unsuccessful */
        /* FIXME: There is a problem here. send_r_error (called by
         * boa_perror) would work for NPH and CGI, but not for GUNZIP.  
         * Fix that. 
         */
        boa_perror(req, "fork failed");
        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        return 0;
        break;
    case 0:
        /* child */
        reset_signals();

        if (req->cgi_type == CGI || req->cgi_type == NPH) {
            char *c;
            unsigned int l;
            char *newpath, *oldpath;

            c = strrchr(req->pathname, '/');
            if (!c) {
                /* there will always be a '.' */
                log_error_doc(req);
                fprintf(stderr,
                        "unable to find '/' in req->pathname: \"%s\"\n",
                        req->pathname);
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            *c = '\0';

            if (chdir(req->pathname) != 0) {
                int saved_errno = errno;
                log_error_doc(req);
                fprintf(stderr, "Could not chdir to \"%s\":",
                        req->pathname);
                errno = saved_errno;
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            oldpath = req->pathname;
            req->pathname = ++c;
            l = strlen(req->pathname) + 3;
            /* prefix './' */
            newpath = malloc(sizeof (char) * l);
            if (!newpath) {
                /* there will always be a '.' */
                log_error_doc(req);
                perror("unable to malloc for newpath");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }
            newpath[0] = '.';
            newpath[1] = '/';
            memcpy(&newpath[2], req->pathname, l - 2); /* includes the trailing '\0' */
            free(oldpath);
            req->pathname = newpath;
        }
        if (use_pipes) {
            /* close the 'read' end of the pipes[] */
            close(pipes[0]);
            /* tie CGI's STDOUT to our write end of pipe */
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - pipes");
                _exit(EXIT_FAILURE);
            }
            close(pipes[1]);
        } else {
            /* tie stdout to socket */
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - fd");
                _exit(EXIT_FAILURE);
            }
            close(req->fd);
        }
        /* Switch socket flags back to blocking */
        if (set_block_fd(STDOUT_FILENO) == -1) {
            log_error_doc(req);
            perror("cgi-fcntl");
            _exit(EXIT_FAILURE);
        }
        /* tie post_data_fd to POST stdin */
        if (req->method == M_POST) { /* tie stdin to file */
// davidhsu ----------------------
#ifndef NEW_POST
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
#endif
//-------------------------------	
			
        }

#ifdef USE_SETRLIMIT
        /* setrlimit stuff.
         * This is neat!
         * RLIMIT_STACK    max stack size
         * RLIMIT_CORE     max core file size
         * RLIMIT_RSS      max resident set size
         * RLIMIT_NPROC    max number of processes
         * RLIMIT_NOFILE   max number of open files
         * RLIMIT_MEMLOCK  max locked-in-memory address space
         * RLIMIT_AS       address space (virtual memory) limit
         *
         * RLIMIT_CPU      CPU time in seconds
         * RLIMIT_DATA     max data size
         *
         * Currently, we only limit the CPU time and the DATA segment
         * We also "nice" the process.
         *
         * This section of code adapted from patches sent in by Steve Thompson
         * (no email available)
         */

        {
            struct rlimit rl;
            int retval;

            if (cgi_rlimit_cpu) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_cpu;
                retval = setrlimit(RLIMIT_CPU, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_CPU,%d): %s\n",
                            rlimit_cpu, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_limit_data) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_data;
                retval = setrlimit(RLIMIT_DATA, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_DATA,%d): %s\n",
                            rlimit_data, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_nice) {
                retval = nice(cgi_nice);
                if (retval == -1) {
                    log_error_time();
                    perror("nice");
                    _exit(EXIT_FAILURE);
                }
            }
        }
#endif

        umask(cgi_umask);       /* change umask *again* u=rwx,g=rxw,o= */

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tie STDERR (current log_error) to cgi_log_fd,
         *  then we ought to tie it to /dev/null
         *  FIXME: we currently don't tie it to /dev/null, we leave it
         *  tied to whatever 'error_log' points to.  This means CGIs can
         *  scribble on the error_log, probably a bad thing.
         */
        if (cgi_log_fd) {
            dup2(cgi_log_fd, STDERR_FILENO);
        }

        if (req->cgi_type) {
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);
        } else {
            if (req->pathname[strlen(req->pathname) - 1] == '/')
                execl(dirmaker, dirmaker, req->pathname, req->request_uri,
                      (void *) NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, (void *) NULL);
#endif
        }
        /* execve failed */
        log_error_doc(req);
        fprintf(stderr, "Unable to execve/execl pathname: \"%s\"",
                req->pathname);
        perror("");
        _exit(EXIT_FAILURE);
        break;

    default:
        /* parent */
        /* if here, fork was successful */
        if (verbose_cgi_logs) {
            log_error_time();
            fprintf(stderr, "Forked child \"%s\" pid %d\n",
                    req->pathname, child_pid);
        }

        if (req->method == M_POST) {

// davidhsu ----------------
#ifndef NEW_POST
             close(req->post_data_fd); /* child closed it too */
             req->post_data_fd = 0;
#else			 
		if (req->post_data) {
			free(req->post_data);
			req->post_data = NULL;
		}
		req->post_data_len = 0;
		req->post_data_idx = 0;
#endif		
//------------------------

        }

        /* NPH, GUNZIP, etc... all go straight to the fd */
        if (!use_pipes)
            return 0;

        close(pipes[1]);
        req->data_fd = pipes[0];

        req->status = PIPE_READ;
        if (req->cgi_type == CGI) {
            req->cgi_status = CGI_PARSE; /* got to parse cgi header */
            /* for cgi_header... I get half the buffer! */
            req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
        } else {
            req->cgi_status = CGI_BUFFER;
            /* I get all the buffer! */
            req->header_line = req->header_end = req->buffer;
        }

        /* reset req->filepos for logging (it's used in pipe.c) */
        /* still don't know why req->filesize might be reset though */
        req->filepos = 0;
        break;
    }
#endif //!EXCLUDE_CGI

    return 1;
}
Exemple #3
0
int init_cgi(request * req)
{
    int child_pid;
    int pipes[2];
    int use_pipes = 0;

    SQUASH_KA(req);

    if (req->is_cgi) {
        if (complete_env(req) == 0) {
            return 0;
        }
    }
#ifdef FASCIST_LOGGING
    {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }
#endif

    if (req->is_cgi == CGI || 1) {
        use_pipes = 1;
        if (pipe(pipes) == -1) {
            log_error_time();
            perror("pipe");
            return 0;
        }

        
        if (set_nonblock_fd(pipes[0]) == -1) {
            log_error_time();
            perror("cgi-fcntl");
            close(pipes[0]);
            close(pipes[1]);
            return 0;
        }
    }

    child_pid = fork();
    switch(child_pid) {
    case -1:
        
        log_error_time();
        perror("fork");

        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        send_r_error(req);
        /* FIXME: There is aproblem here. send_r_error would work
           for NPH and CGI, but not for GUNZIP.  Fix that. */
        
        return 0;
        break;
    case 0:
        
        if (req->is_cgi == CGI || req->is_cgi == NPH) {
            char *foo = strdup(req->pathname);
            char *c;

            if (!foo) {
                WARN("unable to strdup pathname for req->pathname");
                _exit(1);
            }
            c = strrchr(foo, '/');
            if (c) {
                ++c;
                *c = '\0';
            } else {
                
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
            if (chdir(foo) != 0) {
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
        }
        if (use_pipes) {
            close(pipes[0]);
            
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {
                log_error_time();
                perror("dup2 - pipes");
                close(pipes[1]);
                _exit(1);
            }
            close(pipes[1]);
            if (set_block_fd(STDOUT_FILENO) == -1) {
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        } else {
            
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_time();
                perror("dup2 - fd");
                _exit(1);
            }
            
            if (set_block_fd(req->fd) == -1) {
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        }
        
        if (req->method == M_POST) { 
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
        }
        /* Close access log, so CGI program can't scribble
         * where it shouldn't
         */
        close_access_log();

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tied STDERR (current log_error) to cgi_log_fd,
         *  then we ought to close it.
         */
        if (!cgi_log_fd)
            dup2(devnullfd, STDERR_FILENO);
        else
            dup2(cgi_log_fd, STDERR_FILENO);

        if (req->is_cgi) {
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);
        } else {
            if (req->pathname[strlen(req->pathname) - 1] == '/')
                execl(dirmaker, dirmaker, req->pathname, req->request_uri,
                      NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, NULL);
#endif
        }
        
        WARN(req->pathname);
        _exit(1);
        break;

    default:
        
        
        if (verbose_cgi_logs) {
            log_error_time();
            fprintf(stderr, "Forked child \"%s\" pid %d\n",
                    req->pathname, child_pid);
        }

        if (req->method == M_POST) {
            close(req->post_data_fd); 
            req->post_data_fd = 0;
        }

        
        if (!use_pipes)
            return 0;

        close(pipes[1]);
        req->data_fd = pipes[0];

        req->status = PIPE_READ;
        if (req->is_cgi == CGI) {
            req->cgi_status = CGI_PARSE; 
            
            req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
        } else {
            req->cgi_status = CGI_BUFFER;
            
            req->header_line = req->header_end = req->buffer;
        }

        
        
        req->filepos = 0;
        break;
    }

    return 1;
}