home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre1.z / postgre1 / test / postfs.usr.bin / in.ftpd.clean / ftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  32.5 KB  |  1,508 lines

  1. /*
  2.  * Copyright (c) 1985, 1988, 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)ftpd.c    5.40 (Berkeley) 7/2/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * FTP server.
  46.  */
  47. #include <sys/param.h>
  48. #include "tmp/libpq-fs.h"
  49. #include "catalog/pg_lobj.h"
  50. #include <sys/ioctl.h>
  51. #include <sys/socket.h>
  52. #include <sys/wait.h>
  53.  
  54. #include <netinet/in.h>
  55. #include <netinet/in_systm.h>
  56. #include <netinet/ip.h>
  57.  
  58. #define    FTP_NAMES
  59. #include <arpa/ftp.h>
  60. #include <arpa/inet.h>
  61. #include <arpa/telnet.h>
  62.  
  63. #include <signal.h>
  64. /*#include <dirent.h>*/
  65. #include <fcntl.h>
  66. #include <time.h>
  67. #include <pwd.h>
  68. #include <setjmp.h>
  69. #include <netdb.h>
  70. #include <errno.h>
  71. #include <syslog.h>
  72. #include <varargs.h>
  73. #include <unistd.h>
  74. #include <stdio.h>
  75. #include <ctype.h>
  76. /*#include <stdlib.h>*/
  77. #include <string.h>
  78. #include "pathnames.h"
  79.  
  80. /*
  81.  * File containing login names
  82.  * NOT to be used on this machine.
  83.  * Commonly used to disallow uucp.
  84.  */
  85. extern    int errno;
  86. extern    char *crypt();
  87. extern    char version[];
  88. extern    char *home;        /* pointer to home directory for glob */
  89. extern    FILE *ftpd_popen(), *fopen(), *freopen();
  90. extern    int  ftpd_pclose(), fclose();
  91. extern    char *getline();
  92. extern    char cbuf[];
  93. extern    off_t restart_point;
  94.  
  95. struct    sockaddr_in ctrl_addr;
  96. struct    sockaddr_in data_source;
  97. struct    sockaddr_in data_dest;
  98. struct    sockaddr_in his_addr;
  99. struct    sockaddr_in pasv_addr;
  100.  
  101. int    data;
  102. jmp_buf    errcatch, urgcatch;
  103. int    logged_in;
  104. struct    passwd *pw;
  105. int    debug;
  106. int    timeout = 900;    /* timeout after 15 minutes of inactivity */
  107. int    maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
  108. int    logging;
  109. int    guest;
  110. int    type;
  111. int    formx;
  112. int    stru;            /* avoid C keyword */
  113. int    mode;
  114. int    usedefault = 1;        /* for data transfers */
  115. int    pdata = -1;        /* for passive mode */
  116. int    transflag;
  117. off_t    file_size;
  118. off_t    byte_count;
  119. #if !defined(CMASK) || CMASK == 0
  120. #undef CMASK
  121. #define CMASK 027
  122. #endif
  123. int    defumask = CMASK;        /* default umask value */
  124. char    tmpline[7];
  125. char    hostname[MAXHOSTNAMELEN];
  126. char    remotehost[MAXHOSTNAMELEN];
  127. char    USER[128];
  128.  
  129. /*
  130.  * Timeout intervals for retrying connections
  131.  * to hosts that don't accept PORT cmds.  This
  132.  * is a kludge, but given the problems with TCP...
  133.  */
  134. #define    SWAITMAX    90    /* wait at most 90 seconds */
  135. #define    SWAITINT    5    /* interval between retries */
  136.  
  137. int    swaitmax = SWAITMAX;
  138. int    swaitint = SWAITINT;
  139.  
  140. void    lostconn(), myoob();
  141. FILE    *getdatasock(), *dataconn();
  142.  
  143. #ifdef SETPROCTITLE
  144. char    **Argv = NULL;        /* pointer to argument vector */
  145. char    *LastArgv = NULL;    /* end of argv */
  146. char    proctitle[BUFSIZ];    /* initial part of title */
  147. #endif /* SETPROCTITLE */
  148.  
  149. main(argc, argv, envp)
  150.     int argc;
  151.     char *argv[];
  152.     char **envp;
  153. {
  154.     int addrlen, on = 1, tos;
  155.     char *cp;
  156.  
  157.     /*
  158.      * LOG_NDELAY sets up the logging connection immediately,
  159.      * necessary for anonymous ftp's that chroot and can't do it later.
  160.      */
  161.     openlog("ftpd", LOG_PID /*| LOG_NDELAY*/, LOG_INFO);
  162.  
  163.     addrlen = sizeof (his_addr);
  164.     if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
  165.         syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
  166.         exit(1);
  167.     }
  168.     addrlen = sizeof (ctrl_addr);
  169.     if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
  170.         syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
  171.         exit(1);
  172.     }
  173. #ifdef IP_TOS
  174.     tos = IPTOS_LOWDELAY;
  175.     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
  176.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  177. #endif
  178.     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  179.     debug = 0;
  180. #ifdef SETPROCTITLE
  181.     /*
  182.      *  Save start and extent of argv for setproctitle.
  183.      */
  184.     Argv = argv;
  185.     while (*envp)
  186.         envp++;
  187.     LastArgv = envp[-1] + strlen(envp[-1]);
  188. #endif /* SETPROCTITLE */
  189.  
  190.     argc--, argv++;
  191.     while (argc > 0 && *argv[0] == '-') {
  192.         for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
  193.  
  194.         case 'v':
  195.             debug = 1;
  196.             break;
  197.  
  198.         case 'd':
  199.             debug = 1;
  200.             break;
  201.  
  202.         case 'l':
  203.             logging = 1;
  204.             break;
  205.  
  206.         case 't':
  207.             timeout = atoi(++cp);
  208.             if (maxtimeout < timeout)
  209.                 maxtimeout = timeout;
  210.             goto nextopt;
  211.  
  212.         case 'T':
  213.             maxtimeout = atoi(++cp);
  214.             if (timeout > maxtimeout)
  215.                 timeout = maxtimeout;
  216.             goto nextopt;
  217.  
  218.         case 'u':
  219.             {
  220.             int val = 0;
  221.  
  222.             while (*++cp && *cp >= '0' && *cp <= '9')
  223.                 val = val*8 + *cp - '0';
  224.             if (*cp)
  225.                 fprintf(stderr, "ftpd: Bad value for -u\n");
  226.             else
  227.                 defumask = val;
  228.             goto nextopt;
  229.             }
  230.  
  231.         default:
  232.             fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
  233.                  *cp);
  234.             break;
  235.         }
  236. nextopt:
  237.         argc--, argv++;
  238.     }
  239.     (void) freopen(_PATH_DEVNULL, "w", stderr);
  240.     (void) signal(SIGPIPE, lostconn);
  241.     (void) signal(SIGCHLD, SIG_IGN);
  242.     if ((int)signal(SIGURG, myoob) < 0)
  243.         syslog(LOG_ERR, "signal: %m");
  244.  
  245.     /* Try to handle urgent data inline */
  246. #ifdef SO_OOBINLINE
  247.     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
  248.         syslog(LOG_ERR, "setsockopt: %m");
  249. #endif
  250.  
  251. #ifdef    F_SETOWN
  252.     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  253.         syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  254. #endif
  255.     dolog(&his_addr);
  256.     /*
  257.      * Set up default state
  258.      */
  259.     data = -1;
  260.     type = TYPE_A;
  261.     formx = FORM_N;
  262.     stru = STRU_F;
  263.     mode = MODE_S;
  264.     tmpline[0] = '\0';
  265.     (void) gethostname(hostname, sizeof (hostname));
  266.     reply(220, "%s FTP server (%s) ready.", hostname, version);
  267.     (void) setjmp(errcatch);
  268.     for (;;)
  269.         (void) yyparse();
  270.     /* NOTREACHED */
  271. }
  272.  
  273. void
  274. lostconn()
  275. {
  276.     if (debug)
  277.         syslog(LOG_DEBUG, "lost connection");
  278.     dologout(-1);
  279. }
  280.  
  281. static char ttyline[20];
  282.  
  283. /*
  284.  * Helper function for sgetpwnam().
  285.  */
  286. char *
  287. sgetsave(s)
  288.     char *s;
  289. {
  290.     char *newx = malloc((unsigned) strlen(s) + 1);
  291.  
  292.     if (newx == NULL) {
  293.         perror_reply(421, "Local resource failure: malloc");
  294.         dologout(1);
  295.         /* NOTREACHED */
  296.     }
  297.     (void) strcpy(newx, s);
  298.     return (newx);
  299. }
  300.  
  301. /*
  302.  * Save the result of a getpwnam.  Used for USER command, since
  303.  * the data returned must not be clobbered by any other command
  304.  * (e.g., globbing).
  305.  */
  306. struct passwd *
  307. sgetpwnam(name)
  308.     char *name;
  309. {
  310.     static struct passwd save;
  311.     register struct passwd *p;
  312.     char *sgetsave();
  313.  
  314.     if ((p = getpwnam(name)) == NULL)
  315.         return (p);
  316.     if (save.pw_name) {
  317.         free(save.pw_name);
  318.         free(save.pw_passwd);
  319.         free(save.pw_gecos);
  320.         free(save.pw_dir);
  321.         free(save.pw_shell);
  322.     }
  323.     save = *p;
  324.     save.pw_name = sgetsave(p->pw_name);
  325.     save.pw_passwd = sgetsave(p->pw_passwd);
  326.     save.pw_gecos = sgetsave(p->pw_gecos);
  327.     save.pw_dir = sgetsave(p->pw_dir);
  328.     save.pw_shell = sgetsave(p->pw_shell);
  329.     return (&save);
  330. }
  331.  
  332. int login_attempts;        /* number of failed login attempts */
  333. int askpasswd;            /* had user command, ask for passwd */
  334.  
  335. /*
  336.  * USER command.
  337.  * Sets global passwd pointer pw if named account exists and is acceptable;
  338.  * sets askpasswd if a PASS command is expected.  If logged in previously,
  339.  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
  340.  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
  341.  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
  342.  * requesting login privileges.  Disallow anyone who does not have a standard
  343.  * shell as returned by getusershell().  Disallow anyone mentioned in the file
  344.  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
  345.  */
  346. user(name)
  347.     char *name;
  348. {
  349.     register char *cp;
  350.     char *shell;
  351.     char *getusershell();
  352.  
  353.     if (logged_in) {
  354.         if (guest) {
  355.             reply(530, "Can't change user from guest login.");
  356.             return;
  357.         }
  358.         end_login();
  359.     }
  360.  
  361.     guest = 0;
  362.     if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
  363.         if (checkuser("ftp") || checkuser("anonymous"))
  364.             reply(530, "User %s access denied.", name);
  365.         else if ((pw = sgetpwnam("ftp")) != NULL) {
  366.             guest = 1;
  367.             askpasswd = 1;
  368.             reply(331, "Guest login ok, send ident as password.");
  369.         } else
  370.             reply(530, "User %s unknown.", name);
  371.         return;
  372.     }
  373.     if (pw = sgetpwnam(name)) {
  374. #if 0
  375.         if ((shell = pw->pw_shell) == NULL || *shell == 0)
  376.             shell = _PATH_BSHELL;
  377.         while ((cp = getusershell()) != NULL)
  378.             if (strcmp(cp, shell) == 0)
  379.                 break;
  380.         endusershell();
  381. #endif
  382.         if (/*cp == NULL || */ checkuser(name)) {
  383.             reply(530, "User %s access denied.", name);
  384.             if (logging)
  385.                 syslog(LOG_NOTICE,
  386.                     "FTP LOGIN REFUSED FROM %s, %s",
  387.                     remotehost, name);
  388.             pw = (struct passwd *) NULL;
  389.             return;
  390.         }
  391.     }
  392.     reply(331, "Password required for %s.", name);
  393.     askpasswd = 1;
  394.     /*
  395.      * Delay before reading passwd after first failed
  396.      * attempt to slow down passwd-guessing programs.
  397.      */
  398.     if (login_attempts)
  399.         sleep((unsigned) login_attempts);
  400. }
  401.  
  402. /*
  403.  * Check if a user is in the file _PATH_FTPUSERS
  404.  */
  405. checkuser(name)
  406.     char *name;
  407. {
  408.     register FILE *fd;
  409.     register char *p;
  410.     char line[BUFSIZ];
  411.  
  412.     if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
  413.         while (fgets(line, sizeof(line), fd) != NULL)
  414.             if ((p = index(line, '\n')) != NULL) {
  415.                 *p = '\0';
  416.                 if (line[0] == '#')
  417.                     continue;
  418.                 if (strcmp(line, name) == 0)
  419.                     return (1);
  420.             }
  421.         (void) fclose(fd);
  422.     }
  423.     return (0);
  424. }
  425.  
  426. /*
  427.  * Terminate login as previous user, if any, resetting state;
  428.  * used when USER command is given or login fails.
  429.  */
  430. end_login()
  431. {
  432.  
  433.     (void) seteuid((uid_t)0);
  434.     if (logged_in)
  435.         logwtmp(ttyline, "", "");
  436.     pw = NULL;
  437.     logged_in = 0;
  438.     guest = 0;
  439. }
  440.  
  441. pass(passwd)
  442.     char *passwd;
  443. {
  444.     char *xpasswd, *salt;
  445.  
  446.     if (logged_in || askpasswd == 0) {
  447.         reply(503, "Login with USER first.");
  448.         return;
  449.     }
  450.     askpasswd = 0;
  451.     if (!guest) {        /* "ftp" is only account allowed no password */
  452.         if (pw == NULL)
  453.             salt = "xx";
  454.         else
  455.             salt = pw->pw_passwd;
  456.         xpasswd = crypt(passwd, salt);
  457.         /* The strcmp does not catch null passwords! */
  458.         if (pw == NULL || *pw->pw_passwd == '\0' ||
  459.             strcmp(xpasswd, pw->pw_passwd)) {
  460.             reply(530, "Login incorrect.");
  461.             pw = NULL;
  462.             if (login_attempts++ >= 5) {
  463.                 syslog(LOG_NOTICE,
  464.                     "repeated login failures from %s",
  465.                     remotehost);
  466.                 exit(0);
  467.             }
  468.             return;
  469.         }
  470.     }
  471.     login_attempts = 0;        /* this time successful */
  472.     (void) setegid((gid_t)pw->pw_gid);
  473.     (void) initgroups(pw->pw_name, pw->pw_gid);
  474.  
  475.     /* open wtmp before chroot */
  476.     (void)sprintf(ttyline, "ftp%d", getpid());
  477.     logwtmp(ttyline, pw->pw_name, remotehost);
  478.     logged_in = 1;
  479.  
  480.     if (guest) {
  481.         /*
  482.          * We MUST do a chdir() after the chroot. Otherwise
  483.          * the old current directory will be accessible as "."
  484.          * outside the newx root!
  485.          */
  486.         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  487.             reply(550, "Can't set guest privileges.");
  488.             goto bad;
  489.         }
  490.     } else if (chdir(pw->pw_dir) < 0) {
  491.         if (chdir("/") < 0) {
  492.             reply(530, "User %s: can't change directory to %s.",
  493.                 pw->pw_name, pw->pw_dir);
  494.             goto bad;
  495.         } else
  496.             lreply(230, "No directory! Logging in with home=/");
  497.     }
  498.     if (seteuid((uid_t)pw->pw_uid) < 0) {
  499.         reply(550, "Can't set uid.");
  500.         goto bad;
  501.     }
  502.     if (guest) {
  503.         reply(230, "-Guest login ok, access restrictions apply.");
  504. #ifdef SETPROCTITLE
  505.         sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
  506.             sizeof(proctitle) - sizeof(remotehost) -
  507.             sizeof(": anonymous/"), passwd);
  508.         setproctitle(proctitle);
  509. #endif /* SETPROCTITLE */
  510.         if (logging)
  511.             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
  512.                 remotehost, passwd);
  513.     } else {
  514.         reply(230, "-User %s logged in.", pw->pw_name);
  515. #ifdef SETPROCTITLE
  516.         sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
  517.         setproctitle(proctitle);
  518. #endif /* SETPROCTITLE */
  519.         if (logging)
  520.             syslog(LOG_INFO, "FTP LOGIN FROM %s, %s",
  521.                 remotehost, pw->pw_name);
  522.     }
  523.     home = pw->pw_dir;        /* home dir for globbing */
  524.         reply(230,"Setting PQ db to %s",pw->pw_name);
  525.         sprintf(USER,"USER=%s",pw->pw_name);
  526.         putenv(USER);
  527.         PQsetdb(pw->pw_name);
  528.  
  529.     (void) umask(defumask);
  530.     return;
  531. bad:
  532.     /* Forget all about it... */
  533.     end_login();
  534. }
  535.  
  536. retrieve(cmd, name)
  537.     char *cmd, *name;
  538. {
  539.     FILE *fin, *dout;
  540.     struct pgstat st;
  541.     int (*closefunc)();
  542.  
  543.     if (cmd == 0) {
  544.         fin = (FILE *)p_open(name, O_RDONLY), closefunc = p_close;
  545.         st.st_size = 0;
  546.     } else {
  547.         char line[BUFSIZ];
  548.  
  549.         (void) sprintf(line, cmd, name), name = line;
  550.         fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
  551.         st.st_size = -1;
  552. /*
  553.         st.st_blksize = BUFSIZ;*/
  554.     }
  555.     if (fin == NULL && cmd != 0) {
  556. /*        if (errno != 0)
  557.             perror_reply(550, name);*/
  558.         return;
  559.     }
  560.     if (cmd == 0 &&
  561.         (p_stat(name, &st) < 0 || (st.st_mode&_S_IFMT) != S_IFREG)) {
  562.         reply(550, "%s: not a plain file.", name);
  563.         goto done;
  564.     }
  565.     if (restart_point) {
  566.         if (type == TYPE_A) {
  567. #if 0
  568.             register int i, n, c;
  569.  
  570.             n = restart_point;
  571.             i = 0;
  572.             while (i++ < n) {
  573.                 if ((c=getc(fin)) == EOF) {
  574.                     perror_reply(550, name);
  575.                     goto done;
  576.                 }
  577.                 if (c == '\n')
  578.                     i++;
  579.             }    
  580. #endif
  581.             reply(550, "TYPE A not supported");
  582.         } else if (lseek(cmd==0?fin:fileno(((FILE *)fin)), restart_point, L_SET) < 0) {
  583.             perror_reply(550, name);
  584.             goto done;
  585.         }
  586.     }
  587.     dout = dataconn(name, st.st_size, "w");
  588.     if (dout == NULL)
  589.         goto done;
  590.     send_data(fin, dout, BUFSIZ /*st.st_blksize*/,cmd);
  591.     (void) fclose(dout);
  592.     data = -1;
  593.     pdata = -1;
  594. done:
  595.     (*closefunc)(fin);
  596. }
  597.  
  598. /* XXX: stream i/o doesn't work */
  599.  
  600. store(name, mode, unique)
  601.     char *name, *mode;
  602.     int unique;
  603. {
  604.     int fout;
  605.     FILE *din;
  606.     struct pgstat st;
  607.     int (*closefunc)();
  608.     char *gunique();
  609.  
  610.     if (unique && p_stat(name, &st) == 0 &&
  611.         (name = gunique(name)) == NULL)
  612.         return;
  613.  
  614.     if (restart_point)
  615.         mode = "r+w";
  616.  
  617.     fout = p_open(name, O_RDWR);
  618.     closefunc = p_close;
  619.     if (fout == NULL) {
  620.         perror_reply(553, name);
  621.         return;
  622.     }
  623.     if (restart_point) {
  624.         if (type == TYPE_A) {
  625. #if postgresnoascii
  626.             register int i, n, c;
  627.  
  628.             n = restart_point;
  629.             i = 0;
  630.             while (i++ < n) {
  631.                 if ((c=getc(fout)) == EOF) {
  632.                     perror_reply(550, name);
  633.                     goto done;
  634.                 }
  635.                 if (c == '\n')
  636.                     i++;
  637.             }    
  638.             /*
  639.              * We must do this seek to "current" position
  640.              * because we are changing from reading to
  641.              * writing.
  642.              */
  643.             if (fseek(fout, 0L, L_INCR) < 0) {
  644.                 perror_reply(550, name);
  645.                 goto done;
  646.             }
  647. #endif
  648.             perror_reply(550,"TYPE A unsupported in postgres");
  649.         } else if (lseek(fout, restart_point, L_SET) < 0) {
  650.             perror_reply(550, name);
  651.             goto done;
  652.         }
  653.     }
  654.     din = dataconn(name, (off_t)-1, "r");
  655.     if (din == NULL)
  656.         goto done;
  657.     if (receive_data(din, fout) == 0) {
  658.         if (unique)
  659.             reply(226, "Transfer complete (unique file name:%s).",
  660.                 name);
  661.         else
  662.             reply(226, "Transfer complete.");
  663.     }
  664.     (void) fclose(din);
  665.     data = -1;
  666.     pdata = -1;
  667. done:
  668.     (*closefunc)(fout);
  669. }
  670.  
  671. FILE *
  672. getdatasock(mode)
  673.     char *mode;
  674. {
  675.     int s, on = 1, tries;
  676.  
  677.     if (data >= 0)
  678.         return (fdopen(data, mode));
  679.     (void) seteuid((uid_t)0);
  680.     s = socket(AF_INET, SOCK_STREAM, 0);
  681.     if (s < 0)
  682.         goto bad;
  683.     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  684.         (char *) &on, sizeof (on)) < 0)
  685.         goto bad;
  686.     /* anchor socket to avoid multi-homing problems */
  687.     data_source.sin_family = AF_INET;
  688.     data_source.sin_addr = ctrl_addr.sin_addr;
  689.     for (tries = 1; ; tries++) {
  690.         if (bind(s, (struct sockaddr *)&data_source,
  691.             sizeof (data_source)) >= 0)
  692.             break;
  693.         if (errno != EADDRINUSE || tries > 10)
  694.             goto bad;
  695.         sleep(tries);
  696.     }
  697.     (void) seteuid((uid_t)pw->pw_uid);
  698. #ifdef IP_TOS
  699.     on = IPTOS_THROUGHPUT;
  700.     if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
  701.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  702. #endif
  703.     return (fdopen(s, mode));
  704. bad:
  705.     (void) seteuid((uid_t)pw->pw_uid);
  706.     (void) close(s);
  707.     return (NULL);
  708. }
  709.  
  710. FILE *
  711. dataconn(name, size, mode)
  712.     char *name;
  713.     off_t size;
  714.     char *mode;
  715. {
  716.     char sizebuf[32];
  717.     FILE *file;
  718.     int retry = 0, tos;
  719.  
  720.     file_size = size;
  721.     byte_count = 0;
  722.     if (size != (off_t) -1)
  723.         (void) sprintf (sizebuf, " (%ld bytes)", size);
  724.     else
  725.         (void) strcpy(sizebuf, "");
  726.     if (pdata >= 0) {
  727.         struct sockaddr_in from;
  728.         int s, fromlen = sizeof(from);
  729.  
  730.         s = accept(pdata, (struct sockaddr *)&from, &fromlen);
  731.         if (s < 0) {
  732.             reply(425, "Can't open data connection.");
  733.             (void) close(pdata);
  734.             pdata = -1;
  735.             return(NULL);
  736.         }
  737.         (void) close(pdata);
  738.         pdata = s;
  739. #ifdef IP_TOS
  740.         tos = IPTOS_LOWDELAY;
  741.         (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
  742.             sizeof(int));
  743. #endif
  744.         reply(150, "Opening %s mode data connection for %s%s.",
  745.              type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  746.         return(fdopen(pdata, mode));
  747.     }
  748.     if (data >= 0) {
  749.         reply(125, "Using existing data connection for %s%s.",
  750.             name, sizebuf);
  751.         usedefault = 1;
  752.         return (fdopen(data, mode));
  753.     }
  754.     if (usedefault)
  755.         data_dest = his_addr;
  756.     usedefault = 1;
  757.     file = getdatasock(mode);
  758.     if (file == NULL) {
  759.         reply(425, "Can't create data socket (%s,%d): %s.",
  760.             inet_ntoa(data_source.sin_addr),
  761.             ntohs(data_source.sin_port), strerror(errno));
  762.         return (NULL);
  763.     }
  764.     data = fileno(file);
  765.     while (connect(data, (struct sockaddr *)&data_dest,
  766.         sizeof (data_dest)) < 0) {
  767.         if (errno == EADDRINUSE && retry < swaitmax) {
  768.             sleep((unsigned) swaitint);
  769.             retry += swaitint;
  770.             continue;
  771.         }
  772.         perror_reply(425, "Can't build data connection");
  773.         (void) fclose(file);
  774.         data = -1;
  775.         return (NULL);
  776.     }
  777.     reply(150, "Opening %s mode data connection for %s%s.",
  778.          type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  779.     return (file);
  780. }
  781.  
  782. /*
  783.  * Tranfer the contents of "instr" to
  784.  * "outstr" peer using the appropriate
  785.  * encapsulation of the data subject
  786.  * to Mode, Structure, and Type.
  787.  *
  788.  * NB: Form isn't handled.
  789.  */
  790. send_data(instr, outstr, blksize, cmd)
  791.     int instr;
  792.      FILE  *outstr;
  793.     off_t blksize;
  794.      int cmd;  /* 0 if outstr is binary file descriptor */
  795. {
  796.     register int c, cnt;
  797.     register char *buf;
  798.     int netfd, filefd;
  799.  
  800.     transflag++;
  801.     if (setjmp(urgcatch)) {
  802.         transflag = 0;
  803.         return;
  804.     }
  805.     switch (type) {
  806.  
  807.     case TYPE_A:
  808.         if (cmd == 0) {
  809.         reply(550,"TYPE A not supported");
  810.         return;
  811.         } else {
  812.         while ((c = getc(((FILE *)instr))) != EOF) {
  813.             byte_count++;
  814.             if (c == '\n') {
  815.                 if (ferror(outstr))
  816.                     goto data_err;
  817.                 (void) putc('\r', outstr);
  818.             }
  819.             (void) putc(c, outstr);
  820.         }
  821.         fflush(outstr);
  822.         transflag = 0;
  823.         if (ferror(((FILE *)instr)))
  824.             goto file_err;
  825.         if (ferror(outstr))
  826.             goto data_err;
  827.         reply(226, "Transfer complete.");
  828.         return;
  829.         }
  830.     case TYPE_I:
  831.     case TYPE_L:
  832.         if ((buf = malloc((u_int)blksize)) == NULL) {
  833.             transflag = 0;
  834.             perror_reply(451, "Local resource failure: malloc");
  835.             return;
  836.         }
  837.         netfd = fileno(outstr);
  838.         filefd = instr;
  839.         while ((cnt = p_read(filefd, buf, (u_int)blksize)) > 0 &&
  840.             write(netfd, buf, cnt) == cnt)
  841.             byte_count += cnt;
  842.         transflag = 0;
  843.         (void)free(buf);
  844.         if (cnt != 0) {
  845.             if (cnt < 0)
  846.                 goto file_err;
  847.             goto data_err;
  848.         }
  849.         reply(226, "Transfer complete.");
  850.         return;
  851.     default:
  852.         transflag = 0;
  853.         reply(550, "Unimplemented TYPE %d in send_data", type);
  854.         return;
  855.     }
  856.  
  857. data_err:
  858.     transflag = 0;
  859.     perror_reply(426, "Data connection");
  860.     return;
  861.  
  862. file_err:
  863.     transflag = 0;
  864.     perror_reply(551, "Error on input file");
  865. }
  866.  
  867. /*
  868.  * Transfer data from peer to
  869.  * "outstr" using the appropriate
  870.  * encapulation of the data subject
  871.  * to Mode, Structure, and Type.
  872.  *
  873.  * N.B.: Form isn't handled.
  874.  */
  875. receive_data(instr, outstr)
  876.     FILE *instr;
  877.      int outstr;
  878. {
  879.     register int c;
  880.     int cnt, bare_lfs = 0;
  881.     char buf[BUFSIZ];
  882.  
  883.     transflag++;
  884.     if (setjmp(urgcatch)) {
  885.         transflag = 0;
  886.         return (-1);
  887.     }
  888.     switch (type) {
  889.  
  890.     case TYPE_I:
  891.     case TYPE_L:
  892.         while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
  893.             if (p_write(outstr, buf, cnt) != cnt)
  894.                 goto file_err;
  895.             byte_count += cnt;
  896.         }
  897.         if (cnt < 0)
  898.             goto data_err;
  899.         transflag = 0;
  900.         return (0);
  901.  
  902.     case TYPE_E:
  903.         reply(553, "TYPE E not implemented.");
  904.         transflag = 0;
  905.         return (-1);
  906.  
  907.     case TYPE_A:
  908.         reply(553,"TYPE A not implemented.");
  909.         return -1;
  910. #if 0
  911.         while ((c = getc(instr)) != EOF) {
  912.             byte_count++;
  913.             if (c == '\n')
  914.                 bare_lfs++;
  915.             while (c == '\r') {
  916.                 if (p_ferror(outstr))
  917.                     goto data_err;
  918.                 if ((c = getc(instr)) != '\n') {
  919.                     (void) putc ('\r', outstr);
  920.                     if (c == '\0' || c == EOF)
  921.                         goto contin2;
  922.                 }
  923.             }
  924.             (void) putc(c, outstr);
  925.     contin2:    ;
  926.         }
  927.         fflush(outstr);
  928.         if (ferror(instr))
  929.             goto data_err;
  930.         if (ferror(outstr))
  931.             goto file_err;
  932.         transflag = 0;
  933.         if (bare_lfs) {
  934.             lreply(230, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
  935.             printf("   File may not have transferred correctly.\r\n");
  936.         }
  937.         return (0);
  938. #endif
  939.     default:
  940.         reply(550, "Unimplemented TYPE %d in receive_data", type);
  941.         transflag = 0;
  942.         return (-1);
  943.     }
  944.  
  945. data_err:
  946.     transflag = 0;
  947.     perror_reply(426, "Data Connection");
  948.     return (-1);
  949.  
  950. file_err:
  951.     transflag = 0;
  952.     perror_reply(452, "Error writing file");
  953.     return (-1);
  954. }
  955.  
  956. statfilecmd(filename)
  957.     char *filename;
  958. {
  959.     char line[BUFSIZ];
  960.     FILE *fin;
  961.     int c;
  962.  
  963.     (void) sprintf(line, "/bin/pls -lgA %s", filename);
  964.     fin = ftpd_popen(line, "r");
  965.     lreply(211, "status of %s:", filename);
  966.     while ((c = getc(fin)) != EOF) {
  967.         if (c == '\n') {
  968.             if (ferror(stdout)){
  969.                 perror_reply(421, "control connection");
  970.                 (void) ftpd_pclose(fin);
  971.                 dologout(1);
  972.                 /* NOTREACHED */
  973.             }
  974.             if (ferror(fin)) {
  975.                 perror_reply(551, filename);
  976.                 (void) ftpd_pclose(fin);
  977.                 return;
  978.             }
  979.             (void) putc('\r', stdout);
  980.         }
  981.         (void) putc(c, stdout);
  982.     }
  983.     (void) ftpd_pclose(fin);
  984.     reply(211, "End of Status");
  985. }
  986.  
  987. statcmd()
  988. {
  989.     struct sockaddr_in *sin;
  990.     u_char *a, *p;
  991.  
  992.     lreply(211, "%s FTP server status:", hostname, version);
  993.     printf("     %s\r\n", version);
  994.     printf("     Connected to %s", remotehost);
  995.     if (!isdigit(remotehost[0]))
  996.         printf(" (%s)", inet_ntoa(his_addr.sin_addr));
  997.     printf("\r\n");
  998.     if (logged_in) {
  999.         if (guest)
  1000.             printf("     Logged in anonymously\r\n");
  1001.         else
  1002.             printf("     Logged in as %s\r\n", pw->pw_name);
  1003.     } else if (askpasswd)
  1004.         printf("     Waiting for password\r\n");
  1005.     else
  1006.         printf("     Waiting for user name\r\n");
  1007.     printf("     TYPE: ??"/*, typenames[type]*/);
  1008.     if (type == TYPE_A || type == TYPE_E)
  1009.         printf(", FORM: ??"/*, formnames[form]*/);
  1010.     if (type == TYPE_L)
  1011. #if NBBY == 8
  1012.         printf(" %d", NBBY);
  1013. #else
  1014.         printf(" %d", bytesize);    /* need definition! */
  1015. #endif
  1016.     printf("; STRUcture: %s; transfer MODE: %s\r\n",
  1017.         /*strunames[stru]*/"??", /*modenames[mode]*/"??");
  1018.     if (data != -1)
  1019.         printf("     Data connection open\r\n");
  1020.     else if (pdata != -1) {
  1021.         printf("     in Passive mode");
  1022.         sin = &pasv_addr;
  1023.         goto printaddr;
  1024.     } else if (usedefault == 0) {
  1025.         printf("     PORT");
  1026.         sin = &data_dest;
  1027. printaddr:
  1028.         a = (u_char *) &sin->sin_addr;
  1029.         p = (u_char *) &sin->sin_port;
  1030. #define UC(b) (((int) b) & 0xff)
  1031.         printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
  1032.             UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1033. #undef UC
  1034.     } else
  1035.         printf("     No data connection\r\n");
  1036.     reply(211, "End of status");
  1037. }
  1038.  
  1039. fatal(s)
  1040.     char *s;
  1041. {
  1042.     reply(451, "Error in server: %s\n", s);
  1043.     reply(221, "Closing connection due to server error.");
  1044.     dologout(0);
  1045.     /* NOTREACHED */
  1046. }
  1047.  
  1048. /* VARARGS2 */
  1049. reply(n, fmt, p0, p1, p2, p3, p4, p5)
  1050.     int n;
  1051.     char *fmt;
  1052. {
  1053.     printf("%d", n);
  1054.     if (fmt[0] != '-') printf (" ");
  1055.     printf(fmt, p0, p1, p2, p3, p4, p5);
  1056.     printf("\r\n");
  1057.     (void)fflush(stdout);
  1058.     if (debug) {
  1059.         syslog(LOG_DEBUG, "<--- %d ", n);
  1060.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  1061. }
  1062. }
  1063.  
  1064. /* VARARGS2 */
  1065. lreply(n, fmt, p0, p1, p2, p3, p4, p5)
  1066.     int n;
  1067.     char *fmt;
  1068. {
  1069.     printf("%d- ", n);
  1070.     printf(fmt, p0, p1, p2, p3, p4, p5);
  1071.     printf("\r\n");
  1072.     (void)fflush(stdout);
  1073.     if (debug) {
  1074.         syslog(LOG_DEBUG, "<--- %d- ", n);
  1075.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  1076.     }
  1077. }
  1078.  
  1079. ack(s)
  1080.     char *s;
  1081. {
  1082.     reply(250, "%s command successful.", s);
  1083. }
  1084.  
  1085. nack(s)
  1086.     char *s;
  1087. {
  1088.     reply(502, "%s command not implemented.", s);
  1089. }
  1090.  
  1091. /* ARGSUSED */
  1092. yyerror(s)
  1093.     char *s;
  1094. {
  1095.     char *cp;
  1096.  
  1097.     if (cp = index(cbuf,'\n'))
  1098.         *cp = '\0';
  1099.     reply(500, "'%s': command not understood.", cbuf);
  1100. }
  1101.  
  1102. deletex(name)
  1103.     char *name;
  1104. {
  1105.     struct pgstat st;
  1106.  
  1107.     if (p_stat(name, &st) < 0) {
  1108.         perror_reply(550, name);
  1109.         return;
  1110.     }
  1111.     if ((st.st_mode&_S_IFMT) == S_IFDIR) {
  1112.         if (p_rmdir(name) < 0) {
  1113.             perror_reply(550, name);
  1114.             return;
  1115.         }
  1116.         goto done;
  1117.     }
  1118.     if (p_unlink(name) < 0) {
  1119.         perror_reply(550, name);
  1120.         return;
  1121.     }
  1122. done:
  1123.     ack("DELE");
  1124. }
  1125.  
  1126. cwd(path)
  1127.     char *path;
  1128. {
  1129.     if (p_chdir(path) < 0)
  1130.         perror_reply(550, path);
  1131.     else
  1132.         ack("CWD");
  1133. }
  1134.  
  1135. makedir(name)
  1136.     char *name;
  1137. {
  1138.     if (p_mkdir(name, 0777) < 0)
  1139.         perror_reply(550, name);
  1140.     else
  1141.         reply(257, "MKD command successful.");
  1142. }
  1143.  
  1144. removedir(name)
  1145.     char *name;
  1146. {
  1147.     if (p_rmdir(name) < 0)
  1148.         perror_reply(550, name);
  1149.     else
  1150.         ack("RMD");
  1151. }
  1152.  
  1153. pwd()
  1154. {
  1155.     char path[MAXPATHLEN + 1];
  1156.     extern char *p_getwd();
  1157.  
  1158.     if (p_getwd(path) == (char *)NULL)
  1159.         reply(550, "%s.", path);
  1160.     else
  1161.         reply(257, "\"%s\" is current directory.", path);
  1162. }
  1163.  
  1164. char *
  1165. renamefrom(name)
  1166.     char *name;
  1167. {
  1168.     struct pgstat st;
  1169.  
  1170.     if (p_stat(name, &st) < 0) {
  1171.         perror_reply(550, name);
  1172.         return ((char *)0);
  1173.     }
  1174.     reply(350, "File exists, ready for destination name");
  1175.     return (name);
  1176. }
  1177.  
  1178. renamecmd(from, to)
  1179.     char *from, *to;
  1180. {
  1181.     if (p_rename(from, to) < 0)
  1182.         perror_reply(550, "rename");
  1183.     else
  1184.         ack("RNTO");
  1185. }
  1186.  
  1187. dolog(sin)
  1188.     struct sockaddr_in *sin;
  1189. {
  1190.     struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
  1191.         sizeof (struct in_addr), AF_INET);
  1192.     time_t t, time();
  1193.     extern char *ctime();
  1194.  
  1195.     if (hp)
  1196.         (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
  1197.     else
  1198.         (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
  1199.             sizeof (remotehost));
  1200. #ifdef SETPROCTITLE
  1201.     sprintf(proctitle, "%s: connected", remotehost);
  1202.     setproctitle(proctitle);
  1203. #endif /* SETPROCTITLE */
  1204.  
  1205.     if (logging) {
  1206.         t = time((time_t *) 0);
  1207.         syslog(LOG_INFO, "connection from %s at %s",
  1208.             remotehost, ctime(&t));
  1209.     }
  1210. }
  1211.  
  1212. /*
  1213.  * Record logout in wtmp file
  1214.  * and exit with supplied status.
  1215.  */
  1216. dologout(status)
  1217.     int status;
  1218. {
  1219.     if (logged_in) {
  1220.         (void) seteuid((uid_t)0);
  1221.         logwtmp(ttyline, "", "");
  1222.     }
  1223.     PQfinish();
  1224.     /* beware of flushing buffers after a SIGPIPE */
  1225.     _exit(status);
  1226. }
  1227.  
  1228. void
  1229. myoob()
  1230. {
  1231.     char *cp;
  1232.  
  1233.     /* only process if transfer occurring */
  1234.     if (!transflag)
  1235.         return;
  1236.     cp = tmpline;
  1237.     if (getline(cp, 7, stdin) == NULL) {
  1238.         reply(221, "You could at least say goodbye.");
  1239.         dologout(0);
  1240.     }
  1241.     upper(cp);
  1242.     if (strcmp(cp, "ABOR\r\n") == 0) {
  1243.         tmpline[0] = '\0';
  1244.         reply(426, "Transfer aborted. Data connection closed.");
  1245.         reply(226, "Abort successful");
  1246.         longjmp(urgcatch, 1);
  1247.     }
  1248.     if (strcmp(cp, "STAT\r\n") == 0) {
  1249.         if (file_size != (off_t) -1)
  1250.             reply(213, "Status: %lu of %lu bytes transferred",
  1251.                 byte_count, file_size);
  1252.         else
  1253.             reply(213, "Status: %lu bytes transferred", byte_count);
  1254.     }
  1255. }
  1256.  
  1257. /*
  1258.  * Note: a response of 425 is not mentioned as a possible response to
  1259.  *     the PASV command in RFC959. However, it has been blessed as
  1260.  *     a legitimate response by Jon Postel in a telephone conversation
  1261.  *    with Rick Adams on 25 Jan 89.
  1262.  */
  1263. passive()
  1264. {
  1265.     int len;
  1266.     register char *p, *a;
  1267.  
  1268.     pdata = socket(AF_INET, SOCK_STREAM, 0);
  1269.     if (pdata < 0) {
  1270.         perror_reply(425, "Can't open passive connection");
  1271.         return;
  1272.     }
  1273.     pasv_addr = ctrl_addr;
  1274.     pasv_addr.sin_port = 0;
  1275.     (void) seteuid((uid_t)0);
  1276.     if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
  1277.         (void) seteuid((uid_t)pw->pw_uid);
  1278.         goto pasv_error;
  1279.     }
  1280.     (void) seteuid((uid_t)pw->pw_uid);
  1281.     len = sizeof(pasv_addr);
  1282.     if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
  1283.         goto pasv_error;
  1284.     if (listen(pdata, 1) < 0)
  1285.         goto pasv_error;
  1286.     a = (char *) &pasv_addr.sin_addr;
  1287.     p = (char *) &pasv_addr.sin_port;
  1288.  
  1289. #define UC(b) (((int) b) & 0xff)
  1290.  
  1291.     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  1292.         UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1293.     return;
  1294.  
  1295. pasv_error:
  1296.     (void) close(pdata);
  1297.     pdata = -1;
  1298.     perror_reply(425, "Can't open passive connection");
  1299.     return;
  1300. }
  1301.  
  1302. /*
  1303.  * Generate unique name for file with basename "local".
  1304.  * The file named "local" is already known to exist.
  1305.  * Generates failure reply on error.
  1306.  */
  1307. char *
  1308. gunique(local)
  1309.     char *local;
  1310. {
  1311.     static char newx[MAXPATHLEN];
  1312.     struct pgstat st;
  1313.     char *cp = rindex(local, '/');
  1314.     int count = 0;
  1315.  
  1316.     if (cp)
  1317.         *cp = '\0';
  1318.     if (p_stat(cp ? local : ".", &st) < 0) {
  1319.         perror_reply(553, cp ? local : ".");
  1320.         return((char *) 0);
  1321.     }
  1322.     if (cp)
  1323.         *cp = '/';
  1324.     (void) strcpy(newx, local);
  1325.     cp = newx + strlen(newx);
  1326.     *cp++ = '.';
  1327.     for (count = 1; count < 100; count++) {
  1328.         (void) sprintf(cp, "%d", count);
  1329.         if (p_stat(newx, &st) < 0)
  1330.             return(newx);
  1331.     }
  1332.     reply(452, "Unique file name cannot be created.");
  1333.     return((char *) 0);
  1334. }
  1335.  
  1336. /*
  1337.  * Format and send reply containing system error number.
  1338.  */
  1339. perror_reply(code, string)
  1340.     int code;
  1341.     char *string;
  1342. {
  1343.     reply(code, "%s: %s.", string, strerror(errno));
  1344. }
  1345.  
  1346. static char *onefile[] = {
  1347.     "",
  1348.     0
  1349. };
  1350.  
  1351. send_file_list(whichfiles)
  1352.     char *whichfiles;
  1353. {
  1354.     struct pgstat st;
  1355.     PDIR *dirp = NULL;
  1356.     struct pgdirent *dir;
  1357.     FILE *dout = NULL;
  1358.     register char **dirlist, *dirname;
  1359.     int simple = 0;
  1360.     char *strpbrk();
  1361.  
  1362.     if (strpbrk(whichfiles, "~{[*?") != NULL) {
  1363.         extern char **ftpglob(), *globerr;
  1364.  
  1365.         globerr = NULL;
  1366.         dirlist = ftpglob(whichfiles);
  1367.         if (globerr != NULL) {
  1368.             reply(550, globerr);
  1369.             return;
  1370.         } else if (dirlist == NULL) {
  1371.             errno = ENOENT;
  1372.             perror_reply(550, whichfiles);
  1373.             return;
  1374.         }
  1375.     } else {
  1376.         onefile[0] = whichfiles;
  1377.         dirlist = onefile;
  1378.         simple = 1;
  1379.     }
  1380.  
  1381.     if (setjmp(urgcatch)) {
  1382.         transflag = 0;
  1383.         return;
  1384.     }
  1385.     while (dirname = *dirlist++) {
  1386.         if (p_stat(dirname, &st) < 0) {
  1387.             /*
  1388.              * If user typed "ls -l", etc, and the client
  1389.              * used NLST, do what the user meant.
  1390.              */
  1391.             if (dirname[0] == '-' && *dirlist == NULL &&
  1392.                 transflag == 0) {
  1393.                 retrieve("/bin/pls %s", dirname);
  1394.                 return;
  1395.             }
  1396.             perror_reply(550, whichfiles);
  1397.             if (dout != NULL) {
  1398.                 (void) fclose(dout);
  1399.                 transflag = 0;
  1400.                 data = -1;
  1401.                 pdata = -1;
  1402.             }
  1403.             return;
  1404.         }
  1405.  
  1406.         if ((st.st_mode&_S_IFMT) == S_IFREG) {
  1407.             if (dout == NULL) {
  1408.                 dout = dataconn("file list", (off_t)-1, "w");
  1409.                 if (dout == NULL)
  1410.                     return;
  1411.                 transflag++;
  1412.             }
  1413.             fprintf(dout, "%s%s\n", dirname,
  1414.                 type == TYPE_A ? "\r" : "");
  1415.             byte_count += strlen(dirname) + 1;
  1416.             continue;
  1417.         } else if ((st.st_mode&_S_IFMT) != S_IFDIR)
  1418.             continue;
  1419.  
  1420.         if ((dirp = p_opendir(dirname)) == NULL)
  1421.             continue;
  1422.  
  1423.         while ((dir = p_readdir(dirp)) != NULL) {
  1424.             char nbuf[MAXPATHLEN];
  1425.  
  1426.             if (dir->d_name[0] == '.' && dir->d_namlen == 1)
  1427.                 continue;
  1428.             if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
  1429.                 dir->d_namlen == 2)
  1430.                 continue;
  1431.  
  1432.             sprintf(nbuf, "%s/%s", dirname, dir->d_name);
  1433.  
  1434.             /*
  1435.              * We have to do a stat to insure it's
  1436.              * not a directory or special file.
  1437.              */
  1438.             if (simple || (p_stat(nbuf, &st) == 0 &&
  1439.                 (st.st_mode&_S_IFMT) == S_IFREG)) {
  1440.                 if (dout == NULL) {
  1441.                     dout = dataconn("file list", (off_t)-1,
  1442.                         "w");
  1443.                     if (dout == NULL)
  1444.                         return;
  1445.                     transflag++;
  1446.                 }
  1447.                 if (nbuf[0] == '.' && nbuf[1] == '/')
  1448.                     fprintf(dout, "%s%s\n", &nbuf[2],
  1449.                         type == TYPE_A ? "\r" : "");
  1450.                 else
  1451.                     fprintf(dout, "%s%s\n", nbuf,
  1452.                         type == TYPE_A ? "\r" : "");
  1453.                 byte_count += strlen(nbuf) + 1;
  1454.             }
  1455.         }
  1456.         (void) p_closedir(dirp);
  1457.     }
  1458.  
  1459.     if (dout == NULL)
  1460.         reply(550, "No files found.");
  1461.     else if (ferror(dout) != 0)
  1462.         perror_reply(550, "Data connection");
  1463.     else
  1464.         reply(226, "Transfer complete.");
  1465.  
  1466.     transflag = 0;
  1467.     if (dout != NULL)
  1468.         (void) fclose(dout);
  1469.     data = -1;
  1470.     pdata = -1;
  1471. }
  1472.  
  1473. #ifdef SETPROCTITLE
  1474. /*
  1475.  * clobber argv so ps will show what we're doing.
  1476.  * (stolen from sendmail)
  1477.  * warning, since this is usually started from inetd.conf, it
  1478.  * often doesn't have much of an environment or arglist to overwrite.
  1479.  */
  1480.  
  1481. /*VARARGS1*/
  1482. setproctitle(fmt, a, b, c)
  1483. char *fmt;
  1484. {
  1485.     register char *p, *bp, ch;
  1486.     register int i;
  1487.     char buf[BUFSIZ];
  1488.  
  1489.     (void) sprintf(buf, fmt, a, b, c);
  1490.  
  1491.     /* make ps print our process name */
  1492.     p = Argv[0];
  1493.     *p++ = '-';
  1494.  
  1495.     i = strlen(buf);
  1496.     if (i > LastArgv - p - 2) {
  1497.         i = LastArgv - p - 2;
  1498.         buf[i] = '\0';
  1499.     }
  1500.     bp = buf;
  1501.     while (ch = *bp++)
  1502.         if (ch != '\n' && ch != '\r')
  1503.             *p++ = ch;
  1504.     while (p < LastArgv)
  1505.         *p++ = ' ';
  1506. }
  1507. #endif /* SETPROCTITLE */
  1508.