Ejemplo n.º 1
0
int init_cgi(request * req)
{
	int child_pid;
	int p[2];

	SQUASH_KA(req);

	complete_env(req);

	if (req->is_cgi == CGI) {
		if (pipe(p) == -1) {
#ifdef BOA_TIME_LOG
			log_error_time();
			perror("pipe");
#endif
			syslog(LOG_ERR, "pipe: %d.\n", errno);
			return 0;
		}
		if (fcntl(p[0], F_SETFL, O_NONBLOCK) == -1) {
#ifdef BOA_TIME_LOG
			fprintf(stderr, "Unable to do something: %d.\n", errno);
#endif
			syslog(LOG_ERR, "Unable to do something: %d.\n", errno);
			close(p[0]);
			close(p[1]);
			return 0;
		}
	}
#ifdef EMBED
	if ((child_pid = vfork()) == -1) {	/* vfork unsuccessful */
#else
	if ((child_pid = fork()) == -1) {	/* fork unsuccessful */
#endif
		if (req->is_cgi == CGI) {
			close(p[0]);
			close(p[1]);
		}
#ifdef BOA_TIME_LOG
		log_error_time();
		perror("fork");
#endif
		return 0;
	}
	/* if here, fork was successful */

	if (!child_pid) {			/* 0 == child */
		int newstdin = -1, newstdout = -1, newstderr = -1;

		if (req->is_cgi != CGI) {	/* nph or gunzip, etc... */
			newstdout = req->fd;
		} else {
			/* tie stdout to write end of pipe */
			close(p[0]);
			newstdout = p[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);
			newstdin = 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 */
		if (cgi_log_fd)
			newstderr = cgi_log_fd;
		else
			newstderr = open("/dev/null", O_WRONLY);

		/* Set up stdin/out/err without trampling over each other. */
		if (newstdin >= 0 && newstdin != STDIN_FILENO) {
			if (newstdout == STDIN_FILENO)
				newstdout = dup(newstdout);
			if (newstderr == STDIN_FILENO)
				newstderr = dup(newstderr);
			dup2(newstdin, STDIN_FILENO);
			close(newstdin);
		}
		if (newstdout >= 0 && newstdout != STDOUT_FILENO) {
			if (newstderr == STDOUT_FILENO)
				newstderr = dup(newstderr);
			dup2(newstdout, STDOUT_FILENO);
			close(newstdout);
			/* Switch socket flags back to blocking */
			if (fcntl(STDOUT_FILENO, F_SETFL, 0) == -1) {
#ifdef BOA_TIME_LOG
				perror("cgi-fcntl");
#endif
			}
		}
		if (newstderr >= 0 && newstderr != STDERR_FILENO) {
			dup2(newstderr, STDERR_FILENO);
			close(newstderr);
		}

		if (req->is_cgi) {
			char *aargv[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);
			else {
#if 0
				execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
					  req->pathname, NULL);
#endif
				syslog(LOG_ERR, "gunzip not found");
				
			}
		}
		/* execve failed */
		log_error_time();
		perror(req->pathname);
		_exit(1);
	}
	/* if here, fork was successful */

	if (verbose_cgi_logs) {
#ifdef BOA_TIME_LOG
		log_error_time();
		fprintf(stderr, "Forked child \"%s\" pid %d\n",
				req->pathname, child_pid);
#endif
		syslog(LOG_INFO, "Forked child \"%s\" pid %d\n",
				req->pathname, child_pid);
	}
	if (req->is_cgi != CGI)
		return 0;

	req->data_fd = p[0];

	/* close duplicate write end of pipe */
	close(p[1]);
	
	req->status = PIPE_READ;
	req->filesize = req->filepos = 0; /* why is this here??? */

	if (req->is_cgi == CGI) {		/* cgi */
		/* for cgi_header... I get half the buffer! */
		req->header_line = req->header_end = 
 			(req->buffer + BUFFER_SIZE / 2);
		req->cgi_status = CGI_READ;	/* got to parse cgi header */
	} else	{					/* gunzip or similar */
		req->header_line = req->header_end = req->buffer;
		req->cgi_status = CGI_WRITE;	/* don't do it. */
	}
	
	return 1;					/* success */
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 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;
}