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

Revision 10101, 25.3 KB checked in by ghudson, 28 years ago (diff)
Close a window of vulnerability in signal handlers.
Line 
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>
47#ifdef SYSV
48#include <shadow.h>
49#endif
50#include <setjmp.h>
51#include <netdb.h>
52#include <errno.h>
53#ifdef POSIX
54#include <string.h>
55#include <termios.h>
56#else
57#include <strings.h>
58#endif
59#ifdef ultrix
60#include <nsyslog.h>
61#else
62#include <syslog.h>
63#endif
64#ifdef ATHENA
65#include "athena_ftpd.h"
66#include "krb.h"
67#endif
68
69#ifndef MAXHOSTNAMELEN
70#define MAXHOSTNAMELEN  64
71#endif /* !MAXHOSTNAMELEN */
72
73#ifndef BUG_ADDRESS
74#define BUG_ADDRESS "ftp-bugs@ATHENA.MIT.EDU"
75#endif
76 
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();
91#ifndef SOLARIS
92extern  char *getline(), *getwd();
93#else
94extern  char *getline(), *getcwd();
95#endif
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;
107#ifdef ATHENA
108int     athena;
109#endif
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];
125char    *bug_address = NULL;
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();
139#ifdef ATHENA
140int     dologout();
141#endif
142int     myoob();
143FILE    *getdatasock(), *dataconn();
144
145main(argc, argv)
146        int argc;
147        char *argv[];
148{
149        int addrlen, on = 1;
150        long pgid;
151        int cp;
152        struct hostent *hostentry;
153        extern char *optarg;
154        extern int optind;
155#ifdef POSIX
156        struct sigaction act;
157        sigemptyset(&act.sa_mask);
158        act.sa_flags = 0;
159#endif
160       
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;
173#ifdef ATHENA
174        athena = 0;
175#endif
176#ifdef LOG_LOCAL3
177        openlog("ftpd", LOG_PID, LOG_LOCAL3);
178#else
179        openlog("ftpd", LOG_PID);
180#endif
181#ifdef ATHENA
182        while ((cp = getopt(argc, argv, "avdlt:b:")) != EOF) switch (cp) {
183        case 'a':
184                athena = 1;
185                break;
186#else
187        while ((cp = getopt(argc, argv, "vdlt:b:")) != EOF) switch (cp) {
188#endif
189        case 'v':
190                debug = 1;
191                break;
192
193        case 'd':
194                debug = 1;
195                break;
196
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;
213        }
214#ifdef BUG_ADDRESS
215        if (! bug_address)
216                bug_address = BUG_ADDRESS;
217#endif
218        (void) freopen("/dev/null", "w", stderr);
219#ifdef POSIX
220        act.sa_handler= (void (*)()) lostconn;
221        (void) sigaction (SIGPIPE, &act, NULL);
222#else
223        (void) signal(SIGPIPE, lostconn);       
224#endif
225#ifdef ATHENA
226        if (athena)
227          {
228#ifdef POSIX
229            act.sa_handler= (void (*)()) dologout;
230            (void) sigaction (SIGHUP, &act, NULL);
231            (void) sigaction (SIGTERM, &act, NULL);
232#else
233            (void) signal(SIGHUP, dologout);
234            (void) signal(SIGTERM, dologout);
235#endif
236          }
237#endif
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
246        (void) signal(SIGCHLD, SIG_IGN);
247        if ((int)signal(SIGURG, myoob) < 0)
248                syslog(LOG_ERR, "signal: %m");
249#endif
250
251
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();
259#ifndef SOLARIS
260        if (ioctl(fileno(stdin), SIOCSPGRP, (char *) &pgid) < 0) {
261                syslog(LOG_ERR, "ioctl: %m");
262        }
263#endif
264
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));
277        hostentry = gethostbyname(hostname);
278        if (hostentry) {
279                strncpy(hostname, hostentry->h_name, sizeof(hostname));
280                hostname[sizeof(hostname) - 1] = '\0';
281        }
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
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
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
353#ifdef ATHENA
354        if ((p = (athena ? athena_getpwnam(name)
355                         : get_pwnam(name))) == NULL)
356#else
357        if ((p = get_pwnam(name)) == NULL)
358#endif
359                return (p);
360        if (save.pw_name) {
361                free(save.pw_name);
362                free(save.pw_passwd);
363#if !defined(_IBMR2)  && !defined(SOLARIS)
364                free(save.pw_comment);
365#endif
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);
373#if !defined(_IBMR2) && !defined(SOLARIS)
374        save.pw_comment = sgetsave(p->pw_comment);
375#endif
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;
386#ifdef ATHENA
387        char *athena_auth_errtext, *athena_attach_errtext;
388#endif
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 */
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
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.");
419                        pw = NULL; /* pw = NULL's are small memory leaks XXX */
420                        return;
421                }
422#ifdef ATHENA
423            }
424#endif
425        }
426#if defined(_IBMR2)
427        setegid_rios(pw->pw_gid);
428#else
429        setegid(pw->pw_gid);
430#endif
431        initgroups(pw->pw_name, pw->pw_gid);
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
449        if (chdir(pw->pw_dir)) {
450#ifdef ATHENA
451                if (athena && athena_attach_errtext)
452                  lreply(530, athena_attach_errtext);
453#endif
454                reply(530, "User %s: can't change directory to %s.",
455                        pw->pw_name, pw->pw_dir);
456                goto bad;
457        }
458#if defined(_IBMR2)
459        seteuid_rios(0);
460#else
461        seteuid(0);
462#endif
463
464        /* open wtmp before chroot */
465        (void)sprintf(ttyline, "ftp%d", getpid());
466#ifdef ATHENA
467        if (athena)
468          loguwtmp(ttyline, pw->pw_name, remotehost);
469        else
470#endif
471        logwtmp(ttyline, pw->pw_name, remotehost);
472
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
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
512          reply(230, "User %s logged in.", pw->pw_name);
513#if defined(_IBMR2)
514        seteuid_rios(pw->pw_uid);
515#else
516#ifdef SOLARIS
517        setuid(pw->pw_uid);
518#else
519        seteuid(pw->pw_uid);
520#endif
521#endif
522        home = pw->pw_dir;              /* home dir for globbing */
523        return;
524bad:
525#if defined(_IBMR2)
526        seteuid_rios(0);
527#else
528        seteuid(0);
529#endif
530#ifdef ATHENA
531        if (athena)
532          athena_logout(pw);
533#endif
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);
649#if defined(ATHENA) && defined(_IBMR2)
650        seteuid_rios(0);
651#else
652#ifdef SOLARIS
653        setuid(0);
654#else
655        seteuid(0);
656#endif
657#endif
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;
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)
668                goto bad;
669#if defined(ATHENA) && defined(_IBMR2)
670        seteuid_rios(pw->pw_uid);
671#else
672#ifdef SOLARIS
673        setuid(pw->pw_uid);
674#else
675       seteuid(pw->pw_uid);
676#endif
677#endif
678        return (fdopen(s, mode));
679bad:
680
681#if defined(ATHENA) && defined(_IBMR2)
682        seteuid_rios(pw->pw_uid);
683#else
684#ifdef SOLARIS
685        setuid(pw->pw_uid);
686#else
687        seteuid(pw->pw_uid);
688#endif
689#endif
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) {
736                reply(425, "Can't create data socket (%s,%d): %s. ",
737                    inet_ntoa(data_source.sin_addr),
738                    ntohs(data_source.sin_port),
739                    sys_errlist[errno]) ;
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
891reply(n, s, p0, p1, p2, p3, p4, p5)
892        int n;
893        char *s, *p0, *p1, *p2, *p3, *p4, *p5;
894     /* declaring p0-5 as char * reduces number of errors from hc2 */
895{
896
897        printf("%d ", n);
898        printf(s, p0, p1, p2, p3, p4, p5);
899        printf("\r\n");
900        (void) fflush(stdout);
901        if (debug) {
902                syslog(LOG_DEBUG, "<--- %d ", n);
903                syslog(LOG_DEBUG, s, p0, p1, p2, p3, p4, p5);
904        }
905}
906
907lreply(n, s, p0, p1, p2, p3, p4)
908        int n;
909        char *s, *p0, *p1, *p2, *p3, *p4;
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
938        cp = strchr(cbuf,'\n');
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();
984#if defined(ATHENA) && defined(_IBMR2)
985        seteuid_rios(pw->pw_uid);
986#else
987        seteuid(pw->pw_uid);
988#endif
989        if (mkdir(name, 0777) < 0)
990                reply(550, "%s: %s.", name, sys_errlist[errno]);
991        else
992                reply(257, "MKD command successful.");
993#if defined(ATHENA) && defined(_IBMR2)
994        seteuid_rios(oldeuid);
995#else
996        seteuid(oldeuid);
997#endif
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
1015#ifndef SOLARIS
1016        if (getwd(path) == NULL) {
1017#else
1018        if( getcwd(path, MAXPATHLEN + 1) == NULL) {
1019#endif
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{
1078        /* Avoid window where SIGURG could go back to main loop after euid
1079         * is 0. */
1080        transflag = 0;
1081
1082#if defined(ATHENA) && defined(_IBMR2)
1083        seteuid_rios(0);
1084#else
1085        seteuid(0);
1086#endif
1087        if (logged_in) {
1088#ifdef ATHENA
1089          if (athena)
1090                loguwtmp(ttyline, "", "");
1091          else
1092#endif
1093                logwtmp(ttyline, "", "");
1094        }
1095#ifdef ATHENA
1096        if (athena)
1097          athena_logout(pw);
1098#endif
1099
1100        /* beware of flushing buffers after a SIGPIPE */
1101        _exit(status);
1102}
1103
1104
1105/*
1106 * Check to see if the specified name is in
1107 * the file FTPUSERS.  Return 1 if it is not (or
1108 * if FTPUSERS cannot be opened), or 0 if it is.
1109 */
1110checkftpusers(name)
1111        char *name;
1112{
1113        FILE *fd;
1114        char line[BUFSIZ], *cp;
1115        int found = 0;
1116       
1117        if ((fd = fopen(FTPUSERS, "r")) == NULL)
1118                return (1);
1119        while (fgets(line, sizeof (line), fd) != NULL) {
1120                if ((cp = strchr(line, '\n')) != NULL)
1121                        *cp = '\0';
1122                if (strcmp(line, name) == 0) {
1123                        found++;
1124                        break;
1125                }
1126        }
1127        (void) fclose(fd);
1128        return (!found);
1129}
1130
1131
1132/*
1133 * Check user requesting login privileges.
1134 * Disallow anyone who does not have a standard
1135 * shell returned by getusershell() (/etc/shells).
1136 * Then, call checkftpusers() to disallow anyone
1137 * mentioned in the file FTPUSERS,
1138 * to allow people such as uucp to be avoided.
1139 */
1140checkuser(name)
1141        register char *name;
1142{
1143        register char *cp;
1144        struct passwd *p;
1145        char *shell;
1146        char *getusershell();
1147
1148#ifdef ATHENA
1149        if (athena ?
1150                     (((p = athena_getpwnam(name)) == NULL) ||
1151                        athena_notallowed(name))
1152                   : ((p = get_pwnam(name)) == NULL))
1153#else
1154        if ((p = get_pwnam(name)) == NULL)
1155#endif
1156                return (0);
1157        if ((shell = p->pw_shell) == NULL || *shell == 0)
1158                shell = "/bin/sh";
1159        while ((cp = getusershell()) != NULL)
1160                if (strcmp(cp, shell) == 0)
1161                        break;
1162        endusershell();
1163        if (cp == NULL)
1164                return (0);
1165        return (checkftpusers(name));
1166}
1167
1168myoob()
1169{
1170        char *cp;
1171
1172        /* only process if transfer occurring */
1173        if (!transflag) {
1174                return;
1175        }
1176        cp = tmpline;
1177        if (getline(cp, 7, stdin) == NULL) {
1178                reply(221, "You could at least say goodby.");
1179                dologout(0);
1180        }
1181        upper(cp);
1182        if (strcmp(cp, "ABOR\r\n"))
1183                return;
1184        tmpline[0] = '\0';
1185        reply(426,"Transfer aborted. Data connection closed.");
1186        reply(226,"Abort successful");
1187        longjmp(urgcatch, 1);
1188}
1189
1190/*
1191 * Note: The 530 reply codes could be 4xx codes, except nothing is
1192 * given in the state tables except 421 which implies an exit.  (RFC959)
1193 */
1194passive()
1195{
1196        int len;
1197        struct sockaddr_in tmp;
1198        register char *p, *a;
1199
1200        pdata = socket(AF_INET, SOCK_STREAM, 0);
1201        if (pdata < 0) {
1202                reply(530, "Can't open passive connection");
1203                return;
1204        }
1205        tmp = ctrl_addr;
1206        tmp.sin_port = 0;
1207#if defined(_IBMR2)
1208        seteuid_rios(0);
1209#else
1210        seteuid(0);
1211#endif
1212        if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) {
1213#if defined(ATHENA) && defined(_IBMR2)
1214                seteuid_rios(pw->pw_uid);
1215#else
1216                seteuid(pw->pw_uid);
1217#endif
1218                (void) close(pdata);
1219                pdata = -1;
1220                reply(530, "Can't open passive connection");
1221                return;
1222        }
1223#if defined(ATHENA) && defined(_IBMR2)
1224        seteuid_rios(pw->pw_uid);
1225#else
1226        seteuid(pw->pw_uid);
1227#endif
1228        len = sizeof(tmp);
1229        if (getsockname(pdata, (char *) &tmp, &len) < 0) {
1230                (void) close(pdata);
1231                pdata = -1;
1232                reply(530, "Can't open passive connection");
1233                return;
1234        }
1235        if (listen(pdata, 1) < 0) {
1236                (void) close(pdata);
1237                pdata = -1;
1238                reply(530, "Can't open passive connection");
1239                return;
1240        }
1241        a = (char *) &tmp.sin_addr;
1242        p = (char *) &tmp.sin_port;
1243
1244#define UC(b) (((int) b) & 0xff)
1245
1246        reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1247                UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1248}
1249
1250char *
1251gunique(local)
1252        char *local;
1253{
1254        static char new[MAXPATHLEN];
1255        char *cp = strrchr(local, '/');
1256        int d, count=0;
1257        char ext = '1';
1258
1259        if (cp) {
1260                *cp = '\0';
1261        }
1262        d = access(cp ? local : ".", 2);
1263        if (cp) {
1264                *cp = '/';
1265        }
1266        if (d < 0) {
1267                syslog(LOG_ERR, "%s: %m", local);
1268                return((char *) 0);
1269        }
1270        (void) strcpy(new, local);
1271        cp = new + strlen(new);
1272        *cp++ = '.';
1273        while (!d) {
1274                if (++count == 100) {
1275                        reply(452, "Unique file name not cannot be created.");
1276                        return((char *) 0);
1277                }
1278                *cp++ = ext;
1279                *cp = '\0';
1280                if (ext == '9') {
1281                        ext = '0';
1282                }
1283                else {
1284                        ext++;
1285                }
1286                if ((d = access(new, 0)) < 0) {
1287                        break;
1288                }
1289                if (ext != '0') {
1290                        cp--;
1291                }
1292                else if (*(cp - 2) == '.') {
1293                        *(cp - 1) = '1';
1294                }
1295                else {
1296                        *(cp - 2) = *(cp - 2) + 1;
1297                        cp--;
1298                }
1299        }
1300        return(new);
1301}
Note: See TracBrowser for help on using the repository browser.