- while ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("ftpd: socket");
- sleep(5);
- }
- if (options & SO_DEBUG)
- if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
- perror("ftpd: setsockopt (SO_DEBUG)");
- if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0)
- perror("ftpd: setsockopt (SO_KEEPALIVE)");
- while (bind(s, &ctrl_addr, sizeof (ctrl_addr), 0) < 0) {
- perror("ftpd: bind");
- sleep(5);
- }
- signal(SIGCHLD, reapchild);
- listen(s, 10);
- for (;;) {
- int hisaddrlen = sizeof (his_addr);
-
- ctrl = accept(s, &his_addr, &hisaddrlen, 0);
- if (ctrl < 0) {
- if (errno == EINTR)
- continue;
- perror("ftpd: accept");
- continue;
+
+#ifdef F_SETOWN
+ if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
+ syslog(LOG_ERR, "fcntl F_SETOWN: %m");
+#endif
+ dolog(&his_addr);
+ /*
+ * Set up default state
+ */
+ data = -1;
+ type = TYPE_A;
+ form = FORM_N;
+ stru = STRU_F;
+ mode = MODE_S;
+ tmpline[0] = '\0';
+ (void) gethostname(hostname, sizeof (hostname));
+ reply(220, "%s FTP server (%s) ready.", hostname, version);
+ (void) setjmp(errcatch);
+ for (;;)
+ (void) yyparse();
+ /* NOTREACHED */
+}
+
+lostconn()
+{
+
+ if (debug)
+ syslog(LOG_DEBUG, "lost connection");
+ dologout(-1);
+}
+
+static char ttyline[20];
+
+/*
+ * Helper function for sgetpwnam().
+ */
+char *
+sgetsave(s)
+ char *s;
+{
+ char *malloc();
+ char *new = malloc((unsigned) strlen(s) + 1);
+
+ if (new == NULL) {
+ perror_reply(421, "Local resource failure: malloc");
+ dologout(1);
+ /* NOTREACHED */
+ }
+ (void) strcpy(new, s);
+ return (new);
+}
+
+/*
+ * Save the result of a getpwnam. Used for USER command, since
+ * the data returned must not be clobbered by any other command
+ * (e.g., globbing).
+ */
+struct passwd *
+sgetpwnam(name)
+ char *name;
+{
+ static struct passwd save;
+ register struct passwd *p;
+ char *sgetsave();
+
+ if ((p = getpwnam(name)) == NULL)
+ return (p);
+ if (save.pw_name) {
+ free(save.pw_name);
+ free(save.pw_passwd);
+ free(save.pw_gecos);
+ free(save.pw_dir);
+ free(save.pw_shell);
+ }
+ save = *p;
+ save.pw_name = sgetsave(p->pw_name);
+ save.pw_passwd = sgetsave(p->pw_passwd);
+ save.pw_gecos = sgetsave(p->pw_gecos);
+ save.pw_dir = sgetsave(p->pw_dir);
+ save.pw_shell = sgetsave(p->pw_shell);
+ return (&save);
+}
+
+int login_attempts; /* number of failed login attempts */
+int askpasswd; /* had user command, ask for passwd */
+
+/*
+ * USER command.
+ * Sets global passwd pointer pw if named account exists and is acceptable;
+ * sets askpasswd if a PASS command is expected. If logged in previously,
+ * need to reset state. If name is "ftp" or "anonymous", the name is not in
+ * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
+ * If account doesn't exist, ask for passwd anyway. Otherwise, check user
+ * requesting login privileges. Disallow anyone who does not have a standard
+ * shell as returned by getusershell(). Disallow anyone mentioned in the file
+ * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
+ */
+user(name)
+ char *name;
+{
+ register char *cp;
+ char *shell;
+ char *getusershell();
+
+ if (logged_in) {
+ if (guest) {
+ reply(530, "Can't change user from guest login.");
+ return;