Steve Jacobson's changes (from <csvsj@ucbopal>).
authorGregory Minshall <minshall@ucbvax.Berkeley.EDU>
Tue, 4 Feb 1986 06:32:49 +0000 (22:32 -0800)
committerGregory Minshall <minshall@ucbvax.Berkeley.EDU>
Tue, 4 Feb 1986 06:32:49 +0000 (22:32 -0800)
SCCS-vsn: libexec/ftpd/ftpd.c 5.2
SCCS-vsn: libexec/ftpd/ftpcmd.y 5.3
SCCS-vsn: libexec/ftpd/Makefile 5.2

usr/src/libexec/ftpd/Makefile
usr/src/libexec/ftpd/ftpcmd.y
usr/src/libexec/ftpd/ftpd.c

index 84edecc..5b53d55 100644 (file)
@@ -3,7 +3,7 @@
 # All rights reserved.  The Berkeley software License Agreement
 # specifies the terms and conditions for redistribution.
 #
 # All rights reserved.  The Berkeley software License Agreement
 # specifies the terms and conditions for redistribution.
 #
-#      @(#)Makefile    5.1 (Berkeley) %G%
+#      @(#)Makefile    5.2 (Berkeley) %G%
 #
 ALL=   ftpd.o ftpcmd.o glob.o vers.o
 DESTDIR=
 #
 ALL=   ftpd.o ftpcmd.o glob.o vers.o
 DESTDIR=
index 826edf9..74a5b07 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
@@ -12,7 +12,7 @@
 %{
 
 #ifndef lint
 %{
 
 #ifndef lint
-static char sccsid[] = "@(#)ftpcmd.y   5.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)ftpcmd.y   5.3 (Berkeley) %G%";
 #endif
 
 #include <sys/types.h>
 #endif
 
 #include <sys/types.h>
@@ -37,14 +37,19 @@ extern      int type;
 extern int form;
 extern int debug;
 extern int timeout;
 extern int form;
 extern int debug;
 extern int timeout;
+extern  int pdata;
 extern char hostname[];
 extern char *globerr;
 extern int usedefault;
 extern char hostname[];
 extern char *globerr;
 extern int usedefault;
+extern int unique;
+extern  int transflag;
+extern  char tmpline[];
 char   **glob();
 
 static int cmd_type;
 static int cmd_form;
 static int cmd_bytesz;
 char   **glob();
 
 static int cmd_type;
 static int cmd_form;
 static int cmd_bytesz;
+char cbuf[512];
 
 char   *index();
 %}
 
 char   *index();
 %}
@@ -61,7 +66,7 @@ char  *index();
        MRSQ    MRCP    ALLO    REST    RNFR    RNTO
        ABOR    DELE    CWD     LIST    NLST    SITE
        STAT    HELP    NOOP    XMKD    XRMD    XPWD
        MRSQ    MRCP    ALLO    REST    RNFR    RNTO
        ABOR    DELE    CWD     LIST    NLST    SITE
        STAT    HELP    NOOP    XMKD    XRMD    XPWD
-       XCUP
+       XCUP    STOU
 
        LEXERR
 
 
        LEXERR
 
@@ -77,6 +82,7 @@ cmd:          USER SP username CRLF
                = {
                        extern struct passwd *getpwnam();
 
                = {
                        extern struct passwd *getpwnam();
 
+                       logged_in = 0;
                        if (strcmp($3, "ftp") == 0 ||
                          strcmp($3, "anonymous") == 0) {
                                if ((pw = getpwnam("ftp")) != NULL) {
                        if (strcmp($3, "ftp") == 0 ||
                          strcmp($3, "anonymous") == 0) {
                                if ((pw = getpwnam("ftp")) != NULL) {
@@ -84,13 +90,19 @@ cmd:                USER SP username CRLF
                                        reply(331,
                                  "Guest login ok, send ident as password.");
                                }
                                        reply(331,
                                  "Guest login ok, send ident as password.");
                                }
+                               else {
+                                       reply(530, "User %s unknown.", $3);
+                               }
                        } else if (checkuser($3)) {
                                guest = 0;
                                pw = getpwnam($3);
                        } else if (checkuser($3)) {
                                guest = 0;
                                pw = getpwnam($3);
-                               reply(331, "Password required for %s.", $3);
+                               if (pw == NULL) {
+                                       reply(530, "User %s unknown.", $3);
+                               }
+                               else {
+                                   reply(331, "Password required for %s.", $3);
+                               }
                        }
                        }
-                       if (pw == NULL)
-                               reply(530, "User %s unknown.", $3);
                        free($3);
                }
        |       PASS SP password CRLF
                        free($3);
                }
        |       PASS SP password CRLF
