#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_TCPD_H #include #endif #include "extern.h" static void reapchild __P ((int)); #define DEFPORT 21 #ifdef WITH_WRAP int allow_severity = LOG_INFO; int deny_severity = LOG_NOTICE; static int check_host (struct sockaddr *sa) { struct sockaddr_storage *sin; struct hostent *hp; char *addr; if (sa->sa_family != AF_INET) return 1; sin = (struct sockaddr_storage *)sa; #if 1 /* FRITZBOX */ hp = 0; #else hp = gethostbyaddr ((char *)&sin->sin_addr, sizeof (struct in_addr), AF_INET); #endif addr = inet_ntoa (sin->sin_addr); if (hp) { if (!hosts_ctl ("ftpd", hp->h_name, addr, STRING_UNKNOWN)) { syslog (LOG_NOTICE, "tcpwrappers rejected: %s [%s]", hp->h_name, addr); return 0; } } else { if (!hosts_ctl ("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) { syslog (LOG_NOTICE, "tcpwrappers rejected: [%s]", addr); return 0; } } return (1); } #endif static int n_child = 0; static void reapchild (int signo) { int save_errno = errno; (void)signo; while (waitpid (-1, NULL, WNOHANG) > 0) { n_child--; } errno = save_errno; } int server_mode (const char *pidfile, struct sockaddr_storage *phis_addr) { int ctl_sock, fd; struct servent *sv; int port; static struct sockaddr_storage server_addr; /* Our address. */ Log(("%s %u",__FUNCTION__, __LINE__)); /* Become a daemon. */ if (daemon(1,1) < 0) { Log(("%s %u",__FUNCTION__, __LINE__)); syslog (LOG_ERR, "failed to become a daemon"); return -1; } (void) signal (SIGCHLD, reapchild); Log(("%s %u",__FUNCTION__, __LINE__)); /* Get port for ftp/tcp. */ sv = getservbyname ("ftp", "tcp"); port = (sv == NULL) ? DEFPORT : ntohs(sv->s_port); Log(("%s %u",__FUNCTION__, __LINE__)); /* Open socket, bind and start listen. */ ctl_sock = socket (AF_INET, SOCK_STREAM, 0); if (ctl_sock < 0) { syslog (LOG_ERR, "control socket: %m"); return -1; } Log(("%s %u",__FUNCTION__, __LINE__)); /* Enable local address reuse. */ { int on = 1; if (setsockopt (ctl_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) syslog (LOG_ERR, "control setsockopt: %m"); } Log(("%s %u",__FUNCTION__, __LINE__)); memset (&server_addr, 0, sizeof(server_addr)); server_addr.ss_family = AF_INET; ((struct sockaddr_in *)&server_addr)->sin_port = htons (port); if (bind (ctl_sock, (struct sockaddr *)&server_addr, sizeof server_addr)) { syslog (LOG_ERR, "control bind: %m"); close (ctl_sock); return -1; } Log(("%s %u",__FUNCTION__, __LINE__)); if (listen (ctl_sock, 32) < 0) { syslog (LOG_ERR, "control listen: %m"); close (ctl_sock); return -1; } /* Stash pid in pidfile. */ { FILE *pid_fp = fopen (pidfile, "w"); if (pid_fp == NULL) syslog (LOG_ERR, "can't open %s: %m", PATH_FTPDPID); else { fprintf (pid_fp, "%d\n", getpid()); fchmod (fileno(pid_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); fclose (pid_fp); } } Log(("%s %u",__FUNCTION__, __LINE__)); /* Loop forever accepting connection requests and forking off children to handle them. */ while (1) { pid_t pid; int addrlen = sizeof (*phis_addr); Log(("%s %u",__FUNCTION__, __LINE__)); fd = accept (ctl_sock, (struct sockaddr *)phis_addr, &addrlen); Log(("%s %u",__FUNCTION__, __LINE__)); #if 1 /* FRITZBOX */ if (0 == max_clients || n_child < max_clients) { #endif if ((pid = fork ()) == 0) /* child */ { (void) dup2 (fd, 0); (void) dup2 (fd, 1); close (ctl_sock); break; } else if (pid != -1) { n_child++; } } else { /* Too many clients */ char *s = "421 Client limit reached. Try again later.\n"; write(fd, s, strlen(s)); } close (fd); Log(("%s %u",__FUNCTION__, __LINE__)); } Log(("%s %u",__FUNCTION__, __LINE__)); #ifdef WITH_WRAP /* In the child. */ if (!check_host ((struct sockaddr *)phis_addr)) return -1; #endif Log(("%s %u",__FUNCTION__, __LINE__)); return fd; }