source: trunk/athena/etc/ftpd/ftpd.c @ 8020

Revision 8020, 25.2 KB checked in by cfields, 29 years ago (diff)
Shadow password stuff was half ifdefed SOLARIS, half SYSV. Made it all SYSV.
RevLine 
[2890]1/*
2 * Copyright (c) 1985 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley.  The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#ifndef lint
19char copyright[] =
20"@(#) Copyright (c) 1985 Regents of the University of California.\n\
21 All rights reserved.\n";
22#endif /* not lint */
23
24#ifndef lint
25static char sccsid[] = "@(#)ftpd.c      5.19 (Berkeley) 11/30/88 + portability hacks by rick@seismo.css.gov";
26#endif /* not lint */
27
28/*
29 * FTP server.
30 */
31#include <sys/param.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/socket.h>
35#include <sys/file.h>
36#include <sys/wait.h>
37
38#include <netinet/in.h>
39
40#include <arpa/ftp.h>
41#include <arpa/inet.h>
42#include <arpa/telnet.h>
43
44#include <stdio.h>
45#include <signal.h>
46#include <pwd.h>
[8020]47#ifdef SYSV
[7260]48#include <shadow.h>
49#endif
[2890]50#include <setjmp.h>
51#include <netdb.h>
52#include <errno.h>
[7260]53#ifdef POSIX
54#include <string.h>
55#include <termios.h>
56#else
[2890]57#include <strings.h>
[7260]58#endif
[7289]59#ifdef ultrix
60#include <nsyslog.h>
61#else
[2890]62#include <syslog.h>
[7289]63#endif
[6084]64#ifdef ATHENA
65#include "athena_ftpd.h"
66#include "krb.h"
67#endif
[2890]68
69#ifndef MAXHOSTNAMELEN
70#define MAXHOSTNAMELEN  64
71#endif /* !MAXHOSTNAMELEN */
72
[3533]73#ifndef BUG_ADDRESS
74#define BUG_ADDRESS "ftp-bugs@ATHENA.MIT.EDU"
75#endif
76 
[2890]77/*
78 * File containing login names
79 * NOT to be used on this machine.
80 * Commonly used to disallow uucp.
81 */
82#define FTPUSERS        "/etc/ftpusers"
83
84extern  int errno;
85extern  char *sys_errlist[];
86extern  char *crypt();
87extern  char version[];
88extern  char *home;             /* pointer to home directory for glob */
89extern  FILE *ftpd_popen(), *fopen(), *freopen();
90extern  int  pclose(), fclose();
[7260]91#ifndef SOLARIS
[6084]92extern  char *getline(), *getwd();
[7260]93#else
94extern  char *getline(), *getcwd();
95#endif
[2890]96extern  char cbuf[];
97
98struct  sockaddr_in ctrl_addr;
99struct  sockaddr_in data_source;
100struct  sockaddr_in data_dest;
101struct  sockaddr_in his_addr;
102
103int     data;
104jmp_buf errcatch, urgcatch;
105int     logged_in;
106struct  passwd *pw;
[6084]107#ifdef ATHENA
108int     athena;
109#endif
[2890]110int     debug;
111int     timeout = 900;    /* timeout after 15 minutes of inactivity */
112int     logging;
113int     guest;
114int     type;
115int     form;
116int     stru;                   /* avoid C keyword */
117int     mode;
118int     usedefault = 1;         /* for data transfers */
119int     pdata;                  /* for passive mode */
120int     unique;
121int     transflag;
122char    tmpline[7];
123char    hostname[MAXHOSTNAMELEN];
124char    remotehost[MAXHOSTNAMELEN];
[3533]125char    *bug_address = NULL;
[2890]126
127/*
128 * Timeout intervals for retrying connections
129 * to hosts that don't accept PORT cmds.  This
130 * is a kludge, but given the problems with TCP...
131 */
132#define SWAITMAX        90      /* wait at most 90 seconds */
133#define SWAITINT        5       /* interval between retries */
134
135int     swaitmax = SWAITMAX;
136int     swaitint = SWAITINT;
137
138int     lostconn();
[6084]139#ifdef ATHENA
140int     dologout();
141#endif
[2890]142int     myoob();
143FILE    *getdatasock(), *dataconn();
144
145main(argc, argv)
146        int argc;
147        char *argv[];
148{
149        int addrlen, on = 1;
150        long pgid;
[3533]151        int cp;
152        struct hostent *hostentry;
153        extern char *optarg;
154        extern int optind;
[7260]155#ifdef POSIX
156        struct sigaction act;
157        sigemptyset(&act.sa_mask);
158        act.sa_flags = 0;
159#endif
[3533]160       
[2890]161        addrlen = sizeof (his_addr);
162        if (getpeername(0, &his_addr, &addrlen) < 0) {
163                syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
164                exit(1);
165        }
166        addrlen = sizeof (ctrl_addr);
167        if (getsockname(0, (char *) &ctrl_addr, &addrlen) < 0) {
168                syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
169                exit(1);
170        }
171        data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
172        debug = 0;
[6084]173#ifdef ATHENA
174        athena = 0;
175#endif
[2890]176#ifdef LOG_LOCAL3
177        openlog("ftpd", LOG_PID, LOG_LOCAL3);
178#else
179        openlog("ftpd", LOG_PID);
180#endif
[6084]181#ifdef ATHENA
182        while ((cp = getopt(argc, argv, "avdlt:b:")) != EOF) switch (cp) {
183        case 'a':
184                athena = 1;
185                break;
186#else
[3533]187        while ((cp = getopt(argc, argv, "vdlt:b:")) != EOF) switch (cp) {
[6084]188#endif
[3533]189        case 'v':
190                debug = 1;
191                break;
[2890]192
[3533]193        case 'd':
194                debug = 1;
195                break;
[2890]196
[3533]197        case 'l':
198                logging = 1;
199                break;
200               
201        case 't':
202                timeout = atoi(optarg);
203                break;
204               
205        case 'b':
206                bug_address = optarg;
207                break;
208               
209        default:
210                fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
211                        cp);
212                break;
[2890]213        }
[3533]214#ifdef BUG_ADDRESS
215        if (! bug_address)
216                bug_address = BUG_ADDRESS;
217#endif
[2890]218        (void) freopen("/dev/null", "w", stderr);
[7260]219#ifdef POSIX
220        act.sa_handler= (void (*)()) lostconn;
221        (void) sigaction (SIGPIPE, &act, NULL);
222#else
223        (void) signal(SIGPIPE, lostconn);       
224#endif
[6084]225#ifdef ATHENA
226        if (athena)
227          {
[7260]228#ifdef POSIX
229            act.sa_handler= (void (*)()) dologout;
230            (void) sigaction (SIGHUP, &act, NULL);
231            (void) sigaction (SIGTERM, &act, NULL);
232#else
[6084]233            (void) signal(SIGHUP, dologout);
234            (void) signal(SIGTERM, dologout);
[7260]235#endif
[6084]236          }
237#endif
[7260]238#ifdef POSIX
239        act.sa_handler= (void (*)()) SIG_IGN;
240        (void) sigaction (SIGCHLD, &act, NULL);
241        act.sa_handler= (void (*)()) myoob;
242        if( sigaction (SIGURG, &act, NULL) < 0)
243                syslog(LOG_ERR, "signal: %m");
244
245#else
[2890]246        (void) signal(SIGCHLD, SIG_IGN);
247        if ((int)signal(SIGURG, myoob) < 0)
248                syslog(LOG_ERR, "signal: %m");
[7260]249#endif
[2890]250
[7260]251
[2890]252        /* handle urgent data inline */
253        /* Sequent defines this, but it doesn't work */
254#ifdef SO_OOBINLINE
255        if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
256                syslog(LOG_ERR, "setsockopt: %m");
257#endif
258        pgid = getpid();
[7260]259#ifndef SOLARIS
[2890]260        if (ioctl(fileno(stdin), SIOCSPGRP, (char *) &pgid) < 0) {
261                syslog(LOG_ERR, "ioctl: %m");
262        }
[7260]263#endif
264
[2890]265        dolog(&his_addr);
266        /* do telnet option negotiation here */
267        /*
268         * Set up default state
269         */
270        data = -1;
271        type = TYPE_A;
272        form = FORM_N;
273        stru = STRU_F;
274        mode = MODE_S;
275        tmpline[0] = '\0';
276        (void) gethostname(hostname, sizeof (hostname));
[3533]277        hostentry = gethostbyname(hostname);
278        if (hostentry) {
279                strncpy(hostname, hostentry->h_name, sizeof(hostname));
280                hostname[sizeof(hostname) - 1] = '\0';
281        }
[2890]282        reply(220, "%s FTP server (%s) ready.", hostname, version);
283        for (;;) {
284                (void) setjmp(errcatch);
285                (void) yyparse();
286        }
287}
288
289lostconn()
290{
291
292        if (debug)
293                syslog(LOG_DEBUG, "lost connection");
294        dologout(-1);
295}
296
297static char ttyline[20];
298
299/*
300 * Helper function for sgetpwnam().
301 */
302char *
303sgetsave(s)
304        char *s;
305{
306#ifdef notdef
307        char *new = strdup(s);
308#else
309        char *malloc();
310        char *new = malloc((unsigned) strlen(s) + 1);
311#endif
312       
313        if (new == NULL) {
314                reply(553, "Local resource failure: malloc");
315                dologout(1);
316        }
317#ifndef notdef
318        (void) strcpy(new, s);
319#endif
320        return (new);
321}
322
[7260]323#ifdef SYSV
324struct passwd *
325get_pwnam(usr)
326char *usr;
327{
328  struct passwd *pwd;
329  struct spwd *sp;
330  pwd = getpwnam (usr);
331  sp = getspnam(usr);
332  if ((sp != NULL) && (pwd != NULL))
333    pwd->pw_passwd = sp->sp_pwdp;
334   return(pwd);
335}
336#else
337#define get_pwnam(x) getpwnam(x)
338#endif
339
[2890]340/*
341 * Save the result of a getpwnam.  Used for USER command, since
342 * the data returned must not be clobbered by any other command
343 * (e.g., globbing).
344 */
345struct passwd *
346sgetpwnam(name)
347        char *name;
348{
349        static struct passwd save;
350        register struct passwd *p;
351        char *sgetsave();
352
[6084]353#ifdef ATHENA
354        if ((p = (athena ? athena_getpwnam(name)
[7260]355                         : get_pwnam(name))) == NULL)
[6084]356#else
[7260]357        if ((p = get_pwnam(name)) == NULL)
358#endif
[2890]359                return (p);
360        if (save.pw_name) {
361                free(save.pw_name);
362                free(save.pw_passwd);
[7260]363#if !defined(_IBMR2)  && !defined(SOLARIS)
[2890]364                free(save.pw_comment);
[6084]365#endif
[2890]366                free(save.pw_gecos);
367                free(save.pw_dir);
368                free(save.pw_shell);
369        }
370        save = *p;
371        save.pw_name = sgetsave(p->pw_name);
372        save.pw_passwd = sgetsave(p->pw_passwd);
[7260]373#if !defined(_IBMR2) && !defined(SOLARIS)
374        save.pw_comment = sgetsave(p->pw_comment);
[6084]375#endif
[2890]376        save.pw_gecos = sgetsave(p->pw_gecos);
377        save.pw_dir = sgetsave(p->pw_dir);
378        save.pw_shell = sgetsave(p->pw_shell);
379        return (&save);
380}
381
382pass(passwd)
383        char *passwd;
384{
385        char *xpasswd;
[6084]386#ifdef ATHENA
387        char *athena_auth_errtext, *athena_attach_errtext;
388#endif
[2890]389
390        if (logged_in || pw == NULL) {
391                reply(503, "Login with USER first.");
392                return;
393        }
394        if (!guest) {           /* "ftp" is only account allowed no password */
[6084]395#ifdef ATHENA
396          if (athena)
397            {
398              athena_auth_errtext = athena_authenticate(pw->pw_name, passwd);
399              switch(athena_login)
400                {
401                case LOGIN_KERBEROS:
402                  break;
403                case LOGIN_LOCAL:
404                  break;
405                case LOGIN_NONE:
406                  reply(530, athena_auth_errtext);
407                  pw = NULL;
408                  return;
409                  break;
410                }
411            }
412          else
413            {
414#endif
[2890]415                xpasswd = crypt(passwd, pw->pw_passwd);
416                /* The strcmp does not catch null passwords! */
417                if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
418                        reply(530, "Login incorrect.");
[6084]419                        pw = NULL; /* pw = NULL's are small memory leaks XXX */
[2890]420                        return;
421                }
[6084]422#ifdef ATHENA
423            }
424#endif
[2890]425        }
[6084]426#if defined(_IBMR2)
427        setegid_rios(pw->pw_gid);
428#else
[2890]429        setegid(pw->pw_gid);
[6084]430#endif
[2890]431        initgroups(pw->pw_name, pw->pw_gid);
[6084]432
433#ifdef ATHENA
434        if (athena)
435          athena_attach_errtext = athena_attachhomedir(pw,
436                                  (athena_login == LOGIN_KERBEROS) ? 1 : 0);
437#endif
438
439/*
440 * Bleah. If chdir is done as root, nonlocal fascists lose.
441 * This is fine, except for the fact that nonlocal fascists
442 * tend to run things. :-)
443 */
444#if defined(_IBMR2)
445        seteuid_rios(pw->pw_uid);
446#else
447        seteuid(pw->pw_uid);
448#endif
[2890]449        if (chdir(pw->pw_dir)) {
[6084]450#ifdef ATHENA
451                if (athena && athena_attach_errtext)
452                  lreply(530, athena_attach_errtext);
453#endif
[2890]454                reply(530, "User %s: can't change directory to %s.",
455                        pw->pw_name, pw->pw_dir);
456                goto bad;
457        }
[6084]458#if defined(_IBMR2)
459        seteuid_rios(0);
460#else
461        seteuid(0);
462#endif
[2890]463
464        /* open wtmp before chroot */
465        (void)sprintf(ttyline, "ftp%d", getpid());
[6084]466#ifdef ATHENA
467        if (athena)
468          loguwtmp(ttyline, pw->pw_name, remotehost);
469        else
470#endif
[2890]471        logwtmp(ttyline, pw->pw_name, remotehost);
[6084]472
[2890]473        logged_in = 1;
474
475        if (guest) {
476                if (chroot(pw->pw_dir) < 0) {
477                        reply(550, "Can't set guest privileges.");
478                        goto bad;
479                }
480                reply(230, "Guest login ok, access restrictions apply.");
481        } else
[6084]482#ifdef ATHENA
483          if (athena)
484            {
485              switch(athena_login)
486                {
487                case LOGIN_LOCAL:
488                  lreply(230, "User %s logged in without authentication:",
489                         pw->pw_name);
490                  if (athena_attach_errtext)
491                    lreply(230, athena_attach_errtext);
492                  reply(230, athena_auth_errtext);
493                  break;
494                case LOGIN_KERBEROS:
495                  if (athena_auth_errtext)
496                    lreply(230, athena_auth_errtext);
497                  if (athena_attach_errtext)
498                    lreply(230, athena_attach_errtext);
499                  reply(230, "User %s%s logged in with Kerberos tickets.", pw->pw_name,
500                        (athena_auth_errtext ? " mostly" : ""));
501                  break;
502                default:
503                  reply(530, "User %s shouldn't be at this point in the code.",
504                        pw->pw_name);
505                  pw = NULL;
506                  return;
507                  break;
508                }
509            }
510          else
511#endif
[7260]512          reply(230, "User %s logged in.", pw->pw_name);
[6084]513#if defined(_IBMR2)
514        seteuid_rios(pw->pw_uid);
515#else
[7260]516#ifdef SOLARIS
517        setuid(pw->pw_uid);
518#else
[2890]519        seteuid(pw->pw_uid);
[6084]520#endif
[7260]521#endif
[2890]522        home = pw->pw_dir;              /* home dir for globbing */
523        return;
524bad:
[6084]525#if defined(_IBMR2)
526        seteuid_rios(0);
527#else
[2890]528        seteuid(0);
[6084]529#endif
530#ifdef ATHENA
531        if (athena)
532          athena_logout(pw);
533#endif
[2890]534        pw = NULL;
535}
536
537retrieve(cmd, name)
538        char *cmd, *name;
539{
540        FILE *fin, *dout;
541        struct stat st;
542        int (*closefunc)(), tmp;
543
544        if (cmd == 0) {
545#ifdef notdef
546                /* no remote command execution -- it's a security hole */
547                if (*name == '|')
548                        fin = ftpd_popen(name + 1, "r"), closefunc = pclose;
549                else
550#endif
551                        fin = fopen(name, "r"), closefunc = fclose;
552        } else {
553                char line[BUFSIZ];
554
555                (void) sprintf(line, cmd, name), name = line;
556                fin = ftpd_popen(line, "r"), closefunc = pclose;
557        }
558        if (fin == NULL) {
559                if (errno != 0)
560                        reply(550, "%s: %s.", name, sys_errlist[errno]);
561                return;
562        }
563        st.st_size = 0;
564        if (cmd == 0 &&
565            (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
566                reply(550, "%s: not a plain file.", name);
567                goto done;
568        }
569        dout = dataconn(name, st.st_size, "w");
570        if (dout == NULL)
571                goto done;
572        if ((tmp = send_data(fin, dout)) > 0 || ferror(dout) > 0) {
573                reply(550, "%s: %s.", name, sys_errlist[errno]);
574        }
575        else if (tmp == 0) {
576                reply(226, "Transfer complete.");
577        }
578        (void) fclose(dout);
579        data = -1;
580        pdata = -1;
581done:
582        (*closefunc)(fin);
583}
584
585store(name, mode)
586        char *name, *mode;
587{
588        FILE *fout, *din;
589        int (*closefunc)(), dochown = 0, tmp;
590        char *gunique(), *local;
591
592#ifdef notdef
593        /* no remote command execution -- it's a security hole */
594        if (name[0] == '|')
595                fout = ftpd_popen(&name[1], "w"), closefunc = pclose;
596        else
597#endif
598        {
599                struct stat st;
600
601                local = name;
602                if (stat(name, &st) < 0) {
603                        dochown++;
604                }
605                else if (unique) {
606                        if ((local = gunique(name)) == NULL) {
607                                return;
608                        }
609                        dochown++;
610                }
611                fout = fopen(local, mode), closefunc = fclose;
612        }
613        if (fout == NULL) {
614                reply(553, "%s: %s.", local, sys_errlist[errno]);
615                return;
616        }
617        din = dataconn(local, (off_t)-1, "r");
618        if (din == NULL)
619                goto done;
620        if ((tmp = receive_data(din, fout)) > 0 || ferror(fout) > 0) {
621                reply(552, "%s: %s.", local, sys_errlist[errno]);
622        }
623        else if (tmp == 0 && !unique) {
624                reply(226, "Transfer complete.");
625        }
626        else if (tmp == 0 && unique) {
627                reply(226, "Transfer complete (unique file name:%s).", local);
628        }
629        (void) fclose(din);
630        data = -1;
631        pdata = -1;
632done:
633        if (dochown)
634                (void) fchown(fileno(fout), pw->pw_uid, -1);
635        (*closefunc)(fout);
636}
637
638FILE *
639getdatasock(mode)
640        char *mode;
641{
642        int s, on = 1;
643
644        if (data >= 0)
645                return (fdopen(data, mode));
646        s = socket(AF_INET, SOCK_STREAM, 0);
647        if (s < 0)
648                return (NULL);
[6084]649#if defined(ATHENA) && defined(_IBMR2)
650        seteuid_rios(0);
651#else
[7260]652#ifdef SOLARIS
653        setuid(0);
654#else
[2890]655        seteuid(0);
[6084]656#endif
[7260]657#endif
[2890]658        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0)
659                goto bad;
660        /* anchor socket to avoid multi-homing problems */
661        data_source.sin_family = AF_INET;
662        data_source.sin_addr = ctrl_addr.sin_addr;
[7260]663#ifdef SOLARIS
664/* let the system pick a good address */
665        data_source.sin_port = 0;
666#endif
667        if (bind(s, &data_source, sizeof (data_source)) < 0)
[2890]668                goto bad;
[6084]669#if defined(ATHENA) && defined(_IBMR2)
670        seteuid_rios(pw->pw_uid);
671#else
[7260]672#ifdef SOLARIS
673        setuid(pw->pw_uid);
674#else
675       seteuid(pw->pw_uid);
[6084]676#endif
[7260]677#endif
[2890]678        return (fdopen(s, mode));
679bad:
[7260]680
[6084]681#if defined(ATHENA) && defined(_IBMR2)
682        seteuid_rios(pw->pw_uid);
683#else
[7260]684#ifdef SOLARIS
685        setuid(pw->pw_uid);
686#else
687        seteuid(pw->pw_uid);
[6084]688#endif
[7260]689#endif
[2890]690        (void) close(s);
691        return (NULL);
692}
693
694FILE *
695dataconn(name, size, mode)
696        char *name;
697        off_t size;
698        char *mode;
699{
700        char sizebuf[32];
701        FILE *file;
702        int retry = 0;
703
704        if (size >= 0)
705                (void) sprintf (sizebuf, " (%ld bytes)", size);
706        else
707                (void) strcpy(sizebuf, "");
708        if (pdata > 0) {
709                struct sockaddr_in from;
710                int s, fromlen = sizeof(from);
711
712                s = accept(pdata, &from, &fromlen);
713                if (s < 0) {
714                        reply(425, "Can't open data connection.");
715                        (void) close(pdata);
716                        pdata = -1;
717                        return(NULL);
718                }
719                (void) close(pdata);
720                pdata = s;
721                reply(150, "Opening %s mode data connection for %s%s.",
722                     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
723                return(fdopen(pdata, mode));
724        }
725        if (data >= 0) {
726                reply(125, "Using existing data connection for %s%s.",
727                    name, sizebuf);
728                usedefault = 1;
729                return (fdopen(data, mode));
730        }
731        if (usedefault)
732                data_dest = his_addr;
733        usedefault = 1;
734        file = getdatasock(mode);
735        if (file == NULL) {
[7260]736                reply(425, "Can't create data socket (%s,%d): %s. ",
[2890]737                    inet_ntoa(data_source.sin_addr),
738                    ntohs(data_source.sin_port),
[7260]739                    sys_errlist[errno]) ;
[2890]740                return (NULL);
741        }
742        data = fileno(file);
743        while (connect(data, &data_dest, sizeof (data_dest)) < 0) {
744                if (errno == EADDRINUSE && retry < swaitmax) {
745                        sleep((unsigned) swaitint);
746                        retry += swaitint;
747                        continue;
748                }
749                reply(425, "Can't build data connection: %s.",
750                    sys_errlist[errno]);
751                (void) fclose(file);
752                data = -1;
753                return (NULL);
754        }
755        reply(150, "Opening %s mode data connection for %s%s.",
756             type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
757        return (file);
758}
759
760/*
761 * Tranfer the contents of "instr" to
762 * "outstr" peer using the appropriate
763 * encapulation of the date subject
764 * to Mode, Structure, and Type.
765 *
766 * NB: Form isn't handled.
767 */
768send_data(instr, outstr)
769        FILE *instr, *outstr;
770{
771        register int c;
772        int netfd, filefd, cnt;
773        char buf[BUFSIZ];
774
775        transflag++;
776        if (setjmp(urgcatch)) {
777                transflag = 0;
778                return(-1);
779        }
780        switch (type) {
781
782        case TYPE_A:
783                while ((c = getc(instr)) != EOF) {
784                        if (c == '\n') {
785                                if (ferror (outstr)) {
786                                        transflag = 0;
787                                        return (1);
788                                }
789                                (void) putc('\r', outstr);
790                        }
791                        (void) putc(c, outstr);
792                /*      if (c == '\r')                  */
793                /*              putc ('\0', outstr);    */
794                }
795                transflag = 0;
796                if (ferror (instr) || ferror (outstr)) {
797                        return (1);
798                }
799                return (0);
800               
801        case TYPE_I:
802        case TYPE_L:
803                netfd = fileno(outstr);
804                filefd = fileno(instr);
805
806                while ((cnt = read(filefd, buf, sizeof (buf))) > 0) {
807                        if (write(netfd, buf, cnt) < 0) {
808                                transflag = 0;
809                                return (1);
810                        }
811                }
812                transflag = 0;
813                return (cnt < 0);
814        }
815        reply(550, "Unimplemented TYPE %d in send_data", type);
816        transflag = 0;
817        return (-1);
818}
819
820/*
821 * Transfer data from peer to
822 * "outstr" using the appropriate
823 * encapulation of the data subject
824 * to Mode, Structure, and Type.
825 *
826 * N.B.: Form isn't handled.
827 */
828receive_data(instr, outstr)
829        FILE *instr, *outstr;
830{
831        register int c;
832        int cnt;
833        char buf[BUFSIZ];
834
835
836        transflag++;
837        if (setjmp(urgcatch)) {
838                transflag = 0;
839                return(-1);
840        }
841        switch (type) {
842
843        case TYPE_I:
844        case TYPE_L:
845                while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
846                        if (write(fileno(outstr), buf, cnt) < 0) {
847                                transflag = 0;
848                                return (1);
849                        }
850                }
851                transflag = 0;
852                return (cnt < 0);
853
854        case TYPE_E:
855                reply(553, "TYPE E not implemented.");
856                transflag = 0;
857                return (-1);
858
859        case TYPE_A:
860                while ((c = getc(instr)) != EOF) {
861                        while (c == '\r') {
862                                if (ferror (outstr)) {
863                                        transflag = 0;
864                                        return (1);
865                                }
866                                if ((c = getc(instr)) != '\n')
867                                        (void) putc ('\r', outstr);
868                        /*      if (c == '\0')                  */
869                        /*              continue;               */
870                        }
871                        (void) putc (c, outstr);
872                }
873                transflag = 0;
874                if (ferror (instr) || ferror (outstr))
875                        return (1);
876                return (0);
877        }
878        transflag = 0;
879        fatal("Unknown type in receive_data.");
880        /*NOTREACHED*/
881}
882
883fatal(s)
884        char *s;
885{
886        reply(451, "Error in server: %s\n", s);
887        reply(221, "Closing connection due to server error.");
888        dologout(0);
889}
890
[2893]891reply(n, s, p0, p1, p2, p3, p4, p5)
[2890]892        int n;
[6084]893        char *s, *p0, *p1, *p2, *p3, *p4, *p5;
894     /* declaring p0-5 as char * reduces number of errors from hc2 */
[2890]895{
896
897        printf("%d ", n);
[2893]898        printf(s, p0, p1, p2, p3, p4, p5);
[2890]899        printf("\r\n");
900        (void) fflush(stdout);
901        if (debug) {
902                syslog(LOG_DEBUG, "<--- %d ", n);
[2893]903                syslog(LOG_DEBUG, s, p0, p1, p2, p3, p4, p5);
[2890]904        }
905}
906
907lreply(n, s, p0, p1, p2, p3, p4)
908        int n;
[6084]909        char *s, *p0, *p1, *p2, *p3, *p4;
[2890]910{
911        printf("%d-", n);
912        printf(s, p0, p1, p2, p3, p4);
913        printf("\r\n");
914        (void) fflush(stdout);
915        if (debug) {
916                syslog(LOG_DEBUG, "<--- %d- ", n);
917                syslog(LOG_DEBUG, s, p0, p1, p2, p3, p4);
918        }
919}
920
921ack(s)
922        char *s;
923{
924        reply(250, "%s command successful.", s);
925}
926
927nack(s)
928        char *s;
929{
930        reply(502, "%s command not implemented.", s);
931}
932
933yyerror(s)
934        char *s;
935{
936        char *cp;
937
[7260]938        cp = strchr(cbuf,'\n');
[2890]939        *cp = '\0';
940        reply(500, "'%s': command not understood.",cbuf);
941}
942
943delete(name)
944        char *name;
945{
946        struct stat st;
947
948        if (stat(name, &st) < 0) {
949                reply(550, "%s: %s.", name, sys_errlist[errno]);
950                return;
951        }
952        if ((st.st_mode&S_IFMT) == S_IFDIR) {
953                if (rmdir(name) < 0) {
954                        reply(550, "%s: %s.", name, sys_errlist[errno]);
955                        return;
956                }
957                goto done;
958        }
959        if (unlink(name) < 0) {
960                reply(550, "%s: %s.", name, sys_errlist[errno]);
961                return;
962        }
963done:
964        ack("DELE");
965}
966
967cwd(path)
968        char *path;
969{
970
971        if (chdir(path) < 0) {
972                reply(550, "%s: %s.", path, sys_errlist[errno]);
973                return;
974        }
975        ack("CWD");
976}
977
978makedir(name)
979        char *name;
980{
981        unsigned short oldeuid;
982
983        oldeuid = geteuid();
[6084]984#if defined(ATHENA) && defined(_IBMR2)
985        seteuid_rios(pw->pw_uid);
986#else
[2890]987        seteuid(pw->pw_uid);
[6084]988#endif
[2890]989        if (mkdir(name, 0777) < 0)
990                reply(550, "%s: %s.", name, sys_errlist[errno]);
991        else
992                reply(257, "MKD command successful.");
[6084]993#if defined(ATHENA) && defined(_IBMR2)
994        seteuid_rios(oldeuid);
995#else
[2890]996        seteuid(oldeuid);
[6084]997#endif
[2890]998}
999
1000removedir(name)
1001        char *name;
1002{
1003
1004        if (rmdir(name) < 0) {
1005                reply(550, "%s: %s.", name, sys_errlist[errno]);
1006                return;
1007        }
1008        ack("RMD");
1009}
1010
1011pwd()
1012{
1013        char path[MAXPATHLEN + 1];
1014
[7260]1015#ifndef SOLARIS
[2890]1016        if (getwd(path) == NULL) {
[7260]1017#else
1018        if( getcwd(path, MAXPATHLEN + 1) == NULL) {
1019#endif
[2890]1020                reply(550, "%s.", path);
1021                return;
1022        }
1023        reply(257, "\"%s\" is current directory.", path);
1024}
1025
1026char *
1027renamefrom(name)
1028        char *name;
1029{
1030        struct stat st;
1031
1032        if (stat(name, &st) < 0) {
1033                reply(550, "%s: %s.", name, sys_errlist[errno]);
1034                return ((char *)0);
1035        }
1036        reply(350, "File exists, ready for destination name");
1037        return (name);
1038}
1039
1040renamecmd(from, to)
1041        char *from, *to;
1042{
1043
1044        if (rename(from, to) < 0) {
1045                reply(550, "rename: %s.", sys_errlist[errno]);
1046                return;
1047        }
1048        ack("RNTO");
1049}
1050
1051dolog(sin)
1052        struct sockaddr_in *sin;
1053{
1054        struct hostent *hp = gethostbyaddr(&sin->sin_addr,
1055                sizeof (struct in_addr), AF_INET);
1056        time_t t;
1057        extern char *ctime();
1058
1059        if (hp) {
1060                (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
1061                endhostent();
1062        } else
1063                (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1064                    sizeof (remotehost));
1065        if (!logging)
1066                return;
1067        t = time((time_t *) 0);
1068        syslog(LOG_INFO,"FTPD: connection from %s at %s", remotehost, ctime(&t));
1069}
1070
1071/*
1072 * Record logout in wtmp file
1073 * and exit with supplied status.
1074 */
1075dologout(status)
1076        int status;
1077{
[6084]1078#if defined(ATHENA) && defined(_IBMR2)
1079        seteuid_rios(0);
1080#else
1081        seteuid(0);
1082#endif
[2890]1083        if (logged_in) {
[6084]1084#ifdef ATHENA
1085          if (athena)
1086                loguwtmp(ttyline, "", "");
1087          else
1088#endif
[2890]1089                logwtmp(ttyline, "", "");
1090        }
[6084]1091#ifdef ATHENA
[7260]1092        if (athena)
[6084]1093          athena_logout(pw);
1094#endif
[7260]1095
[2890]1096        /* beware of flushing buffers after a SIGPIPE */
1097        _exit(status);
1098}
1099
[2893]1100
[2890]1101/*
[2893]1102 * Check to see if the specified name is in
1103 * the file FTPUSERS.  Return 1 if it is not (or
1104 * if FTPUSERS cannot be opened), or 0 if it is.
1105 */
1106checkftpusers(name)
1107        char *name;
1108{
1109        FILE *fd;
1110        char line[BUFSIZ], *cp;
1111        int found = 0;
1112       
1113        if ((fd = fopen(FTPUSERS, "r")) == NULL)
1114                return (1);
1115        while (fgets(line, sizeof (line), fd) != NULL) {
[7260]1116                if ((cp = strchr(line, '\n')) != NULL)
[2893]1117                        *cp = '\0';
1118                if (strcmp(line, name) == 0) {
1119                        found++;
1120                        break;
1121                }
1122        }
1123        (void) fclose(fd);
1124        return (!found);
1125}
1126
1127
1128/*
[6084]1129 * Check user requesting login privileges.
[2890]1130 * Disallow anyone who does not have a standard
1131 * shell returned by getusershell() (/etc/shells).
[2893]1132 * Then, call checkftpusers() to disallow anyone
1133 * mentioned in the file FTPUSERS,
[2890]1134 * to allow people such as uucp to be avoided.
1135 */
1136checkuser(name)
1137        register char *name;
1138{
1139        register char *cp;
1140        struct passwd *p;
1141        char *shell;
[2893]1142        char *getusershell();
[2890]1143
[6084]1144#ifdef ATHENA
1145        if (athena ?
1146                     (((p = athena_getpwnam(name)) == NULL) ||
1147                        athena_notallowed(name))
[7260]1148                   : ((p = get_pwnam(name)) == NULL))
[6084]1149#else
[7260]1150        if ((p = get_pwnam(name)) == NULL)
[6084]1151#endif
[2890]1152                return (0);
1153        if ((shell = p->pw_shell) == NULL || *shell == 0)
1154                shell = "/bin/sh";
1155        while ((cp = getusershell()) != NULL)
1156                if (strcmp(cp, shell) == 0)
1157                        break;
1158        endusershell();
1159        if (cp == NULL)
1160                return (0);
[2893]1161        return (checkftpusers(name));
[2890]1162}
1163
1164myoob()
1165{
1166        char *cp;
1167
1168        /* only process if transfer occurring */
1169        if (!transflag) {
1170                return;
1171        }
1172        cp = tmpline;
1173        if (getline(cp, 7, stdin) == NULL) {
1174                reply(221, "You could at least say goodby.");
1175                dologout(0);
1176        }
1177        upper(cp);
1178        if (strcmp(cp, "ABOR\r\n"))
1179                return;
1180        tmpline[0] = '\0';
1181        reply(426,"Transfer aborted. Data connection closed.");
1182        reply(226,"Abort successful");
1183        longjmp(urgcatch, 1);
1184}
1185
1186/*
1187 * Note: The 530 reply codes could be 4xx codes, except nothing is
1188 * given in the state tables except 421 which implies an exit.  (RFC959)
1189 */
1190passive()
1191{
1192        int len;
1193        struct sockaddr_in tmp;
1194        register char *p, *a;
1195
1196        pdata = socket(AF_INET, SOCK_STREAM, 0);
1197        if (pdata < 0) {
1198                reply(530, "Can't open passive connection");
1199                return;
1200        }
1201        tmp = ctrl_addr;
1202        tmp.sin_port = 0;
[6084]1203#if defined(_IBMR2)
1204        seteuid_rios(0);
1205#else
[2890]1206        seteuid(0);
[6084]1207#endif
[2890]1208        if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) {
[6084]1209#if defined(ATHENA) && defined(_IBMR2)
1210                seteuid_rios(pw->pw_uid);
1211#else
[2890]1212                seteuid(pw->pw_uid);
[6084]1213#endif
[2890]1214                (void) close(pdata);
1215                pdata = -1;
1216                reply(530, "Can't open passive connection");
1217                return;
1218        }
[6084]1219#if defined(ATHENA) && defined(_IBMR2)
1220        seteuid_rios(pw->pw_uid);
1221#else
[2890]1222        seteuid(pw->pw_uid);
[6084]1223#endif
[2890]1224        len = sizeof(tmp);
1225        if (getsockname(pdata, (char *) &tmp, &len) < 0) {
1226                (void) close(pdata);
1227                pdata = -1;
1228                reply(530, "Can't open passive connection");
1229                return;
1230        }
1231        if (listen(pdata, 1) < 0) {
1232                (void) close(pdata);
1233                pdata = -1;
1234                reply(530, "Can't open passive connection");
1235                return;
1236        }
1237        a = (char *) &tmp.sin_addr;
1238        p = (char *) &tmp.sin_port;
1239
1240#define UC(b) (((int) b) & 0xff)
1241
1242        reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1243                UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1244}
1245
1246char *
1247gunique(local)
1248        char *local;
1249{
1250        static char new[MAXPATHLEN];
[7260]1251        char *cp = strrchr(local, '/');
[2890]1252        int d, count=0;
1253        char ext = '1';
1254
1255        if (cp) {
1256                *cp = '\0';
1257        }
1258        d = access(cp ? local : ".", 2);
1259        if (cp) {
1260                *cp = '/';
1261        }
1262        if (d < 0) {
1263                syslog(LOG_ERR, "%s: %m", local);
1264                return((char *) 0);
1265        }
1266        (void) strcpy(new, local);
1267        cp = new + strlen(new);
1268        *cp++ = '.';
1269        while (!d) {
1270                if (++count == 100) {
1271                        reply(452, "Unique file name not cannot be created.");
1272                        return((char *) 0);
1273                }
1274                *cp++ = ext;
1275                *cp = '\0';
1276                if (ext == '9') {
1277                        ext = '0';
1278                }
1279                else {
1280                        ext++;
1281                }
1282                if ((d = access(new, 0)) < 0) {
1283                        break;
1284                }
1285                if (ext != '0') {
1286                        cp--;
1287                }
1288                else if (*(cp - 2) == '.') {
1289                        *(cp - 1) = '1';
1290                }
1291                else {
1292                        *(cp - 2) = *(cp - 2) + 1;
1293                        cp--;
1294                }
1295        }
1296        return(new);
1297}
Note: See TracBrowser for help on using the repository browser.