home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / tcpip / amitcp-support / wustl-ftpdaemon / src / ftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-29  |  76.1 KB  |  2,905 lines

  1. /* Copyright (c) 1985, 1988, 1990 Regents of the University of California.
  2.  * All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are
  6.  * met: 1. Redistributions of source code must retain the above copyright
  7.  * notice, this list of conditions and the following disclaimer. 2.
  8.  * Redistributions in binary form must reproduce the above copyright notice,
  9.  * this list of conditions and the following disclaimer in the documentation
  10.  * and/or other materials provided with the distribution. 3. All advertising
  11.  * materials mentioning features or use of this software must display the
  12.  * following acknowledgement: This product includes software developed by the
  13.  * University of California, Berkeley and its contributors. 4. Neither the
  14.  * name of the University nor the names of its contributors may be used to
  15.  * endorse or promote products derived from this software without specific
  16.  * prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
  19.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21.  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
  22.  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28.  * SUCH DAMAGE. 
  29.  */
  30.  
  31. #ifndef lint
  32. char copyright[] =
  33. "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\
  34.  All rights reserved.\n";
  35. #endif /* not lint */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)ftpd.c  5.40 (Berkeley) 7/2/91";
  39. #endif /* not lint */
  40.  
  41. /* FTP server. */
  42. #include "config.h"
  43.  
  44. #include <sys/types.h>
  45. #include <sys/param.h>
  46. #include <sys/stat.h>
  47. #include <sys/ioctl.h>
  48. #include <sys/socket.h>
  49. #ifndef AMIGA
  50. #include <sys/file.h>
  51. #include <sys/wait.h>
  52. #endif
  53.  
  54. #ifdef AIX
  55. #include <sys/id.h>
  56. #include <sys/priv.h>
  57. #endif
  58.  
  59. #include <netinet/in.h>
  60. #include <netinet/in_systm.h>
  61. #include <netinet/ip.h>
  62.  
  63. #define FTP_NAMES
  64. #include <arpa/ftp.h>
  65. #include <arpa/inet.h>
  66. #include <arpa/telnet.h>
  67.  
  68. #include <ctype.h>
  69. #include <stdio.h>
  70. #include <signal.h>
  71. #include <pwd.h>
  72. #include <setjmp.h>
  73. #include <netdb.h>
  74. #include <errno.h>
  75. #include <string.h>
  76. #include <varargs.h>
  77. #ifdef SYSSYSLOG
  78. #include <sys/syslog.h>
  79. #else
  80. #include <syslog.h>
  81. #endif
  82. #include <time.h>
  83. #ifdef AMIGA
  84. #include <bsdsocket.h>
  85. #endif
  86. #include "conversions.h"
  87. #include "extensions.h"
  88. #include "pathnames.h"
  89.  
  90. #ifdef M_UNIX
  91. #include <arpa/nameser.h>
  92. #include <resolv.h>
  93. #endif
  94.  
  95. #if defined(SVR4) || defined(ISC) || defined(AMIGA)
  96. #include <fcntl.h>
  97. #endif
  98.  
  99. #ifdef HAVE_SYSINFO
  100. #include <sys/systeminfo.h>
  101. #endif
  102.  
  103. #ifdef SHADOW_PASSWORD
  104. #include <shadow.h>
  105. #endif
  106.  
  107. #ifdef KERBEROS
  108. #include <sys/types.h>
  109. #include <auth.h>
  110. #include <krb.h>
  111. #endif
  112.  
  113. #ifdef ULTRIX_AUTH
  114. #include <auth.h>
  115. #include <sys/svcinfo.h>
  116. #endif
  117.  
  118. #ifdef HAVE_DIRENT
  119. #include <dirent.h>
  120. #else
  121. #include <sys/dir.h>
  122. #endif
  123.  
  124. #ifndef TRUE
  125. #define  TRUE   1
  126. #endif
  127.  
  128. #ifndef FALSE
  129. #define  FALSE  !TRUE
  130. #endif
  131.  
  132. /* File containing login names NOT to be used on this machine. Commonly used
  133.  * to disallow uucp. */
  134. extern int errno;
  135. extern int pidfd;
  136. extern char *ctime(const time_t *);
  137. #ifndef NO_CRYPT_PROTO
  138. extern char *crypt(const char *, const char *);
  139. #endif
  140. extern char version[];
  141. extern char *home;              /* pointer to home directory for glob */
  142. extern FILE *ftpd_popen(char *program, char *type, int closestderr),
  143.  *fopen(const char *, const char *),
  144.  *freopen(const char *, const char *, FILE *);
  145. extern int ftpd_pclose(FILE *iop),
  146.   fclose(FILE *);
  147. extern char *getline(),
  148.  *realpath(char *pathname, char *result);
  149. extern char cbuf[];
  150. extern off_t restart_point;
  151.  
  152. struct sockaddr_in ctrl_addr;
  153. struct sockaddr_in data_source;
  154. struct sockaddr_in data_dest;
  155. struct sockaddr_in his_addr;
  156. struct sockaddr_in pasv_addr;
  157.  
  158. int data;
  159. jmp_buf errcatch,
  160.   urgcatch;
  161. int logged_in;
  162. struct passwd *pw;
  163. int debug;
  164. int timeout = 900;              /* timeout after 15 minutes of inactivity */
  165. int maxtimeout = 7200;          /* don't allow idle time to be set beyond 2
  166.                                  * hours */
  167. int logging;
  168. int log_commands = 1;
  169. int anonymous;
  170. int guest;
  171. int type;
  172. int form;
  173. int stru;                       /* avoid C keyword */
  174. int mode;
  175. int usedefault = 1;             /* for data transfers */
  176. int pdata = -1;                 /* for passive mode */
  177. int transflag;
  178. off_t file_size;
  179. off_t byte_count;
  180.  
  181. #if !defined(CMASK) || CMASK == 0
  182. #undef CMASK
  183. #define CMASK 002
  184. #endif
  185. mode_t defumask = CMASK;           /* default umask value */
  186. char tmpline[7];
  187. char hostname[MAXHOSTNAMELEN];
  188. char remotehost[MAXHOSTNAMELEN];
  189. char remoteaddr[MAXHOSTNAMELEN];
  190.  
  191. /* log failures     27-apr-93 ehk/bm */
  192. #ifdef LOG_FAILED
  193. #define MAXUSERNAMELEN    32
  194. char the_user[MAXUSERNAMELEN];
  195. #endif
  196.  
  197. /* Access control and logging passwords */
  198. int use_accessfile = 1;
  199. char guestpw[MAXHOSTNAMELEN];
  200. char privatepw[MAXHOSTNAMELEN];
  201. int nameserved = 0;
  202. extern char authuser[];
  203. extern int authenticated;
  204.  
  205. /* File transfer logging */
  206. int xferlog = 0;
  207. int log_outbound_xfers = 0;
  208. int log_incoming_xfers = 0;
  209.  
  210. /* Allow use of lreply(); this is here since some older FTP clients don't
  211.  * support continuation messages.  In violation of the RFCs... */
  212. int dolreplies = 1;
  213.  
  214. /* Spontaneous reply text.  To be sent along with next reply to user */
  215. char *autospout = NULL;
  216. int autospout_free = 0;
  217.  
  218. /* allowed on-the-fly file manipulations (compress, tar) */
  219. int mangleopts = 0;
  220.  
  221. /* number of login failures before attempts are logged and FTP *EXITS* */
  222. int lgi_failure_threshold = 5;
  223.  
  224. /* Timeout intervals for retrying connections to hosts that don't accept PORT
  225.  * cmds.  This is a kludge, but given the problems with TCP... */
  226. #define SWAITMAX    90          /* wait at most 90 seconds */
  227. #define SWAITINT    5           /* interval between retries */
  228.  
  229. int swaitmax = SWAITMAX;
  230. int swaitint = SWAITINT;
  231.  
  232. SIGNAL_TYPE lostconn(int sig);
  233. SIGNAL_TYPE randomsig(int sig);
  234. SIGNAL_TYPE myoob(int sig);
  235. FILE *getdatasock(char *mode),
  236.  *dataconn(char *name, off_t size, char *mode);
  237.  
  238. #ifdef SETPROCTITLE
  239. char **Argv = NULL;             /* pointer to argument vector */
  240. char *LastArgv = NULL;          /* end of argv */
  241. char proctitle[BUFSIZ];         /* initial part of title */
  242.  
  243. #endif /* SETPROCTITLE */
  244.  
  245. #ifdef KERBEROS
  246. void init_krb();
  247. void end_krb();
  248. char krb_ticket_name[100];
  249. #endif /* KERBEROS */
  250.  
  251. #ifdef ULTRIX_AUTH
  252. int ultrix_check_pass(char *passwd, char *xpasswd);
  253. #endif
  254.  
  255. /* ls program commands and options for lreplies on and off */
  256. char  ls_long[50];
  257. char  ls_short[50];
  258. struct aclmember *entry = NULL;
  259.  
  260. main(int argc, char **argv, char **envp)
  261. {
  262.     int addrlen,
  263.       on = 1;
  264. #ifdef IPTOS_LOWDELAY
  265.     int tos;
  266. #endif
  267.     char *cp;
  268.  
  269. #ifdef AMIGA
  270.     int s = init_inet_daemon();
  271.  
  272.     if (s == -1) {
  273. #ifdef STANDALONE
  274.       struct sockaddr_in sin;
  275.  
  276.       s = serveraccept("ftp", &sin);
  277.       if (s != -1) {
  278.         fprintf(stderr, "Accepted a connection from %s, port %ld\n",
  279.             inet_ntoa(sin.sin_addr), sin.sin_port);
  280.       } else 
  281. #endif
  282.         return 1;
  283.     }
  284.     else
  285.       set_socket_stdio(s);
  286. #endif
  287.  
  288. #ifdef SecureWare
  289.     setluid(1);                         /* make sure there is a valid luid */
  290.     set_auth_parameters(argc,argv);
  291.     setreuid(0, 0);
  292. #endif
  293. #if defined(M_UNIX) && !defined(_M_UNIX)
  294.     res_init();                         /* bug in old (1.1.1) resolver     */
  295.     _res.retrans = 20;                  /* because of fake syslog in 3.2.2 */
  296.     setlogmask(LOG_UPTO(LOG_INFO));
  297. #endif
  298.  
  299.     addrlen = sizeof(his_addr);
  300.     if (getpeername(0, (struct sockaddr *) &his_addr, &addrlen) < 0) {
  301.         syslog(LOG_ERR, "getpeername (%s): %m", argv[0]);
  302. #ifndef DEBUG
  303.         exit(1);
  304. #endif
  305.     }
  306.     addrlen = sizeof(ctrl_addr);
  307.     if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) {
  308.         syslog(LOG_ERR, "getsockname (%s): %m", argv[0]);
  309. #ifndef DEBUG
  310.         exit(1);
  311. #endif
  312.     }
  313. #ifdef IPTOS_LOWDELAY
  314.     tos = IPTOS_LOWDELAY;
  315.     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
  316.           syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  317. #endif
  318.  
  319.     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  320.     debug = 0;
  321.  
  322. #ifdef FACILITY
  323.     openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY);
  324. #else
  325.     openlog("ftpd", LOG_PID);
  326. #endif
  327.  
  328. #ifdef SETPROCTITLE
  329.     /* Save start and extent of argv for setproctitle. */
  330.     Argv = argv;
  331.     while (*envp)
  332.         envp++;
  333.     LastArgv = envp[-1] + strlen(envp[-1]);
  334. #endif /* SETPROCTITLE */
  335.  
  336.     argc--, argv++;
  337.     while (argc > 0 && *argv[0] == '-') {
  338.         for (cp = &argv[0][1]; *cp; cp++)
  339.             switch (*cp) {
  340.  
  341.             case 'a':
  342.                 use_accessfile = 1;
  343.                 break;
  344.  
  345.             case 'A':
  346.                 use_accessfile = 0;
  347.                 break;
  348.  
  349.             case 'v':
  350.                 debug = 1;
  351.                 break;
  352.  
  353.             case 'd':
  354.                 debug = 1;
  355.                 break;
  356.  
  357.             case 'l':
  358.                 logging = 1;
  359.                 break;
  360.  
  361.             case 'L':
  362.                 log_commands = 1;
  363.                 break;
  364.  
  365.             case 'i':
  366.                 log_incoming_xfers = 1;
  367.                 break;
  368.  
  369.             case 'o':
  370.                 log_outbound_xfers = 1;
  371.                 break;
  372.  
  373.             case 't':
  374.                 timeout = atoi(++cp);
  375.                 if (maxtimeout < timeout)
  376.                     maxtimeout = timeout;
  377.                 goto nextopt;
  378.  
  379.             case 'T':
  380.                 maxtimeout = atoi(++cp);
  381.                 if (timeout > maxtimeout)
  382.                     timeout = maxtimeout;
  383.                 goto nextopt;
  384.  
  385.             case 'u':
  386.                 {
  387.                     int val = 0;
  388.  
  389.                     while (*++cp && *cp >= '0' && *cp <= '9')
  390.                         val = val * 8 + *cp - '0';
  391.                     if (*cp)
  392.                         fprintf(stderr, "ftpd: Bad value for -u\n");
  393.                     else
  394.                         defumask = val;
  395.                     goto nextopt;
  396.                 }
  397.  
  398.             default:
  399.                 fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
  400.                         *cp);
  401.                 break;
  402.             }
  403.       nextopt:
  404.         argc--, argv++;
  405.     }
  406.     (void) freopen(_PATH_DEVNULL, "w", stderr);
  407.  
  408.     /* Checking for random signals ... */
  409. #ifdef SIGHUP
  410.     (void) signal(SIGHUP, randomsig);
  411. #endif
  412. #ifdef SIGINT
  413.     (void) signal(SIGINT, randomsig);
  414. #endif
  415. #ifdef SIGQUIT
  416.     (void) signal(SIGQUIT, randomsig);
  417. #endif
  418. #ifdef SIGILL
  419.     (void) signal(SIGILL, randomsig);
  420. #endif
  421. #ifdef SIGTRAP
  422.     (void) signal(SIGTRAP, randomsig);
  423. #endif
  424. #ifdef SIGIOT
  425.     (void) signal(SIGIOT, randomsig);
  426. #endif
  427. #ifdef SIGEMT
  428.     (void) signal(SIGEMT, randomsig);
  429. #endif
  430. #ifdef SIGFPE
  431.     (void) signal(SIGFPE, randomsig);
  432. #endif
  433. #ifdef SIGKILL
  434.     (void) signal(SIGKILL, randomsig);
  435. #endif
  436. #ifdef SIGBUS
  437.     (void) signal(SIGBUS, randomsig);
  438. #endif
  439. #ifdef SIGSEGV
  440.     (void) signal(SIGSEGV, randomsig);
  441. #endif
  442. #ifdef SIGSYS
  443.     (void) signal(SIGSYS, randomsig);
  444. #endif
  445. #ifdef SIGALRM
  446.     (void) signal(SIGALRM, randomsig);
  447. #endif
  448. #ifdef SIGSTOP
  449.     (void) signal(SIGSTOP, randomsig);
  450. #endif
  451. #ifdef SIGTSTP
  452.     (void) signal(SIGTSTP, randomsig);
  453. #endif
  454. #ifdef SIGTTIN
  455.     (void) signal(SIGTTIN, randomsig);
  456. #endif
  457. #ifdef SIGTTOU
  458.     (void) signal(SIGTTOU, randomsig);
  459. #endif
  460. #ifdef SIGIO
  461.     (void) signal(SIGIO, randomsig);
  462. #endif
  463. #ifdef SIGXCPU
  464.     (void) signal(SIGXCPU, randomsig);
  465. #endif
  466. #ifdef SIGXFSZ
  467.     (void) signal(SIGXFSZ, randomsig);
  468. #endif
  469. #ifdef SIGWINCH
  470.     (void) signal(SIGWINCH, randomsig);
  471. #endif
  472. #ifdef SIGVTALRM
  473.     (void) signal(SIGVTALRM, randomsig);
  474. #endif
  475. #ifdef SIGPROF
  476.     (void) signal(SIGPROF, randomsig);
  477. #endif
  478. #ifdef SIGUSR1
  479.     (void) signal(SIGUSR1, randomsig);
  480. #endif
  481. #ifdef SIGUSR2
  482.     (void) signal(SIGUSR2, randomsig);
  483. #endif
  484.  
  485. #ifdef SIGPIPE
  486.     (void) signal(SIGPIPE, lostconn);
  487. #endif
  488. #ifdef SIGCHLD
  489.     (void) signal(SIGCHLD, SIG_IGN);
  490. #endif
  491.  
  492. #ifdef SIGURG
  493.     if ((int) signal(SIGURG, myoob) < 0)
  494.         syslog(LOG_ERR, "signal: %m");
  495. #endif
  496.  
  497.     /* Try to handle urgent data inline */
  498. #ifdef SO_OOBINLINE
  499.     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(int)) < 0)
  500.         syslog(LOG_ERR, "setsockopt (SO_OOBINLINE): %m");
  501. #endif
  502.  
  503. #ifdef  F_SETOWN
  504.     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  505.         syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  506. #endif
  507.     dolog(&his_addr);
  508.     /* Set up default state */
  509.     data = -1;
  510.     type = TYPE_A;
  511.     form = FORM_N;
  512.     stru = STRU_F;
  513.     mode = MODE_S;
  514.     tmpline[0] = '\0';
  515.  
  516. #ifdef HAVE_SYSINFO
  517.     sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
  518. #else
  519.     (void) gethostname(hostname, sizeof (hostname));
  520. #endif
  521.  
  522.     access_init();
  523.     authenticate();
  524.     conv_init();
  525.  
  526.     if (is_shutdown(1) != 0) {
  527.         syslog(LOG_INFO, "connection refused (server shut down) from %s [%s]",
  528.                remotehost, remoteaddr);
  529.         reply(500, "%s FTP server shut down -- please try again later.",
  530.               hostname);
  531.         exit(0);
  532.     }
  533.     show_banner(220);
  534.  
  535.     entry = (struct aclmember *) NULL;
  536.     if (getaclentry("lslong", &entry) && ARG0 && strlen(ARG0) > 0) {
  537.           strcpy(ls_long,ARG0);
  538.       if (ARG1 && strlen(ARG1)) {
  539.              strcat(ls_long," ");
  540.          strcat(ls_long,ARG1);
  541.           }
  542.     } else {
  543. #ifdef AMIGA
  544.           strcpy(ls_long,"AmiTCP:bin/ls -lgA");
  545. #else
  546. #ifdef SVR4
  547. #ifndef AIX
  548.           strcpy(ls_long,"/bin/ls -la");
  549. #else
  550.           strcpy(ls_long,"/bin/ls -lA");
  551. #endif
  552. #else
  553.           strcpy(ls_long,"/bin/ls -lgA");
  554. #endif
  555. #endif
  556.     }
  557.     strcat(ls_long," %s");
  558.  
  559.     entry = (struct aclmember *) NULL;
  560.     if (getaclentry("lsshort", &entry) && ARG0 && strlen(ARG0) > 0) {
  561.           strcpy(ls_short,ARG0);
  562.       if (ARG1 && strlen(ARG1)) {
  563.              strcat(ls_short," ");
  564.              strcat(ls_short,ARG1);
  565.       }
  566.     } else {
  567. #ifdef AMIGA
  568.           strcpy(ls_short,"AmiTCP:bin/ls -lgA");
  569. #else
  570. #ifdef SVR4
  571. #ifndef AIX
  572.           strcpy(ls_short,"/bin/ls -la");
  573. #else
  574.           strcpy(ls_short,"/bin/ls -lA");
  575. #endif
  576. #else
  577.           strcpy(ls_short,"/bin/ls -lgA");
  578. #endif
  579. #endif
  580.     }
  581.     strcat(ls_short," %s");
  582.  
  583.     reply(220, "%s FTP server (%s) ready.", hostname, version);
  584.     (void) setjmp(errcatch);
  585.  
  586.     for (;;)
  587.         (void) yyparse();
  588.     /* NOTREACHED */
  589. }
  590.  
  591. SIGNAL_TYPE
  592. randomsig(int sig)
  593. {
  594.     syslog(LOG_ERR, "exiting on signal %d", sig);
  595. #ifndef AMIGA
  596.     chdir("/etc/tmp");
  597. #endif
  598. #ifdef SIGIOT
  599.     signal(SIGIOT, SIG_DFL);
  600. #endif
  601.     signal(SIGILL, SIG_DFL);
  602.     abort();
  603.     /* dologout(-1); *//* NOTREACHED */
  604. }
  605.  
  606. SIGNAL_TYPE
  607. lostconn(int sig)
  608. {
  609.     if (debug)
  610.         syslog(LOG_DEBUG, "lost connection to %s [%s]", remotehost, remoteaddr);
  611.     dologout(-1);
  612. }
  613.  
  614. static char ttyline[20];
  615.  
  616. /* Helper function for sgetpwnam(). */
  617. char *
  618. sgetsave(char *s)
  619. {
  620.     char *new;
  621.     
  622.     new = (char *) malloc(strlen(s) + 1);
  623.  
  624.     if (new == NULL) {
  625.         perror_reply(421, "Local resource failure: malloc");
  626.         dologout(1);
  627.         /* NOTREACHED */
  628.     }
  629.     (void) strcpy(new, s);
  630.     return (new);
  631. }
  632.  
  633. /* Save the result of a getpwnam.  Used for USER command, since the data
  634.  * returned must not be clobbered by any other command (e.g., globbing). */
  635. struct passwd *
  636. sgetpwnam(char *name)
  637. {
  638.     static struct passwd save;
  639.     register struct passwd *p;
  640. #ifdef M_UNIX
  641.     struct passwd *ret = (struct passwd *) NULL;
  642. #endif
  643.     char *sgetsave(char *s);
  644.  
  645. #ifdef KERBEROS
  646.     register struct authorization *q;
  647. #endif /* KERBEROS */
  648.  
  649. #ifdef SecureWare
  650.     struct pr_passwd *pr;
  651. #endif
  652.  
  653. #ifdef KERBEROS
  654.     init_krb();
  655.     q = getauthuid(p->pw_uid);
  656.     end_krb();
  657. #endif /* KERBEROS */
  658.  
  659. #ifdef M_UNIX
  660. # ifdef SecureWare
  661.     if ((pr = getprpwnam(name)) == NULL)
  662.         goto DONE;
  663. # endif /* SecureWare */
  664.     if ((p = getpwnam(name)) == NULL)
  665.         goto DONE;
  666. #else   /* M_UNIX */
  667. # ifdef SecureWare
  668.     if ((pr = getprpwnam(name)) == NULL)
  669.         return((struct passwd *) pr);
  670. # endif /* SecureWare */
  671.     if ((p = getpwnam(name)) == NULL)
  672.         return (p);
  673. #endif  /* M_UNIX */
  674.  
  675.     if (save.pw_name)   free(save.pw_name);
  676.     if (save.pw_gecos)  free(save.pw_gecos);
  677.     if (save.pw_dir)    free(save.pw_dir);
  678.     if (save.pw_shell)  free(save.pw_shell);
  679.  
  680.     save = *p;
  681.  
  682.     save.pw_name = sgetsave(p->pw_name);
  683.  
  684. #ifdef KERBEROS
  685.     save.pw_passwd = sgetsave(q->a_password);
  686. #elif defined(SecureWare)
  687.      if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
  688.         save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
  689.      else
  690.         save.pw_passwd = sgetsave("");
  691. #else
  692.     save.pw_passwd = sgetsave(p->pw_passwd);
  693. #endif
  694.  
  695.     save.pw_gecos = sgetsave(p->pw_gecos);
  696.     save.pw_dir = sgetsave(p->pw_dir);
  697.     save.pw_shell = sgetsave(p->pw_shell);
  698. #ifdef M_UNIX
  699.     ret = &save;
  700. DONE:
  701.     endpwent();
  702. #endif
  703. #ifdef SecureWare
  704.     endprpwent();
  705. #endif
  706. #ifdef M_UNIX
  707.     return(ret);
  708. #else
  709.     return(&save);
  710. #endif
  711. }
  712.  
  713. int login_attempts;             /* number of failed login attempts */
  714. int askpasswd;                  /* had user command, ask for passwd */
  715.  
  716. /* USER command. Sets global passwd pointer pw if named account exists and is
  717.  * acceptable; sets askpasswd if a PASS command is expected.  If logged in
  718.  * previously, need to reset state.  If name is "ftp" or "anonymous", the
  719.  * name is not in _PATH_FTPUSERS, and ftp account exists, set anonymous and
  720.  * pw, then just return.  If account doesn't exist, ask for passwd anyway.
  721.  * Otherwise, check user requesting login privileges.  Disallow anyone who
  722.  * does not have a standard shell as returned by getusershell().  Disallow
  723.  * anyone mentioned in the file _PATH_FTPUSERS to allow people such as root
  724.  * and uucp to be avoided. */
  725. user(char *name)
  726. {
  727.     register char *cp;
  728.     char *shell;
  729.     char *getusershell();
  730.     int   why = 0;
  731.  
  732. #ifdef HOST_ACCESS                     /* 19-Mar-93    BM              */
  733.     if (!rhost_ok(name, remotehost, remoteaddr))
  734.     {
  735.             reply(530, "User %s access denied.", name);
  736.             syslog(LOG_NOTICE,
  737.                     "FTP LOGIN REFUSED (name in %s) FROM %s [%s], %s",
  738.                      _PATH_FTPHOSTS, remotehost, remoteaddr, name);
  739.             return;
  740.     }
  741. #endif
  742.  
  743. #ifdef LOG_FAILED                       /* 06-Nov-92    EHK             */
  744.     strncpy(the_user, name, MAXUSERNAMELEN - 1);
  745. #endif
  746.  
  747.     if (logged_in) {
  748.         if (anonymous || guest) {
  749.             reply(530, "Can't change user from guest login.");
  750.             return;
  751.         }
  752.         end_login();
  753.     }
  754.  
  755.     anonymous = 0;
  756.     acl_remove();
  757.  
  758.     if (!strcasecmp(name, "ftp") || !strcasecmp(name, "anonymous")) {
  759.       struct aclmember *entry = NULL;
  760.       int machineok=1;
  761.       char guestservername[MAXHOSTNAMELEN];
  762.       guestservername[0]='\0';
  763.  
  764.       if (checkuser("ftp") || checkuser("anonymous")) {
  765.           reply(530, "User %s access denied.", name);
  766.           syslog(LOG_NOTICE,
  767.            "FTP LOGIN REFUSED (ftp in /etc/ftpusers) FROM %s [%s], %s",
  768.            remotehost, remoteaddr, name);
  769.           return;
  770.           
  771.         /*
  772.         ** Algorithm used:
  773.         ** - if no "guestserver" directive is present,
  774.         **     anonymous access is allowed, for backward compatibility.
  775.         ** - if a "guestserver" directive is present,
  776.         **     anonymous access is restricted to the machines listed,
  777.         **     usually the machine whose CNAME on the current domain
  778.         **     is "ftp"...
  779.         **
  780.         ** the format of the "guestserver" line is
  781.         ** guestserver [<machine1> [<machineN>]]
  782.         ** that is, "guestserver" will forbid anonymous access on all machines
  783.         ** while "guestserver ftp inf" will allow anonymous access on
  784.         ** the two machines whose CNAMES are "ftp.enst.fr" and "inf.enst.fr".
  785.         **
  786.         ** if anonymous access is denied on the current machine,
  787.         ** the user will be asked to use the first machine listed (if any)
  788.         ** on the "guestserver" line instead:
  789.         ** 530- Guest login not allowed on this machine,
  790.         **      connect to ftp.enst.fr instead.
  791.         **
  792.         ** -- <Nicolas.Pioch@enst.fr>
  793.         */
  794.       } else if (getaclentry("guestserver", &entry)
  795.                  && ARG0 && strlen(ARG0) > 0) {
  796.         struct hostent *tmphostent;
  797.  
  798.         /*
  799.         ** if a "guestserver" line is present,
  800.         ** default is not to allow guest logins
  801.         */
  802.         machineok=0;
  803.  
  804.         if (hostname[0]
  805.             && ((tmphostent=gethostbyname(hostname)))) {
  806.  
  807.           /*
  808.           ** hostname is the only first part of the FQDN
  809.           ** this may or may not correspond to the h_name value
  810.           ** (machines with more than one IP#, CNAMEs...)
  811.           ** -> need to fix that, calling gethostbyname on hostname
  812.           **
  813.           ** WARNING!
  814.           ** for SunOS 4.x, you need to have a working resolver in the libc
  815.           ** for CNAMES to work properly.
  816.           ** If you don't, add "-lresolv" to the libraries before compiling!
  817.           */
  818.           char dns_localhost[MAXHOSTNAMELEN];
  819.           int machinecount;
  820.  
  821.           strncpy(dns_localhost,
  822.                   tmphostent->h_name,
  823.                   sizeof(dns_localhost));
  824.           dns_localhost[sizeof(dns_localhost)-1]='\0';
  825.  
  826.           for (machinecount=0;
  827.                entry->arg[machinecount] && (entry->arg[machinecount])[0];
  828.                machinecount++) {
  829.  
  830.             if ((tmphostent=gethostbyname(entry->arg[machinecount]))) {
  831.               /*
  832.               ** remember the name of the first machine for redirection
  833.               */
  834.  
  835.               if ((!machinecount) && tmphostent->h_name) {
  836.                 strncpy(guestservername, entry->arg[machinecount],
  837.                         sizeof(guestservername));
  838.                 guestservername[sizeof(guestservername)-1]='\0';
  839.               }
  840.  
  841.               if (!strcasecmp(tmphostent->h_name, dns_localhost)) {
  842.                 machineok++;
  843.                 break;
  844.               }
  845.             }
  846.           }
  847.         }
  848.       }
  849.       if (!machineok) {
  850.         if (guestservername[0])
  851.           reply(530,
  852.              "Guest login not allowed on this machine, connect to %s instead.",
  853.                 guestservername);
  854.         else
  855.           reply(530,
  856.                 "Guest login not allowed on this machine.");
  857.         syslog(LOG_NOTICE,
  858.                "FTP LOGIN REFUSED (localhost not in guestservers) FROM %s [%s], %s",
  859.                remotehost, remoteaddr, name);
  860.         /* End of the big patch -- Nap */
  861.  
  862.         } else if ((pw = sgetpwnam("ftp")) != NULL) {
  863.             anonymous = 1;      /* for the access_ok call */
  864.             if ((why = access_ok(530)) == 1) {
  865.                 askpasswd = 1;
  866.                 acl_setfunctions();
  867.                 reply(331, "Guest login ok, send your complete e-mail address as password.");
  868.             } else if (why == 0) {
  869.                 reply(530, "User %s access denied..", name);
  870.                 syslog(LOG_NOTICE,
  871.                        "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  872.                        remotehost, remoteaddr, name);
  873.                 anonymous = 0;
  874.             } else {
  875.                 reply(530, "User %s access denied.", name);
  876.                 syslog(LOG_NOTICE,
  877.                        "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  878.                        remotehost, remoteaddr, name);
  879.                 dologout(0);
  880.             }
  881.         } else {
  882.             reply(530, "User %s unknown.", name);
  883.             syslog(LOG_NOTICE,
  884.               "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s [%s], %s",
  885.                    remotehost, remoteaddr, name);
  886.         }
  887.         return;
  888.     }
  889.     if ((pw = sgetpwnam(name)) != NULL) {
  890.         if ((shell = pw->pw_shell) == NULL || *shell == 0)
  891.             shell = _PATH_BSHELL;
  892.         while ((cp = getusershell()) != NULL)
  893.             if (strcmp(cp, shell) == 0)
  894.                 break;
  895.         endusershell();
  896.         if (cp == NULL || checkuser(name)) {
  897.             reply(530, "User %s access denied...", name);
  898.             if (logging)
  899.                 syslog(LOG_NOTICE,
  900.                        "FTP LOGIN REFUSED (bad shell) FROM %s [%s], %s",
  901.                        remotehost, remoteaddr, name);
  902.             pw = (struct passwd *) NULL;
  903.             return;
  904.         }
  905.         /* if user is a member of any of the guestgroups, cause a chroot() */
  906.         /* after they log in successfully                                  */
  907.         guest = acl_guestgroup(pw);
  908.     }
  909.     if (access_ok(530) < 1) {
  910.         reply(530, "User %s access denied....", name);
  911.         syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  912.                remotehost, remoteaddr, name);
  913.         return;
  914.     } else
  915.         acl_setfunctions();
  916.  
  917.     reply(331, "Password required for %s.", name);
  918.     askpasswd = 1;
  919.     /* Delay before reading passwd after first failed attempt to slow down
  920.      * passwd-guessing programs. */
  921.     if (login_attempts)
  922.         sleep((unsigned) login_attempts);
  923. }
  924.  
  925. /* Check if a user is in the file _PATH_FTPUSERS */
  926. checkuser(char *name)
  927. {
  928.     register FILE *fd;
  929.     register char *p;
  930.     char line[BUFSIZ];
  931.  
  932.     if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
  933.         while (fgets(line, sizeof(line), fd) != NULL)
  934.             if ((p = strchr(line, '\n')) != NULL) {
  935.                 *p = '\0';
  936.                 if (line[0] == '#')
  937.                     continue;
  938.                 if (strcmp(line, name) == 0) {
  939.                     (void) fclose(fd);
  940.                     return (1);
  941.                 }
  942.             }
  943.         (void) fclose(fd);
  944.     }
  945.     return (0);
  946. }
  947.  
  948. /* Terminate login as previous user, if any, resetting state; used when USER
  949.  * command is given or login fails. */
  950. end_login(void)
  951. {
  952.  
  953.     (void) seteuid((uid_t) 0);
  954.     if (logged_in)
  955.         logwtmp(ttyline, "", "");
  956.     pw = NULL;
  957.     logged_in = 0;
  958.     anonymous = 0;
  959.     guest = 0;
  960. }
  961.  
  962. int
  963. validate_eaddr(char *eaddr)
  964. {
  965.     int i,
  966.       host,
  967.       state;
  968.  
  969.     for (i = host = state = 0; eaddr[i] != '\0'; i++) {
  970.         switch (eaddr[i]) {
  971.         case '.':
  972.             if (!host)
  973.                 return 0;
  974.             if (state == 2)
  975.                 state = 3;
  976.             host = 0;
  977.             break;
  978.         case '@':
  979.             if (!host || state > 1 || !strncasecmp("ftp", eaddr + i - host, host))
  980.                 return 0;
  981.             state = 2;
  982.             host = 0;
  983.             break;
  984.         case '!':
  985.         case '%':
  986.             if (!host || state > 1)
  987.                 return 0;
  988.             state = 1;
  989.             host = 0;
  990.             break;
  991.         case '-':
  992.             break;
  993.         default:
  994.             host++;
  995.         }
  996.     }
  997.     if (((state == 3) && host > 1) || ((state == 2) && !host) ||
  998.         ((state == 1) && host > 1))
  999.         return 1;
  1000.     else
  1001.         return 0;
  1002. }
  1003.  
  1004. pass(char *passwd)
  1005. {
  1006.     char *xpasswd,
  1007.      *salt;
  1008.  
  1009. #ifdef ULTRIX_AUTH
  1010.     int numfails;
  1011. #endif /* ULTRIX_AUTH */
  1012.  
  1013.     if (logged_in || askpasswd == 0) {
  1014.         reply(503, "Login with USER first.");
  1015.         return;
  1016.     }
  1017.     askpasswd = 0;
  1018.  
  1019.     /* Disable lreply() if the first character of the password is '-' since
  1020.      * some hosts don't understand continuation messages and hang... */
  1021.  
  1022.     if (*passwd == '-')
  1023.         dolreplies = 0;
  1024.     else
  1025.         dolreplies = 1;
  1026.  
  1027.     if (!anonymous) {           /* "ftp" is only account allowed no password */
  1028.         if (*passwd == '-')
  1029.             passwd++;
  1030. #ifdef SHADOW_PASSWORD
  1031.         if (pw) {
  1032.            struct spwd *spw = getspnam( pw->pw_name );
  1033.            if( !spw ) { pw->pw_passwd = ""; }
  1034.            else { pw->pw_passwd = spw->sp_pwdp; }
  1035.         }
  1036. #endif
  1037.  
  1038.         *guestpw = NULL;
  1039.         if (pw == NULL)
  1040.             salt = "xx";
  1041.         else
  1042.             salt = pw->pw_passwd;
  1043. #ifdef KERBEROS
  1044.         xpasswd = crypt16(passwd, salt);
  1045. #else
  1046.         xpasswd = crypt(passwd, salt);
  1047. #endif
  1048.  
  1049. #ifdef ULTRIX_AUTH
  1050.         if ((numfails = ultrix_check_pass(passwd, xpasswd)) < 0) {
  1051. #else
  1052.         /* The strcmp does not catch null passwords! */
  1053.         if (pw == NULL || *pw->pw_passwd == '\0' ||
  1054.             strcmp(xpasswd, pw->pw_passwd)) {
  1055. #endif
  1056.             reply(530, "Login incorrect.");
  1057.  
  1058. #ifdef LOG_FAILED                       /* 27-Apr-93    EHK/BM             */
  1059.             syslog(LOG_INFO, "failed login from %s [%s], %s",
  1060.                               remotehost, remoteaddr, the_user);
  1061. #endif
  1062.             acl_remove();
  1063.  
  1064.             pw = NULL;
  1065.             if (++login_attempts >= lgi_failure_threshold) {
  1066.                 syslog(LOG_NOTICE, "repeated login failures from %s [%s]",
  1067.                        remotehost, remoteaddr);
  1068.                 exit(0);
  1069.             }
  1070.             return;
  1071.         }
  1072.     } else {
  1073.         char *pwin,
  1074.          *pwout = guestpw;
  1075.         struct aclmember *entry = NULL;
  1076.         int valid;
  1077.  
  1078.         if (getaclentry("passwd-check", &entry) &&
  1079.             ARG0 && strcasecmp(ARG0, "none")) {
  1080.  
  1081.             if (!strcasecmp(ARG0, "rfc822"))
  1082.                 valid = validate_eaddr(passwd);
  1083.             else if (!strcasecmp(ARG0, "trivial"))
  1084.                 valid = (strchr(passwd, '@') == NULL) ? 0 : 1;
  1085.             else
  1086.                 valid = 1;
  1087.  
  1088.             if (!valid && ARG1 && !strcasecmp(ARG1, "enforce")) {
  1089.                 lreply(530, "The response '%s' is not valid", passwd);
  1090.                 lreply(530, "Please use your e-mail address as your password");
  1091.                 lreply(530, "   for example: %s@%s or %s@",
  1092.                        authenticated ? authuser : "joe", remotehost,
  1093.                        authenticated ? authuser : "joe");
  1094.                 lreply(530, "[%s will be added if password ends with @]",
  1095.                        remotehost);
  1096.                 reply(530, "Login incorrect.");
  1097.         acl_remove();    
  1098.                 if (++login_attempts >= lgi_failure_threshold) {
  1099.                     syslog(LOG_NOTICE, "repeated login failures from %s [%s]",
  1100.                            remotehost, remoteaddr);
  1101.                     exit(0);
  1102.                 }
  1103.                 return;
  1104.             } else if (!valid) {
  1105.                 lreply(230, "The response '%s' is not valid", passwd);
  1106.                 lreply(230,
  1107.                 "Next time please use your e-mail address as your password");
  1108.                 lreply(230, "        for example: %s@%s",
  1109.                        authenticated ? authuser : "joe", remotehost);
  1110.             }
  1111.         }
  1112.         if (!*passwd) {
  1113.             strcpy(guestpw, "[none_given]");
  1114.         } else {
  1115.             int cnt = sizeof(guestpw) - 2;
  1116.  
  1117.             for (pwin = passwd; *pwin && cnt--; pwin++)
  1118.                 if (!isgraph(*pwin))
  1119.                     *pwout++ = '_';
  1120.                 else
  1121.                     *pwout++ = *pwin;
  1122.         }
  1123.     }
  1124.  
  1125.     /* if autogroup command applies to user's class change pw->pw_gid */
  1126.     if (anonymous)
  1127.         (void) acl_autogroup(pw);
  1128.  
  1129.     login_attempts = 0;         /* this time successful */
  1130.     (void) setegid((gid_t) pw->pw_gid);
  1131.     (void) initgroups(pw->pw_name, pw->pw_gid);
  1132.  
  1133.     /* open wtmp before chroot */
  1134.     (void) sprintf(ttyline, "ftp%d", getpid());
  1135.     logwtmp(ttyline, pw->pw_name, remotehost);
  1136.     logged_in = 1;
  1137.  
  1138.     /* if logging is enabled, open logfile before chroot */
  1139.     if (log_outbound_xfers || log_incoming_xfers)
  1140.         xferlog = open(_PATH_XFERLOG, O_WRONLY | O_APPEND | O_CREAT, 0660);
  1141.  
  1142.     expand_id();
  1143.  
  1144.     if (anonymous || guest) {
  1145.         /* We MUST do a chdir() after the chroot. Otherwise the old current
  1146.          * directory will be accessible as "." outside the new root! */
  1147.         if (anonymous) {
  1148.             if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1149.                 reply(550, "Can't set guest privileges.");
  1150.                 goto bad;
  1151.             }
  1152.         } else if (guest) {
  1153.             char *sp;
  1154.  
  1155.             /* determine root and home directory */
  1156.  
  1157.             if ((sp = strstr(pw->pw_dir, "/./")) == NULL) {
  1158.                 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1159.                     reply(550, "Can't set guest privileges.");
  1160.                     goto bad;
  1161.                 }
  1162.             } else {
  1163.                 *sp++ = '\0';
  1164.  
  1165.                 if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) {
  1166.                     reply(550, "Can't set guest privileges.");
  1167.                     goto bad;
  1168.                 }
  1169.             }
  1170.         }
  1171.     } else {
  1172.         if (chdir(pw->pw_dir) < 0) {
  1173. #ifdef AMIGA
  1174.             if (chdir("SYS:") < 0) {
  1175. #else
  1176.             if (chdir("/") < 0) {
  1177. #endif
  1178.                 reply(530, "User %s: can't change directory to %s.",
  1179.                       pw->pw_name, pw->pw_dir);
  1180.                 goto bad;
  1181.             } else
  1182. #ifndef AMIGA
  1183.                 lreply(230, "No directory! Logging in with home=/");
  1184. #else
  1185.                 lreply(230, "No directory! Logging in with home=SYS:");
  1186. #endif
  1187.         }
  1188.     }
  1189.  
  1190. #ifdef AIX
  1191.     {
  1192.        /* AIX 3 lossage.  Don't ask.  It's undocumented.  */
  1193.        priv_t priv;
  1194.  
  1195.        priv.pv_priv[0] = 0;
  1196.        priv.pv_priv[1] = 0;
  1197.        setgroups(NULL, NULL);
  1198.        if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
  1199.                    &priv, sizeof(priv_t)) < 0 ||
  1200.            setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)pw->pw_uid) < 0 ||
  1201.            seteuid((uid_t)pw->pw_uid) < 0) {
  1202.                reply(550, "Can't set uid (AIX3).");
  1203.                goto bad;
  1204.        }
  1205.     }
  1206. # ifdef UID_DEBUG
  1207.     lreply(230, "ruid=%d, euid=%d, suid=%d, luid=%d", getuidx(ID_REAL),
  1208.          getuidx(ID_EFFECTIVE), getuidx(ID_SAVED), getuidx(ID_LOGIN));
  1209.     lreply(230, "rgid=%d, egid=%d, sgid=%d, lgid=%d", getgidx(ID_REAL),
  1210.          getgidx(ID_EFFECTIVE), getgidx(ID_SAVED), getgidx(ID_LOGIN));
  1211. #endif
  1212. #else
  1213.     if (seteuid((uid_t) pw->pw_uid) < 0) {
  1214.         reply(550, "Can't set uid.");
  1215.         goto bad;
  1216.     }
  1217. #endif
  1218.     /* * following two lines were inside the next scope... */
  1219.  
  1220.     show_message(230, LOG_IN);
  1221.     show_readme(230, LOG_IN);
  1222.  
  1223. #ifdef ULTRIX_AUTH
  1224.     if (!anonymous && numfails > 0) {
  1225.         lreply(230,
  1226.             "There have been %d unsuccessful login attempts on your account",
  1227.             numfails);
  1228.     }
  1229. #endif /* ULTRIX_AUTH */    
  1230.  
  1231.     if (anonymous) {
  1232.         (void) is_shutdown(0);  /* display any shutdown messages now */
  1233.  
  1234.         reply(230, "Guest login ok, access restrictions apply.");
  1235. #ifdef SETPROCTITLE
  1236.         sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
  1237.                     sizeof(proctitle) - sizeof(remotehost) -
  1238.                     sizeof(": anonymous/"), passwd);
  1239.         setproctitle("%s", proctitle);
  1240. #endif /* SETPROCTITLE */
  1241.         if (logging)
  1242.             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s [%s], %s",
  1243.                    remotehost, remoteaddr, passwd);
  1244.     } else {
  1245.         reply(230, "User %s logged in.%s", pw->pw_name, guest ?
  1246.               "  Access restrictions apply." : "");
  1247. #ifdef SETPROCTITLE
  1248.         sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
  1249.         setproctitle(proctitle);
  1250. #endif /* SETPROCTITLE */
  1251.         if (logging)
  1252.             syslog(LOG_INFO, "FTP LOGIN FROM %s [%s], %s",
  1253.                    remotehost, remoteaddr, pw->pw_name);
  1254.     }
  1255.     home = pw->pw_dir;          /* home dir for globbing */
  1256.     (void) umask(defumask);
  1257.     return;
  1258.   bad:
  1259.     /* Forget all about it... */
  1260.     xferlog = 0;
  1261.     end_login();
  1262. }
  1263.  
  1264. char *
  1265. opt_string(int options)
  1266. {
  1267.     static char buf[100];
  1268.     char *ptr = buf;
  1269.  
  1270.     if ((options & O_COMPRESS) != NULL)
  1271.         *ptr++ = 'C';
  1272.     if ((options & O_TAR) != NULL)
  1273.         *ptr++ = 'T';
  1274.     if ((options & O_UNCOMPRESS) != NULL)
  1275.         *ptr++ = 'U';
  1276.     if (options == 0)
  1277.         *ptr++ = '_';
  1278.     *ptr++ = '\0';
  1279.     return (buf);
  1280. }
  1281.  
  1282. retrieve(char *cmd, char *name)
  1283. {
  1284.     FILE *fin,
  1285.      *dout;
  1286.     struct stat st,
  1287.       junk;
  1288.     int (*closefunc) () = NULL;
  1289.     int options = 0;
  1290.     time_t start_time = time(NULL);
  1291.     static char *logname;
  1292.     char namebuf[MAXPATHLEN];
  1293.     struct convert *cptr;
  1294.  
  1295.     if (!cmd && stat(name, &st)) {
  1296.         char fnbuf[MAXPATHLEN],
  1297.          *ptr;
  1298.  
  1299.         cptr = cvtptr;
  1300.  
  1301.         if (cptr == NULL) {
  1302.             (void) reply(550, "%s: No such file OR directory.", name);
  1303.             return;
  1304.         }
  1305.  
  1306.         do {
  1307.             if (!(mangleopts & O_COMPRESS) && (cptr->options & O_COMPRESS))
  1308.                 continue;
  1309.             if (!(mangleopts & O_UNCOMPRESS) && (cptr->options & O_UNCOMPRESS))
  1310.                 continue;
  1311.             if (!(mangleopts & O_TAR) && (cptr->options & O_TAR))
  1312.                 continue;
  1313.  
  1314.             if ( (cptr->stripfix) && (cptr->postfix) ) {
  1315.                 int pfxlen = strlen(cptr->postfix);
  1316.         int sfxlen = strlen(cptr->stripfix);
  1317.                 int namelen = strlen(name);
  1318.                 (void) strcpy(fnbuf, name);
  1319.  
  1320.                 if (namelen <= pfxlen)
  1321.                     continue;
  1322.         if ((namelen - pfxlen + sfxlen) >= sizeof(fnbuf))
  1323.             continue;
  1324.  
  1325.         if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
  1326.             continue;
  1327.                 *(fnbuf + namelen - pfxlen) = '\0';
  1328.                 (void) strcat(fnbuf, cptr->stripfix);
  1329.                 if (stat(fnbuf, &st))
  1330.                     continue;
  1331.             } else if (cptr->postfix) {
  1332.                 int pfxlen = strlen(cptr->postfix);
  1333.                 int namelen = strlen(name);
  1334.  
  1335.                 if (namelen <= pfxlen)
  1336.                     continue;
  1337.                 (void) strcpy(fnbuf, name);
  1338.                 if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
  1339.                     continue;
  1340.                 *(fnbuf + namelen - pfxlen) = (char) NULL;
  1341.                 if (stat(fnbuf, &st))
  1342.                     continue;
  1343.             } else if (cptr->stripfix) {
  1344.                 (void) strcpy(fnbuf, name);
  1345.                 (void) strcat(fnbuf, cptr->stripfix);
  1346.                 if (stat(fnbuf, &st))
  1347.                     continue;
  1348.             } else {
  1349.                 (void) reply(550, "%s: No such file OR directory.", name);
  1350.                 return;
  1351.             }
  1352.  
  1353.             if (S_ISDIR(st.st_mode)) {
  1354.                 if (!(cptr->types & T_DIR)) {
  1355.                     (void) reply(550, "Cannot %s directories.", cptr->name);
  1356.                     return;
  1357.                 }
  1358.                 if (cptr->options & O_TAR) {
  1359.                     strcpy(namebuf, fnbuf);
  1360.                     strcat(namebuf, "/.notar");
  1361.                     if (!stat(namebuf, &junk)) {
  1362.                         (void) reply(550,
  1363.                                   "Sorry, you may not TAR that directory.");
  1364.                         return;
  1365.                     }
  1366.                 }
  1367.             }
  1368.  
  1369.             if (S_ISREG(st.st_mode) && !(cptr->types & T_REG)) {
  1370.                 (void) reply(550, "Cannot %s plain files.", cptr->name);
  1371.                 return;
  1372.             }
  1373.             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
  1374.                 (void) reply(550, "Cannot %s special files.", cptr->name);
  1375.                 return;
  1376.             }
  1377.             if (!(cptr->types & T_ASCII) && deny_badasciixfer(550, ""))
  1378.                 return;
  1379.  
  1380.             logname = fnbuf;
  1381.             options |= cptr->options;
  1382.  
  1383.             strcpy(namebuf, cptr->external_cmd);
  1384.             if ((ptr = strchr(namebuf, ' ')) != NULL)
  1385.                 *ptr = '\0';
  1386.             if (stat(namebuf, &st) != NULL) {
  1387.                 syslog(LOG_ERR, "external command %s not found",
  1388.                        namebuf);
  1389.                 (void) reply(550,
  1390.                 "Local error: conversion program not found. Cannot %s file.",
  1391.                              cptr->name);
  1392.                 return;
  1393.             }
  1394.             (void) retrieve(cptr->external_cmd, fnbuf);
  1395.  
  1396.             goto dolog;
  1397.         } while ( (cptr = cptr->next) != NULL );
  1398.  
  1399.     } else
  1400.         logname = (char *) NULL;
  1401.  
  1402. #ifdef AMIGA
  1403.     if (!IsInRoot (name))
  1404.     {
  1405.         reply(553, "%s: No such file or directory", name);
  1406.         return;
  1407.     }
  1408. #endif
  1409.  
  1410.     if (cmd == 0) {
  1411.         fin = fopen(name, "r"), closefunc = fclose;
  1412.         st.st_size = 0;
  1413.     } else {
  1414.         char line[BUFSIZ];
  1415.  
  1416.         (void) sprintf(line, cmd, name), name = line;
  1417.         fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose;
  1418.         st.st_size = -1;
  1419. #ifdef HAVE_ST_BLKSIZE
  1420.         st.st_blksize = BUFSIZ;
  1421. #endif
  1422.     }
  1423.     if (fin == NULL) {
  1424.         if (errno != 0)
  1425.             perror_reply(550, name);
  1426.         return;
  1427.     }
  1428.     if (cmd == 0 &&
  1429.         (fstat(fileno(fin), &st) < 0 || (st.st_mode & S_IFMT) != S_IFREG)) {
  1430.         reply(550, "%s: not a plain file.", name);
  1431.         goto done;
  1432.     }
  1433.     if (restart_point) {
  1434.         if (type == TYPE_A) {
  1435.             register int i,
  1436.               n,
  1437.               c;
  1438.  
  1439.             n = restart_point;
  1440.             i = 0;
  1441.             while (i++ < n) {
  1442.                 if ((c = getc(fin)) == EOF) {
  1443.                     perror_reply(550, name);
  1444.                     goto done;
  1445.                 }
  1446.                 if (c == '\n')
  1447.                     i++;
  1448.             }
  1449.         } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
  1450.             perror_reply(550, name);
  1451.             goto done;
  1452.         }
  1453.     }
  1454.     dout = dataconn(name, st.st_size, "w");
  1455.     if (dout == NULL)
  1456.         goto done;
  1457. #ifdef HAVE_ST_BLKSIZE
  1458.     send_data(fin, dout, st.st_blksize);
  1459. #else
  1460.     send_data(fin, dout, BUFSIZ);
  1461. #endif
  1462.     (void) fclose(dout);
  1463.  
  1464.   dolog:
  1465.     if (log_outbound_xfers && xferlog && (cmd == 0)) {
  1466.         char msg[MAXPATHLEN];
  1467.         int xfertime = time(NULL) - start_time;
  1468.         time_t curtime = time(NULL);
  1469.         int loop;
  1470.  
  1471.         if (!xfertime)
  1472.             xfertime++;
  1473.         realpath(logname ? logname : name, namebuf);
  1474.         for (loop = 0; namebuf[loop]; loop++)
  1475.             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
  1476.                 namebuf[loop] = '_';
  1477.         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
  1478.                 ctime(&curtime),
  1479.                 xfertime,
  1480.                 remotehost,
  1481.                 byte_count,
  1482.                 namebuf,
  1483.                 (type == TYPE_A) ? 'a' : 'b',
  1484.                 opt_string(options),
  1485.                 'o',
  1486.                 anonymous ? 'a' : 'r',
  1487.                 anonymous ? guestpw : pw->pw_name,
  1488.                 authenticated,
  1489.                 authenticated ? authuser : "*"
  1490.             );
  1491.         write(xferlog, msg, strlen(msg));
  1492.     }
  1493.     data = -1;
  1494.     pdata = -1;
  1495.   done:
  1496.     if (closefunc)
  1497.         (*closefunc) (fin);
  1498. }
  1499.  
  1500. store(char *name, char *mode, int unique)
  1501. {
  1502.     FILE *fout, *din;
  1503.     struct stat st;
  1504.     int (*closefunc) ();
  1505.     char *gunique(char *local);
  1506.     time_t start_time = time(NULL);
  1507.  
  1508.     struct aclmember *entry = NULL;
  1509.  
  1510.     int fdout;
  1511.  
  1512. #ifdef OVERWRITE
  1513.     int overwrite = 1;
  1514.  
  1515. #endif /* OVERWRITE */
  1516.  
  1517. #ifdef UPLOAD
  1518.     int open_flags = (O_RDWR | O_CREAT |
  1519.               ((mode && *mode == 'a') ? O_APPEND : O_TRUNC));
  1520.  
  1521.     mode_t oldmask;
  1522.     int f_mode = -1,
  1523.       match_value = -1;
  1524.     uid_t uid;
  1525.     gid_t gid;
  1526.     uid_t oldid;
  1527.     int trunc = O_TRUNC;
  1528.     int valid = 0;
  1529.  
  1530. #endif /* UPLOAD */
  1531.  
  1532.     if (unique && stat(name, &st) == 0 &&
  1533.         (name = gunique(name)) == NULL)
  1534.         return;
  1535.  
  1536.     /*
  1537.      * check the filename, is it legal?
  1538.      */
  1539.     if ( (fn_check(name)) <= 0 )
  1540.         return;
  1541.  
  1542. #ifdef OVERWRITE
  1543.     /* if overwrite permission denied and file exists... then deny the user
  1544.      * permission to write the file. */
  1545.     while (getaclentry("overwrite", &entry) && ARG0 && ARG1 != NULL) {
  1546.         if (type_match(ARG1))
  1547.             if (strcmp(ARG0, "yes") != 0) {
  1548.                 overwrite = 0;
  1549.                 open_flags |= O_EXCL;
  1550.             }
  1551.     }
  1552.  
  1553.     if (!overwrite && !stat(name, &st)) {
  1554.         reply(553, "%s: Permission denied. (Overwrite)", name);
  1555.         return;
  1556.     }
  1557. #endif /* OVERWRITE */
  1558.  
  1559. #ifdef UPLOAD
  1560.     if ( (match_value = upl_check(name, &uid, &gid, &f_mode, &valid)) < 0 )
  1561.         return;
  1562.  
  1563.     /* Only truncate on open if the file is not to be appended to. */
  1564.     if (mode[0] == 'a' || (mode[0] == 'r' && mode[0] == '+') || restart_point)
  1565.         trunc = 0;
  1566.  
  1567.     /* if the user has an explicit new file mode, than open the file using
  1568.      * that mode.  We must take care to not let the umask affect the file
  1569.      * mode.
  1570.      * 
  1571.      * else open the file and let the default umask determine the file mode. */
  1572.     if (f_mode >= 0) {
  1573.         oldmask = umask(0000);
  1574.         fdout = open(name, open_flags, f_mode);
  1575.         umask(oldmask);
  1576.     } else
  1577.         fdout = open(name, open_flags, 0666);
  1578.  
  1579.     if (fdout < 0) {
  1580.         perror_reply(553, name);
  1581.         return;
  1582.     }
  1583.     /* if we have a uid and gid, then use them. */
  1584.  
  1585.     if (valid > 0) {
  1586.         oldid = geteuid();
  1587.         (void) seteuid((uid_t) 0);
  1588.         if ((fchown(fdout, uid, gid)) < 0) {
  1589.             (void) seteuid(oldid);
  1590.             perror_reply(550, "fchown");
  1591.             return;
  1592.         }
  1593.         (void) seteuid(oldid);
  1594.     }
  1595. #endif /* UPLOAD */
  1596.  
  1597.     if (restart_point)
  1598.         mode = "r+w";
  1599.  
  1600. #ifdef UPLOAD
  1601.     fout = fdopen(fdout, mode);
  1602. #else
  1603.     fout = fopen(name, mode);
  1604. #endif /* UPLOAD */
  1605.  
  1606.     closefunc = fclose;
  1607.     if (fout == NULL) {
  1608.         perror_reply(553, name);
  1609.         return;
  1610.     }
  1611.     if (restart_point) {
  1612.         if (type == TYPE_A) {
  1613.             register int i,
  1614.               n,
  1615.               c;
  1616.  
  1617.             n = restart_point;
  1618.             i = 0;
  1619.             while (i++ < n) {
  1620.                 if ((c = getc(fout)) == EOF) {
  1621.                     perror_reply(550, name);
  1622.                     goto done;
  1623.                 }
  1624.                 if (c == '\n')
  1625.                     i++;
  1626.             }
  1627.             /* We must do this seek to "current" position because we are
  1628.              * changing from reading to writing. */
  1629.             if (fseek(fout, 0L, L_INCR) < 0) {
  1630.                 perror_reply(550, name);
  1631.                 goto done;
  1632.             }
  1633.         } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
  1634.             perror_reply(550, name);
  1635.             goto done;
  1636.         }
  1637.     }
  1638.     din = dataconn(name, (off_t) - 1, "r");
  1639.     if (din == NULL)
  1640.         goto done;
  1641.     if (receive_data(din, fout) == 0) {
  1642.         if (unique)
  1643.             reply(226, "Transfer complete (unique file name:%s).",
  1644.                   name);
  1645.         else
  1646.             reply(226, "Transfer complete.");
  1647.     }
  1648.     (void) fclose(din);
  1649.  
  1650.   dolog:
  1651.     if (log_incoming_xfers && xferlog) {
  1652.         char namebuf[MAXPATHLEN],
  1653.           msg[MAXPATHLEN];
  1654.         int xfertime = time(NULL) - start_time;
  1655.         time_t curtime = time(NULL);
  1656.         int loop;
  1657.  
  1658.         if (!xfertime)
  1659.             xfertime++;
  1660.         realpath(name, namebuf);
  1661.         for (loop = 0; namebuf[loop]; loop++)
  1662.             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
  1663.                 namebuf[loop] = '_';
  1664.         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
  1665.                 ctime(&curtime),
  1666.                 xfertime,
  1667.                 remotehost,
  1668.                 byte_count,
  1669.                 namebuf,
  1670.                 (type == TYPE_A) ? 'a' : 'b',
  1671.                 opt_string(0),
  1672.                 'i',
  1673.                 anonymous ? 'a' : 'r',
  1674.                 anonymous ? guestpw : pw->pw_name,
  1675.                 authenticated,
  1676.                 authenticated ? authuser : "*"
  1677.             );
  1678.         write(xferlog, msg, strlen(msg));
  1679.     }
  1680.     data = -1;
  1681.     pdata = -1;
  1682.   done:
  1683.     (*closefunc) (fout);
  1684. }
  1685.  
  1686. FILE *
  1687. getdatasock(char *mode)
  1688. {
  1689.     int s,
  1690.       on = 1,
  1691.       tries;
  1692.  
  1693.     if (data >= 0)
  1694.         return (fdopen(data, mode));
  1695.     (void) seteuid((uid_t) 0);
  1696.     s = socket(AF_INET, SOCK_STREAM, 0);
  1697.     if (s < 0)
  1698.         goto bad;
  1699.     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  1700.                    (char *) &on, sizeof(on)) < 0)
  1701.         goto bad;
  1702.     /* anchor socket to avoid multi-homing problems */
  1703.     data_source.sin_family = AF_INET;
  1704.     data_source.sin_addr = ctrl_addr.sin_addr;
  1705.     for (tries = 1;; tries++) {
  1706.         if (bind(s, (struct sockaddr *) &data_source,
  1707.                  sizeof(data_source)) >= 0)
  1708.             break;
  1709.         if (errno != EADDRINUSE || tries > 10)
  1710.             goto bad;
  1711.         sleep(tries);
  1712.     }
  1713. #if defined(M_UNIX) && !defined(_M_UNIX)  /* bug in old TCP/IP release */
  1714.     {
  1715.         struct linger li;
  1716.         li.l_onoff = 1;
  1717.         li.l_linger = 900;
  1718.         if (setsockopt(s, SOL_SOCKET, SO_LINGER,
  1719.           (char *)&li, sizeof(struct linger)) < 0) {
  1720.             syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  1721.             goto bad;
  1722.         }
  1723.     }
  1724. #endif
  1725.     (void) seteuid((uid_t) pw->pw_uid);
  1726.  
  1727. #ifdef IPTOS_THROUGHPUT
  1728.     on = IPTOS_THROUGHPUT;
  1729.     if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &on, sizeof(int)) < 0)
  1730.           syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  1731. #endif
  1732.  
  1733.     return (fdopen(s, mode));
  1734.   bad:
  1735.     (void) seteuid((uid_t) pw->pw_uid);
  1736.     (void) close(s);
  1737.     return (NULL);
  1738. }
  1739.  
  1740. FILE *
  1741. dataconn(char *name, off_t size, char *mode)
  1742. {
  1743.     char sizebuf[32];
  1744.     FILE *file;
  1745.     int retry = 0;
  1746. #ifdef IPTOS_LOWDELAY
  1747.     int tos;
  1748. #endif
  1749.  
  1750.     file_size = size;
  1751.     byte_count = 0;
  1752.     if (size != (off_t) - 1)
  1753.         (void) sprintf(sizebuf, " (%ld bytes)", size);
  1754.     else
  1755.         (void) strcpy(sizebuf, "");
  1756.     if (pdata >= 0) {
  1757.         struct sockaddr_in from;
  1758.         int s,
  1759.           fromlen = sizeof(from);
  1760.  
  1761.         s = accept(pdata, (struct sockaddr *) &from, &fromlen);
  1762.         if (s < 0) {
  1763.             reply(425, "Can't open data connection.");
  1764.             (void) close(pdata);
  1765.             pdata = -1;
  1766.             return (NULL);
  1767.         }
  1768.         (void) close(pdata);
  1769.         pdata = s;
  1770. #ifdef IPTOS_LOWDELAY
  1771.         tos = IPTOS_LOWDELAY;
  1772.         (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &tos,
  1773.                           sizeof(int));
  1774.  
  1775. #endif
  1776.         reply(150, "Opening %s mode data connection for %s%s.",
  1777.               type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1778.         return (fdopen(pdata, mode));
  1779.     }
  1780.     if (data >= 0) {
  1781.         reply(125, "Using existing data connection for %s%s.",
  1782.               name, sizebuf);
  1783.         usedefault = 1;
  1784.         return (fdopen(data, mode));
  1785.     }
  1786.     if (usedefault)
  1787.         data_dest = his_addr;
  1788.     usedefault = 1;
  1789.     file = getdatasock(mode);
  1790.     if (file == NULL) {
  1791.         reply(425, "Can't create data socket (%s,%d): %s.",
  1792.               inet_ntoa(data_source.sin_addr),
  1793.               ntohs(data_source.sin_port), strerror(errno));
  1794.         return (NULL);
  1795.     }
  1796.     data = fileno(file);
  1797.     while (connect(data, (struct sockaddr *) &data_dest,
  1798.                    sizeof(data_dest)) < 0) {
  1799.         if ((errno == EADDRINUSE || errno == EINTR) && retry < swaitmax) {
  1800.             sleep((unsigned) swaitint);
  1801.             retry += swaitint;
  1802.             continue;
  1803.         }
  1804.         perror_reply(425, "Can't build data connection");
  1805.         (void) fclose(file);
  1806.         data = -1;
  1807.         return (NULL);
  1808.     }
  1809.     reply(150, "Opening %s mode data connection for %s%s.",
  1810.           type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1811.     return (file);
  1812. }
  1813.  
  1814. /* Tranfer the contents of "instr" to "outstr" peer using the appropriate
  1815.  * encapsulation of the data subject to Mode, Structure, and Type.
  1816.  *
  1817.  * NB: Form isn't handled. */
  1818. send_data(FILE *instr, FILE *outstr, off_t blksize)
  1819. {
  1820.     register int c,
  1821.       cnt;
  1822.     register char *buf;
  1823.     int netfd,
  1824.       filefd;
  1825.  
  1826.     transflag++;
  1827.     if (setjmp(urgcatch)) {
  1828.         transflag = 0;
  1829.         return;
  1830.     }
  1831.     switch (type) {
  1832.  
  1833.     case TYPE_A:
  1834.         while ((c = getc(instr)) != EOF) {
  1835.             byte_count++;
  1836.             if (c == '\n') {
  1837.                 if (ferror(outstr))
  1838.                     goto data_err;
  1839.                 (void) putc('\r', outstr);
  1840.             }
  1841.             (void) putc(c, outstr);
  1842.         }
  1843.         fflush(outstr);
  1844.         transflag = 0;
  1845.         if (ferror(instr))
  1846.             goto file_err;
  1847.         if (ferror(outstr))
  1848.             goto data_err;
  1849.         reply(226, "Transfer complete.");
  1850.         return;
  1851.  
  1852.     case TYPE_I:
  1853.     case TYPE_L:
  1854.         if ((buf = (char *) malloc((u_int) blksize)) == NULL) {
  1855.             transflag = 0;
  1856.             perror_reply(451, "Local resource failure: malloc");
  1857.             return;
  1858.         }
  1859.         netfd = fileno(outstr);
  1860.         filefd = fileno(instr);
  1861.         while ((cnt = read(filefd, buf, (u_int) blksize)) > 0 &&
  1862.                write(netfd, buf, cnt) == cnt)
  1863.             byte_count += cnt;
  1864.         transflag = 0;
  1865.         (void) free(buf);
  1866.         if (cnt != 0) {
  1867.             if (cnt < 0)
  1868.                 goto file_err;
  1869.             goto data_err;
  1870.         }
  1871.         reply(226, "Transfer complete.");
  1872.         return;
  1873.     default:
  1874.         transflag = 0;
  1875.         reply(550, "Unimplemented TYPE %d in send_data", type);
  1876.         return;
  1877.     }
  1878.  
  1879.   data_err:
  1880.     transflag = 0;
  1881.     perror_reply(426, "Data connection");
  1882.     return;
  1883.  
  1884.   file_err:
  1885.     transflag = 0;
  1886.     perror_reply(551, "Error on input file");
  1887. }
  1888.  
  1889. /* Transfer data from peer to "outstr" using the appropriate encapulation of
  1890.  * the data subject to Mode, Structure, and Type.
  1891.  *
  1892.  * N.B.: Form isn't handled. */
  1893. receive_data(FILE *instr, FILE *outstr)
  1894. {
  1895.     register int c;
  1896.     int cnt,
  1897.       bare_lfs = 0;
  1898.     char buf[BUFSIZ];
  1899.  
  1900.     transflag++;
  1901.     if (setjmp(urgcatch)) {
  1902.         transflag = 0;
  1903.         return (-1);
  1904.     }
  1905.     switch (type) {
  1906.  
  1907.     case TYPE_I:
  1908.     case TYPE_L:
  1909.         while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
  1910.             if (write(fileno(outstr), buf, cnt) != cnt)
  1911.                 goto file_err;
  1912.             byte_count += cnt;
  1913.         }
  1914.         if (cnt < 0)
  1915.             goto data_err;
  1916.         transflag = 0;
  1917.         return (0);
  1918.  
  1919.     case TYPE_E:
  1920.         reply(553, "TYPE E not implemented.");
  1921.         transflag = 0;
  1922.         return (-1);
  1923.  
  1924.     case TYPE_A:
  1925.         while ((c = getc(instr)) != EOF) {
  1926.             byte_count++;
  1927.             if (c == '\n')
  1928.                 bare_lfs++;
  1929.             while (c == '\r') {
  1930.                 if (ferror(outstr))
  1931.                     goto data_err;
  1932.                 if ((c = getc(instr)) != '\n') {
  1933.                     (void) putc('\r', outstr);
  1934.                     if (c == '\0' || c == EOF)
  1935.                         goto contin2;
  1936.                 }
  1937.             }
  1938.             (void) putc(c, outstr);
  1939.           contin2:;
  1940.         }
  1941.         fflush(outstr);
  1942.         if (ferror(instr))
  1943.             goto data_err;
  1944.         if (ferror(outstr))
  1945.             goto file_err;
  1946.         transflag = 0;
  1947.         if (bare_lfs) {
  1948.             lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
  1949.             printf("   File may not have transferred correctly.\r\n");
  1950.         }
  1951.         return (0);
  1952.     default:
  1953.         reply(550, "Unimplemented TYPE %d in receive_data", type);
  1954.         transflag = 0;
  1955.         return (-1);
  1956.     }
  1957.  
  1958.   data_err:
  1959.     transflag = 0;
  1960.     perror_reply(426, "Data Connection");
  1961.     return (-1);
  1962.  
  1963.   file_err:
  1964.     transflag = 0;
  1965.     perror_reply(452, "Error writing file");
  1966.     return (-1);
  1967. }
  1968.  
  1969. statfilecmd(char *filename)
  1970. {
  1971.     char line[BUFSIZ];
  1972.     FILE *fin;
  1973.     int c;
  1974.  
  1975.     if (anonymous && dolreplies)
  1976.         (void) sprintf(line, ls_long, filename);
  1977.     else
  1978.         (void) sprintf(line, ls_short, filename);
  1979.     fin = ftpd_popen(line, "r", 0);
  1980.     lreply(211, "status of %s:", filename);
  1981.     while ((c = getc(fin)) != EOF) {
  1982.         if (c == '\n') {
  1983.             if (ferror(stdout)) {
  1984.                 perror_reply(421, "control connection");
  1985.                 (void) ftpd_pclose(fin);
  1986.                 dologout(1);
  1987.                 /* NOTREACHED */
  1988.             }
  1989.             if (ferror(fin)) {
  1990.                 perror_reply(551, filename);
  1991.                 (void) ftpd_pclose(fin);
  1992.                 return;
  1993.             }
  1994.             (void) putc('\r', stdout);
  1995.         }
  1996.         (void) putc(c, stdout);
  1997.     }
  1998.     (void) ftpd_pclose(fin);
  1999.     reply(211, "End of Status");
  2000. }
  2001.  
  2002. statcmd(void)
  2003. {
  2004.     struct sockaddr_in *sin;
  2005.     u_char *a,
  2006.      *p;
  2007.  
  2008.     lreply(211, "%s FTP server status:", hostname);
  2009.     printf("     %s\r\n", version);
  2010.     printf("     Connected to %s", remotehost);
  2011.     if (!isdigit(remotehost[0]))
  2012.         printf(" (%s)", inet_ntoa(his_addr.sin_addr));
  2013.     printf("\r\n");
  2014.     if (logged_in) {
  2015.         if (anonymous)
  2016.             printf("     Logged in anonymously\r\n");
  2017.         else
  2018.             printf("     Logged in as %s\r\n", pw->pw_name);
  2019.     } else if (askpasswd)
  2020.         printf("     Waiting for password\r\n");
  2021.     else
  2022.         printf("     Waiting for user name\r\n");
  2023.     printf("     TYPE: %s", typenames[type]);
  2024.     if (type == TYPE_A || type == TYPE_E)
  2025.         printf(", FORM: %s", formnames[form]);
  2026.     if (type == TYPE_L)
  2027. #if NBBY == 8
  2028.         printf(" %d", NBBY);
  2029. #else
  2030.         printf(" %d", bytesize);/* need definition! */
  2031. #endif
  2032.     printf("; STRUcture: %s; transfer MODE: %s\r\n",
  2033.            strunames[stru], modenames[mode]);
  2034.     if (data != -1)
  2035.         printf("     Data connection open\r\n");
  2036.     else if (pdata != -1) {
  2037.         printf("     in Passive mode");
  2038.         sin = &pasv_addr;
  2039.         goto printaddr;
  2040.     } else if (usedefault == 0) {
  2041.         printf("     PORT");
  2042.         sin = &data_dest;
  2043.       printaddr:
  2044.         a = (u_char *) & sin->sin_addr;
  2045.         p = (u_char *) & sin->sin_port;
  2046. #define UC(b) (((int) b) & 0xff)
  2047.         printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
  2048.                UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  2049. #undef UC
  2050.     } else
  2051.         printf("     No data connection\r\n");
  2052.     reply(211, "End of status");
  2053. }
  2054.  
  2055. fatal(char *s)
  2056. {
  2057.     reply(451, "Error in server: %s\n", s);
  2058.     reply(221, "Closing connection due to server error.");
  2059.     dologout(0);
  2060.     /* NOTREACHED */
  2061. }
  2062.  
  2063. #if defined (HAVE_VPRINTF)
  2064. /* VARARGS2 */
  2065. reply(va_alist)
  2066.   va_dcl
  2067. {
  2068.     int n;
  2069.     char *fmt;
  2070.     va_list ap;
  2071.     
  2072.     va_start(ap);
  2073.     /* first argument is always the return code */
  2074.     n = va_arg(ap, int);
  2075.     /* second argument is always fmt string     */
  2076.     fmt = va_arg(ap, char *);
  2077.  
  2078.     if (autospout != NULL) {
  2079.         char *ptr = autospout;
  2080.  
  2081.         printf("%d-", n);
  2082.         while (*ptr) {
  2083.             if (*ptr == '\n') {
  2084.                 fputs("\r\n", stdout);
  2085.                 if (*(++ptr))
  2086.                     printf("%03d-", n);
  2087.             } else {
  2088. #ifndef AMIGA
  2089.                 putchar(*ptr++);
  2090. #else
  2091.                 putchar(*ptr);
  2092.                 *ptr++;
  2093. #endif
  2094.             }
  2095.         }
  2096.         if (*(--ptr) != '\n')
  2097.             printf("\r\n");
  2098.         if (autospout_free) {
  2099.             (void) free(autospout);
  2100.             autospout_free = 0;
  2101.         }
  2102.         autospout = 0;
  2103.     }
  2104.     printf("%d ", n);
  2105.     vprintf(fmt, ap);
  2106.     printf("\r\n");
  2107.     (void) fflush(stdout);
  2108.  
  2109.     if (debug) {
  2110.         char buf[BUFSIZ];
  2111.         (void) vsprintf(buf, fmt, ap);
  2112.  
  2113.         syslog(LOG_DEBUG, "<--- %d ", n);
  2114.         syslog(LOG_DEBUG, buf);
  2115.     }
  2116.  
  2117.     va_end(ap);
  2118. }
  2119.  
  2120. /* VARARGS2 */
  2121. lreply(va_alist)
  2122.   va_dcl
  2123. {
  2124.     va_list ap;
  2125.     int n;
  2126.     char *fmt;
  2127.  
  2128.     va_start(ap);
  2129.     /* first argument is always the return code */
  2130.     n = va_arg(ap, int);
  2131.     /* second argument is always fmt string     */
  2132.     fmt = va_arg(ap, char *);
  2133.  
  2134.     if (!dolreplies)
  2135.         return;
  2136.     printf("%d-", n);
  2137.     vprintf(fmt, ap);
  2138.     printf("\r\n");
  2139.     (void) fflush(stdout);
  2140.  
  2141.     if (debug) {
  2142.         char buf[BUFSIZ];
  2143.         (void) vsprintf(buf, fmt, ap);
  2144.  
  2145.         syslog(LOG_DEBUG, "<--- %d- ", n);
  2146.         syslog(LOG_DEBUG, buf);
  2147.     }
  2148.  
  2149.     va_end(ap);
  2150. }
  2151.  
  2152. #else
  2153. /* VARARGS2 */
  2154. reply(int n, char *fmt, int p0, int p1, int p2, int p3, int p4, int p5)
  2155. {
  2156.     if (autospout != NULL) {
  2157.         char *ptr = autospout;
  2158.  
  2159.         printf("%d-", n);
  2160.         while (*ptr) {
  2161.             if (*ptr == '\n') {
  2162.                 printf("\r\n");
  2163.                 if (*(++ptr))
  2164.                     printf("%d-", n);
  2165.             } else {
  2166. #ifndef AMIGA
  2167.                 putchar(*ptr++);
  2168. #else
  2169.                 putchar(*ptr);
  2170.                 *ptr++;
  2171. #endif
  2172.             }
  2173.         }
  2174.         if (*(--ptr) != '\n')
  2175.             printf("\r\n");
  2176.         if (autospout_free) {
  2177.             (void) free(autospout);
  2178.             autospout_free = 0;
  2179.         }
  2180.         autospout = 0;
  2181.     }
  2182.     printf("%d ", n);
  2183.     printf(fmt, p0, p1, p2, p3, p4, p5);
  2184.     printf("\r\n");
  2185.     (void) fflush(stdout);
  2186.     if (debug) {
  2187.         syslog(LOG_DEBUG, "<--- %d ", n);
  2188.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  2189.     }
  2190. }
  2191.  
  2192. /* VARARGS2 */
  2193. lreply(int n, char *fmt, int p0, int p1, int p2, int p3, int p4, int p5)
  2194. {
  2195.     if (!dolreplies)
  2196.         return;
  2197.     printf("%d-", n);
  2198.     printf(fmt, p0, p1, p2, p3, p4, p5);
  2199.     printf("\r\n");
  2200.     (void) fflush(stdout);
  2201.     if (debug) {
  2202.         syslog(LOG_DEBUG, "<--- %d- ", n);
  2203.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  2204.     }
  2205. }
  2206. #endif
  2207.  
  2208. ack(char *s)
  2209. {
  2210.     reply(250, "%s command successful.", s);
  2211. }
  2212.  
  2213. nack(char *s)
  2214. {
  2215.     reply(502, "%s command not implemented.", s);
  2216. }
  2217.  
  2218. /* ARGSUSED */
  2219. yyerror(char *s)
  2220. {
  2221.     char *cp;
  2222.  
  2223.     if ((cp = strchr(cbuf, '\n')) != NULL)
  2224.         *cp = '\0';
  2225.     reply(500, "'%s': command not understood.", cbuf);
  2226. }
  2227.  
  2228. delete(char *name)
  2229. {
  2230.     struct stat st;
  2231.  
  2232. #ifdef AMIGA
  2233.     if (!IsInRoot (name))
  2234.     {
  2235.         reply(553, "%s: No such file or directory.", name);
  2236.         return;
  2237.     }
  2238. #endif
  2239.  
  2240.     /*
  2241.      * delete permission?
  2242.      */
  2243.  
  2244.     if ( (del_check(name)) == 0 )
  2245.         return;
  2246.  
  2247.     if (lstat(name, &st) < 0) {
  2248.         perror_reply(550, name);
  2249.         return;
  2250.     }
  2251.     if ((st.st_mode & S_IFMT) == S_IFDIR) {
  2252.         if (rmdir(name) < 0) {
  2253.             perror_reply(550, name);
  2254.             return;
  2255.         }
  2256.         goto done;
  2257.     }
  2258.     if (unlink(name) < 0) {
  2259.         perror_reply(550, name);
  2260.         return;
  2261.     }
  2262.   done:
  2263.     {
  2264.         char path[MAXPATHLEN];
  2265.  
  2266.         realpath(name, path);
  2267.  
  2268.         if (anonymous) {
  2269.             syslog(LOG_NOTICE, "%s of %s [%s] deleted %s", guestpw, remotehost,
  2270.                    remoteaddr, path);
  2271.         } else {
  2272.             syslog(LOG_NOTICE, "%s of %s [%s] deleted %s", pw->pw_name,
  2273.                    remotehost, remoteaddr, path);
  2274.         }
  2275.     }
  2276.  
  2277.     ack("DELE");
  2278. }
  2279.  
  2280. cwd(char *path)
  2281. {
  2282.     struct aclmember *entry = NULL;
  2283.     char cdpath[MAXPATHLEN + 1];
  2284.  
  2285.     if (chdir(path) < 0) {
  2286.         /* alias checking */
  2287.         while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) {
  2288.             if (!strcasecmp(ARG0, path)) {
  2289.                 if (chdir(ARG1) < 0)
  2290.                     perror_reply(550, path);
  2291.                 else {
  2292.                     show_message(250, C_WD);
  2293.                     show_readme(250, C_WD);
  2294.                     ack("CWD");
  2295.                 }
  2296.                 return;
  2297.             }
  2298.         }
  2299.     /* check for "cdpath" directories. */
  2300.     entry = (struct aclmember *) NULL;
  2301.         while (getaclentry("cdpath", &entry) && ARG0 != NULL) {
  2302.         strcpy(cdpath,ARG0);
  2303.         strcat(cdpath,"/");
  2304.         strcat(cdpath,path);
  2305.             if (chdir(cdpath) >= 0) {
  2306.                 show_message(250, C_WD);
  2307.                 show_readme(250, C_WD);
  2308.                 ack("CWD");
  2309.                 return;
  2310.             }
  2311.         }
  2312.         perror_reply(550,path);
  2313.     } else {
  2314.         show_message(250, C_WD);
  2315.         show_readme(250, C_WD);
  2316.         ack("CWD");
  2317.     }
  2318. }
  2319.  
  2320. makedir(char *name)
  2321. {
  2322.     uid_t uid;
  2323.     gid_t gid;
  2324.     int   valid = 0;
  2325.  
  2326.     /*
  2327.      * check the directory, can we mkdir here?
  2328.      */
  2329.     if ( (dir_check(name, &uid, &gid, &valid)) <= 0 )
  2330.         return;
  2331.  
  2332.     /*
  2333.      * check the filename, is it legal?
  2334.      */
  2335.     if ( (fn_check(name)) <= 0 )
  2336.         return;
  2337.  
  2338.     if (mkdir(name, 0777) < 0) {
  2339.         perror_reply(550, name);
  2340.     return;
  2341.     }
  2342.  
  2343.     reply(257, "MKD command successful.");
  2344. }
  2345.  
  2346. removedir(char *name)
  2347. {
  2348.     int c, d;  /* dummy variables */
  2349.         int valid = 0;
  2350.  
  2351.     /*
  2352.      * check the directory, can we rmdir here?
  2353.      */
  2354.     if ( (dir_check(name, &c, &d, &valid)) <= 0 )
  2355.         return;
  2356.  
  2357.     /*
  2358.      * delete permission?
  2359.      */
  2360.  
  2361.     if ( (del_check(name)) == 0 )
  2362.         return;
  2363.  
  2364.     if (rmdir(name) < 0)
  2365.         perror_reply(550, name);
  2366.     else
  2367.         ack("RMD");
  2368. }
  2369.  
  2370. pwd(void)
  2371. {
  2372.     char path[MAXPATHLEN + 1];
  2373. #ifdef HAVE_GETCWD
  2374.     extern char *getcwd();
  2375. #else
  2376.     extern char *getwd(char *);
  2377. #endif
  2378.  
  2379. #ifdef HAVE_GETCWD
  2380.     if (getcwd(path,MAXPATHLEN) == (char *) NULL)
  2381. #else
  2382.     if (getwd(path) == (char *) NULL)
  2383. #endif
  2384.         reply(550, "%s.", path);
  2385.     else
  2386.         reply(257, "\"%s\" is current directory.", path);
  2387. }
  2388.  
  2389. char *
  2390. renamefrom(char *name)
  2391. {
  2392.     struct stat st;
  2393.  
  2394.     if (lstat(name, &st) < 0) {
  2395.         perror_reply(550, name);
  2396.         return ((char *) 0);
  2397.     }
  2398.  
  2399.     /* if rename permission denied and file exists... then deny the user
  2400.      * permission to rename the file. 
  2401.      */
  2402.     while (getaclentry("rename", &entry) && ARG0 && ARG1 != NULL) {
  2403.         if (type_match(ARG1))
  2404.             if (strcmp(ARG0, "yes")) {
  2405.                 reply(553, "%s: Permission denied. (rename)", name);
  2406.                 return ((char *) 0);
  2407.             }
  2408.     }
  2409.  
  2410.     reply(350, "File exists, ready for destination name");
  2411.     return (name);
  2412. }
  2413.  
  2414. renamecmd(char *from, char *to)
  2415. {
  2416.  
  2417.     /*
  2418.      * check the filename, is it legal?
  2419.      */
  2420.     if ( (fn_check(to)) == 0 )
  2421.         return;
  2422.  
  2423. #ifdef AMIGA
  2424.     if (!IsInRoot (to))
  2425.     {
  2426.         reply(553, "Could not determine cwdir: No such file or directory.");
  2427.         return;
  2428.     }
  2429. #endif
  2430.  
  2431.     if (rename(from, to) < 0)
  2432.         perror_reply(550, "rename");
  2433.     else
  2434.         ack("RNTO");
  2435. }
  2436.  
  2437. dolog(struct sockaddr_in *sin)
  2438. {
  2439.     struct hostent *hp;
  2440.     char *blah;
  2441.  
  2442. #ifdef    DNS_TRYAGAIN
  2443.     int num_dns_tries = 0;
  2444.     /*
  2445.      * 27-Apr-93    EHK/BM
  2446.      * far away connections might take some time to get their IP address
  2447.      * resolved. That's why we try again -- maybe our DNS cache has the
  2448.      * PTR-RR now. This code is sloppy. Far better is to check what the
  2449.      * resolver returned so that in case of error, there's no need to
  2450.      * try again.
  2451.      */
  2452. dns_again:
  2453.      hp = gethostbyaddr((char *) &sin->sin_addr,
  2454.                                 sizeof (struct in_addr), AF_INET);
  2455.  
  2456.      if ( !hp && ++num_dns_tries <= 1 ) {
  2457.         sleep(3);
  2458.         goto dns_again;         /* try DNS lookup once more     */
  2459.      }
  2460. #else
  2461.     hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
  2462. #endif
  2463.  
  2464.     blah = inet_ntoa(sin->sin_addr);
  2465.  
  2466.     (void) strncpy(remoteaddr, blah, sizeof(remoteaddr));
  2467.  
  2468.     if (!strcmp(remoteaddr, "0.0.0.0")) {
  2469.         nameserved = 1;
  2470.         strncpy(remotehost, "localhost", sizeof(remotehost));
  2471.     } else {
  2472.         if (hp) {
  2473.             nameserved = 1;
  2474.             (void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
  2475.         } else {
  2476.             nameserved = 0;
  2477.             (void) strncpy(remotehost, remoteaddr, sizeof(remotehost));
  2478.         }
  2479.     }
  2480.  
  2481. #ifdef SETPROCTITLE
  2482.     sprintf(proctitle, "%s: connected", remotehost);
  2483.     setproctitle(proctitle);
  2484. #endif /* SETPROCTITLE */
  2485.  
  2486.     if (logging)
  2487.         syslog(LOG_INFO, "connection from %s [%s]", remotehost,
  2488.                remoteaddr);
  2489. }
  2490.  
  2491. /* Record logout in wtmp file and exit with supplied status. */
  2492. dologout(int status)
  2493. {
  2494.     if (logged_in) {
  2495.         (void) seteuid((uid_t) 0);
  2496.         logwtmp(ttyline, "", "");
  2497.     }
  2498.     syslog(LOG_INFO, "FTP session closed");
  2499.     if (xferlog)
  2500.         close(xferlog);
  2501.     acl_remove();
  2502.     /* beware of flushing buffers after a SIGPIPE */
  2503.     _exit(status);
  2504. }
  2505.  
  2506. SIGNAL_TYPE
  2507. myoob(int sig)
  2508. {
  2509.     char *cp;
  2510.  
  2511.     /* only process if transfer occurring */
  2512.     if (!transflag)
  2513.         return;
  2514.     cp = tmpline;
  2515.     if (getline(cp, 7, stdin) == NULL) {
  2516.         reply(221, "You could at least say goodbye.");
  2517.         dologout(0);
  2518.     }
  2519.     upper(cp);
  2520.     if (strcmp(cp, "ABOR\r\n") == 0) {
  2521.         tmpline[0] = '\0';
  2522.         reply(426, "Transfer aborted. Data connection closed.");
  2523.         reply(226, "Abort successful");
  2524.         longjmp(urgcatch, 1);
  2525.     }
  2526.     if (strcmp(cp, "STAT\r\n") == 0) {
  2527.         if (file_size != (off_t) - 1)
  2528.             reply(213, "Status: %lu of %lu bytes transferred",
  2529.                   byte_count, file_size);
  2530.         else
  2531.             reply(213, "Status: %lu bytes transferred", byte_count);
  2532.     }
  2533. }
  2534.  
  2535. /* Note: a response of 425 is not mentioned as a possible response to the
  2536.  * PASV command in RFC959. However, it has been blessed as a legitimate
  2537.  * response by Jon Postel in a telephone conversation with Rick Adams on 25
  2538.  * Jan 89. */
  2539. passive(void)
  2540. {
  2541.     int len;
  2542.     register char *p,
  2543.      *a;
  2544.  
  2545.     pdata = socket(AF_INET, SOCK_STREAM, 0);
  2546.     if (pdata < 0) {
  2547.         perror_reply(425, "Can't open passive connection");
  2548.         return;
  2549.     }
  2550.     pasv_addr = ctrl_addr;
  2551.     pasv_addr.sin_port = 0;
  2552.     (void) seteuid((uid_t) 0);
  2553.     if (bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr)) < 0) {
  2554.         (void) seteuid((uid_t) pw->pw_uid);
  2555.         goto pasv_error;
  2556.     }
  2557.     (void) seteuid((uid_t) pw->pw_uid);
  2558.     len = sizeof(pasv_addr);
  2559.     if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
  2560.         goto pasv_error;
  2561.     if (listen(pdata, 1) < 0)
  2562.         goto pasv_error;
  2563.     a = (char *) &pasv_addr.sin_addr;
  2564.     p = (char *) &pasv_addr.sin_port;
  2565.  
  2566. #define UC(b) (((int) b) & 0xff)
  2567.  
  2568.     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  2569.           UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  2570.     return;
  2571.  
  2572.   pasv_error:
  2573.     (void) close(pdata);
  2574.     pdata = -1;
  2575.     perror_reply(425, "Can't open passive connection");
  2576.     return;
  2577. }
  2578.  
  2579. /* Generate unique name for file with basename "local". The file named
  2580.  * "local" is already known to exist. Generates failure reply on error. */
  2581. char *
  2582. gunique(char *local)
  2583. {
  2584.     static char new[MAXPATHLEN];
  2585.     struct stat st;
  2586.     char *cp = strrchr(local, '/');
  2587.     int count = 0;
  2588.  
  2589.     if (cp)
  2590.         *cp = '\0';
  2591. #ifndef AMIGA
  2592.     if (stat(cp ? local : ".", &st) < 0) {
  2593.         perror_reply(553, cp ? local : ".");
  2594. #else
  2595.     if (stat(cp ? local : "", &st) < 0) {
  2596.         perror_reply(553, cp ? local : "");
  2597. #endif
  2598.         return ((char *) 0);
  2599.     }
  2600.     if (cp)
  2601.         *cp = '/';
  2602.     (void) strcpy(new, local);
  2603.     cp = new + strlen(new);
  2604.     *cp++ = '.';
  2605.     for (count = 1; count < 100; count++) {
  2606.         (void) sprintf(cp, "%d", count);
  2607.         if (stat(new, &st) < 0)
  2608.             return (new);
  2609.     }
  2610.     reply(452, "Unique file name cannot be created.");
  2611.     return ((char *) 0);
  2612. }
  2613.  
  2614. /* Format and send reply containing system error number. */
  2615. perror_reply(int code, char *string)
  2616. {
  2617.     reply(code, "%s: %s.", string, strerror(errno));
  2618. }
  2619.  
  2620. static char *onefile[] =
  2621. {"", 0};
  2622.  
  2623. send_file_list(char *whichfiles)
  2624. {
  2625.     struct stat st;
  2626.     DIR *dirp = NULL;
  2627.  
  2628. #ifdef HAVE_DIRENT
  2629.     struct dirent *dir;
  2630. #else
  2631.     struct direct *dir;
  2632. #endif
  2633.  
  2634.     FILE *dout = NULL;
  2635.     register char **dirlist,
  2636.      *dirname;
  2637.     int simple = 0;
  2638.     char *strpbrk(const char *, const char *);
  2639.  
  2640.     if (strpbrk(whichfiles, "~{[*?") != NULL) {
  2641.         extern char **ftpglob(register char *v),
  2642.          *globerr;
  2643.  
  2644.         globerr = NULL;
  2645.         dirlist = ftpglob(whichfiles);
  2646.         if (globerr != NULL) {
  2647.             reply(550, globerr);
  2648.             return;
  2649.         } else if (dirlist == NULL) {
  2650.             errno = ENOENT;
  2651.             perror_reply(550, whichfiles);
  2652.             return;
  2653.         }
  2654.     } else {
  2655.         onefile[0] = whichfiles;
  2656.         dirlist = onefile;
  2657.         simple = 1;
  2658.     }
  2659.  
  2660.     if (setjmp(urgcatch)) {
  2661.         transflag = 0;
  2662.         return;
  2663.     }
  2664.     while ((dirname = *dirlist++) != NULL) {
  2665.         if (stat(dirname, &st) < 0) {
  2666.             /* If user typed "ls -l", etc, and the client used NLST, do what
  2667.              * the user meant. */
  2668.             if (dirname[0] == '-' && *dirlist == NULL && transflag == 0) {
  2669. #ifdef AMIGA
  2670.                 retrieve("AmiTCP:bin/ls %s", dirname);
  2671. #else
  2672.                 retrieve("/bin/ls %s", dirname);
  2673. #endif
  2674.                 return;
  2675.             }
  2676.             perror_reply(550, whichfiles);
  2677.             if (dout != NULL) {
  2678.                 (void) fclose(dout);
  2679.                 transflag = 0;
  2680.                 data = -1;
  2681.                 pdata = -1;
  2682.             }
  2683.             return;
  2684.         }
  2685.         if ((st.st_mode & S_IFMT) == S_IFREG) {
  2686.             if (dout == NULL) {
  2687.                 dout = dataconn("file list", (off_t) - 1, "w");
  2688.                 if (dout == NULL)
  2689.                     return;
  2690.                 transflag++;
  2691.             }
  2692.             fprintf(dout, "%s%s\n", dirname,
  2693.                     type == TYPE_A ? "\r" : "");
  2694.             byte_count += strlen(dirname) + 1;
  2695.             continue;
  2696.         } else if ((st.st_mode & S_IFMT) != S_IFDIR)
  2697.             continue;
  2698.  
  2699.         if ((dirp = opendir(dirname)) == NULL)
  2700.             continue;
  2701.  
  2702.         while ((dir = readdir(dirp)) != NULL) {
  2703.             char nbuf[MAXPATHLEN];
  2704.  
  2705. #ifndef HAVE_DIRENT    /* does not have d_namlen */
  2706.             if (dir->d_name[0] == '.' && dir->d_namlen == 1)
  2707. #else
  2708.             if (dir->d_name[0] == '.' && (strlen(dir->d_name) == 1))
  2709. #endif
  2710.                 continue;
  2711. #ifndef HAVE_DIRENT    /* does not have d_namlen */
  2712.             if (dir->d_namlen == 2 && dir->d_name[0] == '.' &&
  2713.                 dir->d_name[1] == '.')
  2714. #else
  2715.             if ((strlen(dir->d_name) == 2) && dir->d_name[0] == '.' &&
  2716.                 dir->d_name[1] == '.')
  2717. #endif
  2718.                 continue;
  2719.  
  2720.             sprintf(nbuf, "%s/%s", dirname, dir->d_name);
  2721.  
  2722.             /* We have to do a stat to insure it's not a directory or special
  2723.              * file. */
  2724.             if (simple || (stat(nbuf, &st) == 0 &&
  2725.                            (st.st_mode & S_IFMT) == S_IFREG)) {
  2726.                 if (dout == NULL) {
  2727.                     dout = dataconn("file list", (off_t) - 1,
  2728.                                     "w");
  2729.                     if (dout == NULL)
  2730.                         return;
  2731.                     transflag++;
  2732.                 }
  2733.                 if (nbuf[0] == '.' && nbuf[1] == '/')
  2734.                     fprintf(dout, "%s%s\n", &nbuf[2],
  2735.                             type == TYPE_A ? "\r" : "");
  2736.                 else
  2737.                     fprintf(dout, "%s%s\n", nbuf,
  2738.                             type == TYPE_A ? "\r" : "");
  2739.                 byte_count += strlen(nbuf) + 1;
  2740.             }
  2741.         }
  2742.         (void) closedir(dirp);
  2743.     }
  2744.  
  2745.     if (dout == NULL)
  2746.         reply(550, "No files found.");
  2747.     else if (ferror(dout) != 0)
  2748.         perror_reply(550, "Data connection");
  2749.     else
  2750.         reply(226, "Transfer complete.");
  2751.  
  2752.     transflag = 0;
  2753.     if (dout != NULL)
  2754.         (void) fclose(dout);
  2755.     data = -1;
  2756.     pdata = -1;
  2757. }
  2758.  
  2759. #ifdef SETPROCTITLE
  2760. # ifndef setproctitle /* because of SCO, we use SCOproctitle instead */
  2761. /* clobber argv so ps will show what we're doing. (stolen from sendmail)
  2762.  * warning, since this is usually started from inetd.conf, it often doesn't
  2763.  * have much of an environment or arglist to overwrite. */
  2764.  
  2765. #ifdef HAVE_PSTAT
  2766. #include <sys/pstat.h>
  2767. #endif
  2768.  
  2769. /* VARARGS2 */
  2770. setproctitle(va_alist)
  2771.   va_dcl
  2772. {
  2773.     va_list ap;
  2774.     char *fmt;
  2775.  
  2776.     register char *p,
  2777.      *bp,
  2778.       ch;
  2779.     register int i;
  2780.     char buf[BUFSIZ];
  2781. #ifdef HAVE_PSTAT
  2782.     union pstun un;
  2783. #endif
  2784.  
  2785.     va_start(ap);
  2786.     /* first argument is always the fmt string */
  2787.     fmt = va_arg(ap, char *);
  2788.  
  2789.     (void) vsprintf(buf, fmt, ap);
  2790.     va_end(ap);
  2791.  
  2792.     /* make ps print our process name */
  2793.     p = Argv[0];
  2794.     *p++ = '-';
  2795.  
  2796.     i = strlen(buf);
  2797. #ifdef HAVE_PSTAT
  2798.     un.pst_command = buf;
  2799.     pstat(PSTAT_SETCMD, un, i, 0, 0);
  2800. #else
  2801.     if (i > LastArgv - p - 2) {
  2802.         i = LastArgv - p - 2;
  2803.         buf[i] = '\0';
  2804.     }
  2805.     bp = buf;
  2806.     while ((ch = *bp++) != (char) NULL)
  2807.         if (ch != '\n' && ch != '\r')
  2808.             *p++ = ch;
  2809.     while (p < LastArgv)
  2810.         *p++ = ' ';
  2811. #endif
  2812. }
  2813. #endif /* setproctitle */
  2814. #endif /* SETPROCTITLE */
  2815.  
  2816. #ifdef KERBEROS
  2817. /* thanks to gshapiro@wpi.wpi.edu for the following kerberosities */
  2818.  
  2819. void
  2820. init_krb()
  2821. {
  2822.     char hostname[100];
  2823.  
  2824. #ifdef HAVE_SYSINFO
  2825.     if (sysinfo(SI_HOSTNAME, hostname, sizeof (hostname)) < 0) {
  2826.         perror("sysinfo");
  2827. #else
  2828.     if (gethostname(hostname, sizeof(hostname)) < 0) {
  2829.         perror("gethostname");
  2830. #endif
  2831.         exit(1);
  2832.     }
  2833.     if (strchr(hostname, '.'))
  2834.         *(strchr(hostname, '.')) = 0;
  2835.  
  2836.     sprintf(krb_ticket_name, "/var/dss/kerberos/tkt/tkt.%d", getpid());
  2837.     krb_set_tkt_string(krb_ticket_name);
  2838.  
  2839.     config_auth();
  2840.  
  2841.     if (krb_svc_init("hesiod", hostname, (char *) NULL, 0, (char *) NULL,
  2842.                      (char *) NULL) != KSUCCESS) {
  2843.         fprintf(stderr, "Couldn't initialize Kerberos\n");
  2844.         exit(1);
  2845.     }
  2846. }
  2847.  
  2848. void
  2849. end_krb()
  2850. {
  2851.     unlink(krb_ticket_name);
  2852. }
  2853. #endif /* KERBEROS */
  2854.  
  2855. #ifdef ULTRIX_AUTH
  2856. static int
  2857. ultrix_check_pass(char *passwd, char *xpasswd)
  2858. {
  2859.     struct svcinfo *svp;
  2860.     int auth_status;
  2861.  
  2862.     if ((svp = getsvc()) == (struct svcinfo *) NULL) {
  2863.         syslog(LOG_WARNING, "getsvc() failed in ultrix_check_pass");
  2864.         return -1;
  2865.     }
  2866.     if (pw == (struct passwd *) NULL) {
  2867.         return -1;
  2868.     }
  2869.     if (((svp->svcauth.seclevel == SEC_UPGRADE) &&
  2870.         (!strcmp(pw->pw_passwd, "*")))
  2871.         || (svp->svcauth.seclevel == SEC_ENHANCED)) {
  2872.         if ((auth_status=authenticate_user(pw, passwd, "/dev/ttypXX")) >= 0) {
  2873.             /* Indicate successful validation */
  2874.             return auth_status;
  2875.         }
  2876.         if (auth_status < 0 && errno == EPERM) {
  2877.             /* Log some information about the failed login attempt. */
  2878.             switch(abs(auth_status)) {
  2879.             case A_EBADPASS:
  2880.                 break;
  2881.             case A_ESOFTEXP:
  2882.                 syslog(LOG_NOTICE, "password will expire soon for user %s",
  2883.                     pw->pw_name);
  2884.                 break;
  2885.             case A_EHARDEXP:
  2886.                 syslog(LOG_NOTICE, "password has expired for user %s",
  2887.                     pw->pw_name);
  2888.                 break;
  2889.             case A_ENOLOGIN:
  2890.                 syslog(LOG_NOTICE, "user %s attempted login to disabled acct",
  2891.                     pw->pw_name);
  2892.                 break;
  2893.             }
  2894.         }
  2895.     }
  2896.     else {
  2897.         if ((*pw->pw_passwd != '\0') && (!strcmp(xpasswd, pw->pw_passwd))) {
  2898.             /* passwd in /etc/passwd isn't empty && encrypted passwd matches */
  2899.             return 0;
  2900.         }
  2901.     }
  2902.     return -1;
  2903. }
  2904. #endif /* ULTRIX_AUTH */
  2905.