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