@@ -101,8 +113,16 @@ cmd:               USER SP username CRLF
        |       PORT SP host_port CRLF
                = {
                        usedefault = 0;
        |       PORT SP host_port CRLF
                = {
                        usedefault = 0;
+                       if (pdata > 0) {
+                               (void) close(pdata);
+                       }
+                       pdata = -1;
                        ack($1);
                }
                        ack($1);
                }
+       |       PASV CRLF
+               = {
+                       passive();
+               }
        |       TYPE SP type_code CRLF
                = {
                        switch (cmd_type) {
        |       TYPE SP type_code CRLF
                = {
                        switch (cmd_type) {
@@ -214,6 +234,10 @@ cmd:               USER SP username CRLF
                        if ($4 != NULL)
                                free($4);
                }
                        if ($4 != NULL)
                                free($4);
                }
+       |       ABOR CRLF
+               = {
+                       ack($1);
+               }
        |       CWD check_login CRLF
                = {
                        if ($2)
        |       CWD check_login CRLF
                = {
                        if ($2)
@@ -263,6 +287,16 @@ cmd:               USER SP username CRLF
                        if ($2)
                                cwd("..");
                }
                        if ($2)
                                cwd("..");
                }
+       |       STOU check_login SP pathname CRLF
+               = {
+                       if ($2 && $4 != NULL) {
+                               unique++;
+                               store($4, "w");
+                               unique = 0;
+                       }
+                       if ($4 != NULL)
+                               free($4);
+               }
        |       QUIT CRLF
                = {
                        reply(221, "Goodbye.");
        |       QUIT CRLF
                = {
                        reply(221, "Goodbye.");
@@ -464,7 +498,7 @@ struct tab cmdtab[] = {             /* In order defined in RFC 765 */
        { "REIN", REIN, ARGS, 0,        "(reinitialize server state)" },
        { "QUIT", QUIT, ARGS, 1,        "(terminate service)", },
        { "PORT", PORT, ARGS, 1,        "<sp> b0, b1, b2, b3, b4" },
        { "REIN", REIN, ARGS, 0,        "(reinitialize server state)" },
        { "QUIT", QUIT, ARGS, 1,        "(terminate service)", },
        { "PORT", PORT, ARGS, 1,        "<sp> b0, b1, b2, b3, b4" },
-       { "PASV", PASV, ARGS, 0,        "(set server in passive mode)" },
+       { "PASV", PASV, ARGS, 1,        "(set server in passive mode)" },
        { "TYPE", TYPE, ARGS, 1,        "<sp> [ A | E | I | L ]" },
        { "STRU", STRU, ARGS, 1,        "(specify file structure)" },
        { "MODE", MODE, ARGS, 1,        "(specify transfer mode)" },
        { "TYPE", TYPE, ARGS, 1,        "<sp> [ A | E | I | L ]" },
        { "STRU", STRU, ARGS, 1,        "(specify file structure)" },
        { "MODE", MODE, ARGS, 1,        "(specify transfer mode)" },
@@ -482,7 +516,7 @@ struct tab cmdtab[] = {             /* In order defined in RFC 765 */
        { "REST", REST, STR1, 0,        "(restart command)" },
        { "RNFR", RNFR, STR1, 1,        "<sp> file-name" },
        { "RNTO", RNTO, STR1, 1,        "<sp> file-name" },
        { "REST", REST, STR1, 0,        "(restart command)" },
        { "RNFR", RNFR, STR1, 1,        "<sp> file-name" },
        { "RNTO", RNTO, STR1, 1,        "<sp> file-name" },
-       { "ABOR", ABOR, ARGS, 0,        "(abort operation)" },
+       { "ABOR", ABOR, ARGS, 1,        "(abort operation)" },
        { "DELE", DELE, STR1, 1,        "<sp> file-name" },
        { "CWD",  CWD,  OSTR, 1,        "[ <sp> directory-name]" },
        { "XCWD", CWD,  OSTR, 1,        "[ <sp> directory-name ]" },
        { "DELE", DELE, STR1, 1,        "<sp> file-name" },
        { "CWD",  CWD,  OSTR, 1,        "[ <sp> directory-name]" },
        { "XCWD", CWD,  OSTR, 1,        "[ <sp> directory-name ]" },
@@ -492,10 +526,15 @@ struct tab cmdtab[] = {           /* In order defined in RFC 765 */
        { "STAT", STAT, OSTR, 0,        "(get server status)" },
        { "HELP", HELP, OSTR, 1,        "[ <sp> <string> ]" },
        { "NOOP", NOOP, ARGS, 1,        "" },
        { "STAT", STAT, OSTR, 0,        "(get server status)" },
        { "HELP", HELP, OSTR, 1,        "[ <sp> <string> ]" },
        { "NOOP", NOOP, ARGS, 1,        "" },
+       { "MKD",  XMKD, STR1, 1,        "<sp> path-name" },
        { "XMKD", XMKD, STR1, 1,        "<sp> path-name" },
        { "XMKD", XMKD, STR1, 1,        "<sp> path-name" },
+       { "RMD",  XRMD, STR1, 1,        "<sp> path-name" },
        { "XRMD", XRMD, STR1, 1,        "<sp> path-name" },
        { "XRMD", XRMD, STR1, 1,        "<sp> path-name" },
+       { "PWD",  XPWD, ARGS, 1,        "(return current directory)" },
        { "XPWD", XPWD, ARGS, 1,        "(return current directory)" },
        { "XPWD", XPWD, ARGS, 1,        "(return current directory)" },
+       { "CDUP", XCUP, ARGS, 1,        "(change to parent directory)" },
        { "XCUP", XCUP, ARGS, 1,        "(change to parent directory)" },
        { "XCUP", XCUP, ARGS, 1,        "(change to parent directory)" },
+       { "STOU", STOU, STR1, 1,        "<sp> file-name" },
        { NULL,   0,    0,    0,        0 }
 };
 
        { NULL,   0,    0,    0,        0 }
 };
 
@@ -522,13 +561,29 @@ getline(s, n, iop)
        register FILE *iop;
 {
        register c;
        register FILE *iop;
 {
        register c;
-       register char *cs;
+       register char *cs, ch;
 
        cs = s;
 
        cs = s;
-       while (--n > 0 && (c = getc(iop)) >= 0) {
+       for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
+               *cs++ = tmpline[c];
+               if (tmpline[c] == '\n') {
+                       *cs++ = '\0';
+                       if (debug) {
+                               fprintf(stderr, "FTPD: command: %s", s);
+                       }
+                       tmpline[0] = '\0';
+                       return(s);
+               }
+               if (c == 0) {
+                       tmpline[0] = '\0';
+               }
+       }
+       while (--n > 0 && read(fileno(iop),&ch,1) >= 0) {
+               c = 0377 & ch;
                while (c == IAC) {
                while (c == IAC) {
-                       c = getc(iop);  /* skip command */
-                       c = getc(iop);  /* try next char */
+                       read(fileno(iop),&ch,1);        /* skip command */
+                       read(fileno(iop),&ch,1);        /* try next char */
+                       c = 0377 & ch;
                }
                *cs++ = c;
                if (c=='\n')
                }
                *cs++ = c;
                if (c=='\n')
@@ -566,7 +621,6 @@ toolong()
 
 yylex()
 {
 
 yylex()
 {
-       static char cbuf[512];
        static int cpos, state;
        register char *cp;
        register struct tab *p;
        static int cpos, state;
        register char *cp;
        register struct tab *p;
@@ -591,7 +645,10 @@ yylex()
                        if (index(cbuf, ' '))
                                cpos = index(cbuf, ' ') - cbuf;
                        else
                        if (index(cbuf, ' '))
                                cpos = index(cbuf, ' ') - cbuf;
                        else
+                               cpos = index(cbuf, '\n') - cbuf;
+                       if (cpos == 0) {
                                cpos = 4;
                                cpos = 4;
+                       }
                        c = cbuf[cpos];
                        cbuf[cpos] = '\0';
                        upper(cbuf);
                        c = cbuf[cpos];
                        cbuf[cpos] = '\0';
                        upper(cbuf);
index fb708d5..f17d867 100644 (file)
@@ -1,17 +1,17 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
 char copyright[] =
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+"@(#) Copyright (c) 1985 Regents of the University of California.\n\
  All rights reserved.\n";
 #endif not lint
 
 #ifndef lint
  All rights reserved.\n";
 #endif not lint
 
 #ifndef lint
-static char sccsid[] = "@(#)ftpd.c     5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)ftpd.c     5.2 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -28,6 +28,7 @@ static char sccsid[] = "@(#)ftpd.c    5.1 (Berkeley) %G%";
 
 #include <arpa/ftp.h>
 #include <arpa/inet.h>
 
 #include <arpa/ftp.h>
 #include <arpa/inet.h>
+#include <arpa/telnet.h>
 
 #include <stdio.h>
 #include <signal.h>
 
 #include <stdio.h>
 #include <signal.h>
@@ -35,6 +36,7 @@ static char sccsid[] = "@(#)ftpd.c    5.1 (Berkeley) %G%";
 #include <setjmp.h>
 #include <netdb.h>
 #include <errno.h>
 #include <setjmp.h>
 #include <netdb.h>
 #include <errno.h>
+#include <strings.h>
 
 /*
  * File containing login names
 
 /*
  * File containing login names
@@ -48,8 +50,10 @@ extern       char *sys_errlist[];
 extern char *crypt();
 extern char version[];
 extern char *home;             /* pointer to home directory for glob */
 extern char *crypt();
 extern char version[];
 extern char *home;             /* pointer to home directory for glob */
-extern FILE *popen(), *fopen();
+extern FILE *popen(), *fopen(), *freopen();
 extern int pclose(), fclose();
 extern int pclose(), fclose();
+extern char *getline();
+extern char cbuf[];
 
 struct sockaddr_in ctrl_addr;
 struct sockaddr_in data_source;
 
 struct sockaddr_in ctrl_addr;
 struct sockaddr_in data_source;
@@ -59,7 +63,7 @@ struct        sockaddr_in his_addr;
 struct hostent *hp;
 
 int    data;
 struct hostent *hp;
 
 int    data;
-jmp_buf        errcatch;
+jmp_buf        errcatch, urgcatch;
 int    logged_in;
 struct passwd *pw;
 int    debug;
 int    logged_in;
 struct passwd *pw;
 int    debug;
@@ -72,6 +76,10 @@ int  form;
 int    stru;                   /* avoid C keyword */
 int    mode;
 int    usedefault = 1;         /* for data transfers */
 int    stru;                   /* avoid C keyword */
 int    mode;
 int    usedefault = 1;         /* for data transfers */
+int    pdata;                  /* for passive mode */
+int    unique;
+int    transflag;
+char   tmpline[7];
 char   hostname[32];
 char   remotehost[32];
 
 char   hostname[32];
 char   remotehost[32];
 
@@ -88,6 +96,7 @@ int   swaitint = SWAITINT;
 
 int    lostconn();
 int    reapchild();
 
 int    lostconn();
 int    reapchild();
+int    myoob();
 FILE   *getdatasock(), *dataconn();
 
 main(argc, argv)
 FILE   *getdatasock(), *dataconn();
 
 main(argc, argv)
@@ -95,6 +104,7 @@ main(argc, argv)
        char *argv[];
 {
        int options = 0, addrlen;
        char *argv[];
 {
        int options = 0, addrlen;
+       long pgid;
        char *cp;
 
        addrlen = sizeof (his_addr);
        char *cp;
 
        addrlen = sizeof (his_addr);
@@ -126,6 +136,7 @@ main(argc, argv)
 
                case 'l':
                        logging = 1;
 
                case 'l':
                        logging = 1;
+                       (void) freopen("/tmp/ftplog", "a", stderr);
                        break;
 
                case 't':
                        break;
 
                case 't':
@@ -143,6 +154,13 @@ nextopt:
        }
        signal(SIGPIPE, lostconn);
        signal(SIGCHLD, SIG_IGN);
        }
        signal(SIGPIPE, lostconn);
        signal(SIGCHLD, SIG_IGN);
+       if (signal(SIGURG, myoob) < 0) {
+               perror("signal");
+       }
+       pgid = getpid();
+       if (ioctl(fileno(stdin), SIOCSPGRP, (char *) &pgid) < 0) {
+               perror("ioctl");
+       }
        dolog(&his_addr);
        /* do telnet option negotiation here */
        /*
        dolog(&his_addr);
        /* do telnet option negotiation here */
        /*
@@ -154,6 +172,7 @@ nextopt:
        form = FORM_N;
        stru = STRU_F;
        mode = MODE_S;
        form = FORM_N;
        stru = STRU_F;
        mode = MODE_S;
+       tmpline[0] = '\0';
        gethostname(hostname, sizeof (hostname));
        reply(220, "%s FTP server (%s) ready.",
                hostname, version);
        gethostname(hostname, sizeof (hostname));
        reply(220, "%s FTP server (%s) ready.",
                hostname, version);
@@ -259,7 +278,7 @@ retrieve(cmd, name)
 {
        FILE *fin, *dout;
        struct stat st;
 {
        FILE *fin, *dout;
        struct stat st;
-       int (*closefunc)();
+       int (*closefunc)(), tmp;
 
        if (cmd == 0) {
 #ifdef notdef
 
        if (cmd == 0) {
 #ifdef notdef
@@ -289,11 +308,15 @@ retrieve(cmd, name)
        dout = dataconn(name, st.st_size, "w");
        if (dout == NULL)
                goto done;
        dout = dataconn(name, st.st_size, "w");
        if (dout == NULL)
                goto done;
-       if (send_data(fin, dout) || ferror(dout))
+       if ((tmp = send_data(fin, dout)) > 0 || ferror(dout) > 0) {
                reply(550, "%s: %s.", name, sys_errlist[errno]);
                reply(550, "%s: %s.", name, sys_errlist[errno]);
-       else
+       }
+       else if (tmp == 0) {
                reply(226, "Transfer complete.");
                reply(226, "Transfer complete.");
-       fclose(dout), data = -1;
+       }
+       fclose(dout);
+       data = -1;
+       pdata = -1;
 done:
        (*closefunc)(fin);
 }
 done:
        (*closefunc)(fin);
 }
@@ -302,7 +325,8 @@ store(name, mode)
        char *name, *mode;
 {
        FILE *fout, *din;
        char *name, *mode;
 {
        FILE *fout, *din;
-       int (*closefunc)(), dochown = 0;
+       int (*closefunc)(), dochown = 0, tmp;
+       char *gunique(), *local;
 
 #ifdef notdef
        /* no remote command execution -- it's a security hole */
 
 #ifdef notdef
        /* no remote command execution -- it's a security hole */
@@ -313,25 +337,40 @@ store(name, mode)
        {
                struct stat st;
 
        {
                struct stat st;
 
-               if (stat(name, &st) < 0)
+               local = name;
+               if (stat(name, &st) < 0) {
                        dochown++;
                        dochown++;
-               fout = fopen(name, mode), closefunc = fclose;
+               }
+               else if (unique) {
+                       if ((local = gunique(name)) == NULL) {
+                               return;
+                       }
+                       dochown++;
+               }
+               fout = fopen(local, mode), closefunc = fclose;
        }
        if (fout == NULL) {
        }
        if (fout == NULL) {
-               reply(550, "%s: %s.", name, sys_errlist[errno]);
+               reply(550, "%s: %s.", local, sys_errlist[errno]);
                return;
        }
                return;
        }
-       din = dataconn(name, (off_t)-1, "r");
+       din = dataconn(local, (off_t)-1, "r");
        if (din == NULL)
                goto done;
        if (din == NULL)
                goto done;
-       if (receive_data(din, fout) || ferror(fout))
-               reply(550, "%s: %s.", name, sys_errlist[errno]);
-       else
+       if ((tmp = receive_data(din, fout)) > 0 || ferror(fout) > 0) {
+               reply(550, "%s: %s.", local, sys_errlist[errno]);
+       }
+       else if (tmp == 0 && !unique) {
                reply(226, "Transfer complete.");
                reply(226, "Transfer complete.");
-       fclose(din), data = -1;
+       }
+       else if (tmp == 0 && unique) {
+               reply(226, "Transfer complete (unique file name:%s).", local);
+       }
+       fclose(din);
+       data = -1;
+       pdata = -1;
 done:
        if (dochown)
 done:
        if (dochown)
-               (void) chown(name, pw->pw_uid, -1);
+               (void) chown(local, pw->pw_uid, -1);
        (*closefunc)(fout);
 }
 
        (*closefunc)(fout);
 }
 
@@ -376,6 +415,24 @@ dataconn(name, size, mode)
                sprintf (sizebuf, " (%ld bytes)", size);
        else
                (void) strcpy(sizebuf, "");
                sprintf (sizebuf, " (%ld bytes)", size);
        else
                (void) strcpy(sizebuf, "");
+       if (pdata > 0) {
+               struct sockaddr_in from;
+               int s, fromlen = sizeof(from);
+
+               s = accept(pdata, &from, &fromlen, 0);
+               if (s < 0) {
+                       reply(425, "Can't open data connection.");
+                       (void) close(pdata);
+                       pdata = -1;
+                       return(NULL);
+               }
+               (void) close(pdata);
+               pdata = s;
+               reply(150, "Openning data connection for %s (%s,%d)%s.",
+                    name, inet_ntoa(from.sin_addr.s_addr),
+                    ntohs(from.sin_port), sizebuf);
+               return(fdopen(pdata, mode));
+       }
        if (data >= 0) {
                reply(125, "Using existing data connection for %s%s.",
                    name, sizebuf);
        if (data >= 0) {
                reply(125, "Using existing data connection for %s%s.",
                    name, sizebuf);
@@ -397,7 +454,7 @@ dataconn(name, size, mode)
            name, inet_ntoa(data_dest.sin_addr.s_addr),
            ntohs(data_dest.sin_port), sizebuf);
        data = fileno(file);
            name, inet_ntoa(data_dest.sin_addr.s_addr),
            ntohs(data_dest.sin_port), sizebuf);
        data = fileno(file);
-       while (connect(data, &data_dest, sizeof (data_dest), 0) < 0) {
+       while (connect(data, &data_dest, sizeof (data_dest)) < 0) {
                if (errno == EADDRINUSE && retry < swaitmax) {
                        sleep(swaitint);
                        retry += swaitint;
                if (errno == EADDRINUSE && retry < swaitmax) {
                        sleep(swaitint);
                        retry += swaitint;
@@ -427,21 +484,30 @@ send_data(instr, outstr)
        int netfd, filefd, cnt;
        char buf[BUFSIZ];
 
        int netfd, filefd, cnt;
        char buf[BUFSIZ];
 
+       transflag++;
+       if (setjmp(urgcatch)) {
+               transflag = 0;
+               return(-1);
+       }
        switch (type) {
 
        case TYPE_A:
                while ((c = getc(instr)) != EOF) {
                        if (c == '\n') {
        switch (type) {
 
        case TYPE_A:
                while ((c = getc(instr)) != EOF) {
                        if (c == '\n') {
-                               if (ferror (outstr))
+                               if (ferror (outstr)) {
+                                       transflag = 0;
                                        return (1);
                                        return (1);
+                               }
                                putc('\r', outstr);
                        }
                        putc(c, outstr);
                                putc('\r', outstr);
                        }
                        putc(c, outstr);
-                       if (c == '\r')
-                               putc ('\0', outstr);
+               /*      if (c == '\r')                  */
+               /*              putc ('\0', outstr);    */
                }
                }
-               if (ferror (instr) || ferror (outstr))
+               transflag = 0;
+               if (ferror (instr) || ferror (outstr)) {
                        return (1);
                        return (1);
+               }
                return (0);
                
        case TYPE_I:
                return (0);
                
        case TYPE_I:
@@ -449,12 +515,17 @@ send_data(instr, outstr)
                netfd = fileno(outstr);
                filefd = fileno(instr);
 
                netfd = fileno(outstr);
                filefd = fileno(instr);
 
-               while ((cnt = read(filefd, buf, sizeof (buf))) > 0)
-                       if (write(netfd, buf, cnt) < 0)
+               while ((cnt = read(filefd, buf, sizeof (buf))) > 0) {
+                       if (write(netfd, buf, cnt) < 0) {
+                               transflag = 0;
                                return (1);
                                return (1);
+                       }
+               }
+               transflag = 0;
                return (cnt < 0);
        }
        reply(504,"Unimplemented TYPE %d in send_data", type);
                return (cnt < 0);
        }
        reply(504,"Unimplemented TYPE %d in send_data", type);
+       transflag = 0;
        return (1);
 }
 
        return (1);
 }
 
@@ -474,35 +545,49 @@ receive_data(instr, outstr)
        char buf[BUFSIZ];
 
 
        char buf[BUFSIZ];
 
 
+       transflag++;
+       if (setjmp(urgcatch)) {
+               transflag = 0;
+               return(-1);
+       }
        switch (type) {
 
        case TYPE_I:
        case TYPE_L:
        switch (type) {
 
        case TYPE_I:
        case TYPE_L:
-               while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0)
-                       if (write(fileno(outstr), buf, cnt) < 0)
+               while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
+                       if (write(fileno(outstr), buf, cnt) < 0) {
+                               transflag = 0;
                                return (1);
                                return (1);
+                       }
+               }
+               transflag = 0;
                return (cnt < 0);
 
        case TYPE_E:
                reply(504, "TYPE E not implemented.");
                return (cnt < 0);
 
        case TYPE_E:
                reply(504, "TYPE E not implemented.");
+               transflag = 0;
                return (1);
 
        case TYPE_A:
                while ((c = getc(instr)) != EOF) {
                        if (c == '\r') {
                return (1);
 
        case TYPE_A:
                while ((c = getc(instr)) != EOF) {
                        if (c == '\r') {
-                               if (ferror (outstr))
+                               if (ferror (outstr)) {
+                                       transflag = 0;
                                        return (1);
                                        return (1);
+                               }
                                if ((c = getc(instr)) != '\n')
                                        putc ('\r', outstr);
                                if ((c = getc(instr)) != '\n')
                                        putc ('\r', outstr);
-                               if (c == '\0')
-                                       continue;
+                       /*      if (c == '\0')                  */
+                       /*              continue;               */
                        }
                        putc (c, outstr);
                }
                        }
                        putc (c, outstr);
                }
+               transflag = 0;
                if (ferror (instr) || ferror (outstr))
                        return (1);
                return (0);
        }
                if (ferror (instr) || ferror (outstr))
                        return (1);
                return (0);
        }
+       transflag = 0;
        fatal("Unknown type in receive_data.");
        /*NOTREACHED*/
 }
        fatal("Unknown type in receive_data.");
        /*NOTREACHED*/
 }
@@ -559,7 +644,7 @@ replystr(s)
 ack(s)
        char *s;
 {
 ack(s)
        char *s;
 {
-       reply(200, "%s command okay.", s);
+       reply(200, "%s command successful.", s);
 }
 
 nack(s)
 }
 
 nack(s)
@@ -570,7 +655,11 @@ nack(s)
 
 yyerror()
 {
 
 yyerror()
 {
-       reply(500, "Command not understood.");
+       char *cp;
+
+       cp = index(cbuf,'\n');
+       *cp = '\0';
+       reply(500, "'%s': command not understood.",cbuf);
 }
 
 delete(name)
 }
 
 delete(name)
@@ -878,3 +967,164 @@ checkuser(name)
        fclose(fd);
        return (!found);
 }
        fclose(fd);
        return (!found);
 }
+
+myoob()
+{
+       char mark, *cp;
+       int aflag = 0, count = 0, iacflag = 0, c;
+
+       if (!transflag) {
+               for (;;) {
+                       if (ioctl(fileno(stdin), SIOCATMARK, &mark) < 0) {
+                               perror("ioctl");
+                               break;
+                       }
+                       if (mark) {
+                               break;
+                       }
+                       read(fileno(stdin), &mark, 1);
+                       c = 0377 & mark;
+               }
+               recv(fileno(stdin), &mark, 1, MSG_OOB);
+               c = 0377 & mark;
+               read(fileno(stdin), &mark, 1);
+               return;
+       }
+       for (;;) {
+               if (ioctl(fileno(stdin), SIOCATMARK, &mark) < 0) {
+                       perror("ioctl");
+                       break;
+               }
+               if (mark) {
+                       break;
+               }
+               read(fileno(stdin), &mark, 1);
+               c = 0377 & mark;
+               if (c == IAC) {
+                       aflag++;
+               }
+               else if (c == IP) {
+                       aflag++;
+               }
+       }
+       recv(fileno(stdin), &mark, 1, MSG_OOB);
+       c = 0377 & mark;
+       if (c == IAC) {
+               aflag++;
+       }
+       read(fileno(stdin), &mark, 1);
+       c = 0377 & mark;
+       if (c == DM) {
+               aflag++;
+       }
+       if (aflag != 4) {
+               return;
+       }
+       cp = tmpline;
+       (void) getline(cp, 7, stdin);
+       upper(cp);
+       if (strcmp(cp, "ABOR\r\n")) {
+               return;
+       }
+       tmpline[0] = '\0';
+       reply(426,"Transfer aborted. Data connection closed.");
+       reply(226,"Abort successful");
+       longjmp(urgcatch, 1);
+}
+
+passive()
+{
+       int len;
+       struct sockaddr_in tmp;
+       register char *p, *a;
+
+       pdata = socket(AF_INET, SOCK_STREAM, 0);
+       if (pdata < 0) {
+               reply(451, "Can't open passive connection");
+               return;
+       }
+       tmp = ctrl_addr;
+       tmp.sin_port = 0;
+       seteuid(0);
+       if (bind(pdata, (char *) &tmp, sizeof(tmp), 0) < 0) {
+               seteuid(pw->pw_uid);
+               (void) close(pdata);
+               pdata = -1;
+               reply(451, "Can't open passive connection");
+               return;
+       }
+       seteuid(pw->pw_uid);
+       len = sizeof(tmp);
+       if (getsockname(pdata, (char *) &tmp, &len) < 0) {
+               (void) close(pdata);
+               pdata = -1;
+               reply(451, "Can't open passive connection");
+               return;
+       }
+       if (listen(pdata, 1) < 0) {
+               (void) close(pdata);
+               pdata = -1;
+               reply(451, "Can't open passive connection");
+               return;
+       }
+       a = (char *) &tmp.sin_addr;
+       p = (char *) &tmp.sin_port;
+
+#define UC(b) (((int) b) & 0xff)
+
+       reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
+               UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+}
+
+char *
+gunique(local)
+       char *local;
+{
+       static char new[MAXPATHLEN];
+       char *cp = rindex(local, '/');
+       int d, count=0;
+       char ext = '1';
+
+       if (cp) {
+               *cp = '\0';
+       }
+       d = access(cp ? local : ".", 2);
+       if (cp) {
+               *cp = '/';
+       }
+       if (d < 0) {
+               perror(local);
+               return((char *) 0);
+       }
+       (void) strcpy(new, local);
+       cp = new + strlen(new);
+       *cp++ = '.';
+       while (!d) {
+               if (++count == 100) {
+                       reply(451, "Unique file name not cannot be created.");
+                       return((char *) 0);
+               }
+               *cp++ = ext;
+               *cp = '\0';
+               if (ext == '9') {
+                       ext = '0';
+               }
+               else {
+                       ext++;
+               }
+               if ((d = access(new, 0)) < 0) {
+                       break;
+               }
+               if (ext != '0') {
+                       cp--;
+               }
+               else if (*(cp - 2) == '.') {
+                       *(cp - 1) = '1';
+               }
+               else {
+                       *(cp - 2) = *(cp - 2) + 1;
+                       cp--;
+               }
+       }
+       return(new);
+}