diff options
Diffstat (limited to 'libexec/ftpd/ftpd.c')
-rw-r--r-- | libexec/ftpd/ftpd.c | 137 |
1 files changed, 108 insertions, 29 deletions
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c index 1137d9f..2d7a041 100644 --- a/libexec/ftpd/ftpd.c +++ b/libexec/ftpd/ftpd.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ftpd.c,v 1.14 1996/01/01 08:35:11 peter Exp $ + * $Id: ftpd.c,v 1.15 1996/03/18 11:09:03 davidg Exp $ */ #ifndef lint @@ -100,12 +100,14 @@ static char version[] = "Version 6.00"; extern off_t restart_point; extern char cbuf[]; +struct sockaddr_in server_addr; struct sockaddr_in ctrl_addr; struct sockaddr_in data_source; struct sockaddr_in data_dest; struct sockaddr_in his_addr; struct sockaddr_in pasv_addr; +int daemon_mode; int data; jmp_buf errcatch, urgcatch; int logged_in; @@ -199,6 +201,7 @@ static void send_data __P((FILE *, FILE *, off_t, off_t, int)); static struct passwd * sgetpwnam __P((char *)); static char *sgetsave __P((char *)); +static void reapchild __P((int)); static char * curdir() @@ -225,31 +228,6 @@ main(argc, argv, envp) tzset(); /* in case no timezone database in ~ftp */ - /* - * LOG_NDELAY sets up the logging connection immediately, - * necessary for anonymous ftp's that chroot and can't do it later. - */ - openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); - addrlen = sizeof(his_addr); - if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); - exit(1); - } -#ifdef SKEY - strcpy(addr_string, inet_ntoa(his_addr.sin_addr)); -#endif - addrlen = sizeof(ctrl_addr); - if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); - exit(1); - } -#ifdef IP_TOS - tos = IPTOS_LOWDELAY; - if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); -#endif - data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); - debug = 0; #ifdef OLD_SETPROCTITLE /* * Save start and extent of argv for setproctitle. @@ -262,11 +240,15 @@ main(argc, argv, envp) #ifdef STATS - while ((ch = getopt(argc, argv, "dlSt:T:u:v")) != EOF) { + while ((ch = getopt(argc, argv, "dlDSt:T:u:v")) != EOF) { #else - while ((ch = getopt(argc, argv, "dlUt:T:u:v")) != EOF) { + while ((ch = getopt(argc, argv, "dlDUt:T:u:v")) != EOF) { #endif switch (ch) { + case 'D': + daemon_mode++; + break; + case 'd': debug = 1; break; @@ -316,12 +298,102 @@ main(argc, argv, envp) break; } } + (void) freopen(_PATH_DEVNULL, "w", stderr); - (void) signal(SIGPIPE, lostconn); + + /* + * LOG_NDELAY sets up the logging connection immediately, + * necessary for anonymous ftp's that chroot and can't do it later. + */ + openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); + + if (daemon_mode) { + int ctl_sock, fd; + struct servent *sv; + + /* + * Detach from parent. + */ + if (daemon(1, 1) < 0) { + syslog(LOG_ERR, "failed to become a daemon"); + exit(1); + } + (void) signal(SIGCHLD, reapchild); + /* + * Get port number for ftp/tcp. + */ + sv = getservbyname("ftp", "tcp"); + if (sv == NULL) { + syslog(LOG_ERR, "getservbyname for ftp failed"); + exit(1); + } + /* + * Open a socket, bind it to the FTP port, and start + * listening. + */ + ctl_sock = socket(AF_INET, SOCK_STREAM, 0); + if (ctl_sock < 0) { + syslog(LOG_ERR, "control socket: %m"); + exit(1); + } + if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, "control setsockopt: %m");; + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = sv->s_port; + if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) { + syslog(LOG_ERR, "control bind: %m"); + exit(1); + } + if (listen(ctl_sock, 32) < 0) { + syslog(LOG_ERR, "control listen: %m"); + exit(1); + } + /* + * Loop forever accepting connection requests and forking off + * children to handle them. + */ + while (1) { + addrlen = sizeof(his_addr); + fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen); + if (fork() == 0) { + /* child */ + (void) dup2(fd, 0); + (void) dup2(fd, 1); + close(ctl_sock); + break; + } + close(fd); + } + } else { + addrlen = sizeof(his_addr); + if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { + syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); + exit(1); + } + } + (void) signal(SIGCHLD, SIG_IGN); + (void) signal(SIGPIPE, lostconn); if ((int)signal(SIGURG, myoob) < 0) syslog(LOG_ERR, "signal: %m"); +#ifdef SKEY + strcpy(addr_string, inet_ntoa(his_addr.sin_addr)); +#endif + addrlen = sizeof(ctrl_addr); + if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { + syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); + exit(1); + } +#ifdef IP_TOS + tos = IPTOS_LOWDELAY; + if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) + syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); +#endif + data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); + /* Try to handle urgent data inline */ #ifdef SO_OOBINLINE if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) @@ -1781,6 +1853,13 @@ out: } } +void +reapchild(signo) + int signo; +{ + while (wait3(NULL, WNOHANG, NULL) > 0); +} + #ifdef OLD_SETPROCTITLE /* * Clobber argv so ps will show what we're doing. (Stolen from sendmail.) |