home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / permissions / part03 < prev    next >
Encoding:
Text File  |  1992-03-22  |  26.3 KB  |  1,214 lines

  1. Newsgroups: comp.sources.unix
  2. From: deraadt@cpsc.ucalgary.ca (Theo Deraadt)
  3. Subject: v25i154: permissions - access control library for YP/NIS environments, Part03/03
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: deraadt@cpsc.ucalgary.ca (Theo Deraadt)
  8. Posting-Number: Volume 25, Issue 154
  9. Archive-Name: permissions/part03
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 3 (of 3)."
  18. # Contents:  in.ftpd/ftpd.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Tue Mar 10 23:11:21 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'in.ftpd/ftpd.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'in.ftpd/ftpd.c'\"
  23. else
  24. echo shar: Extracting \"'in.ftpd/ftpd.c'\" \(24225 characters\)
  25. sed "s/^X//" >'in.ftpd/ftpd.c' <<'END_OF_FILE'
  26. X/*
  27. X * Copyright (c) 1985, 1988 Regents of the University of California.
  28. X * All rights reserved.
  29. X *
  30. X * Redistribution and use in source and binary forms are permitted
  31. X * provided that the above copyright notice and this paragraph are
  32. X * duplicated in all such forms and that any documentation,
  33. X * advertising materials, and other materials related to such
  34. X * distribution and use acknowledge that the software was developed
  35. X * by the University of California, Berkeley.  The name of the
  36. X * University may not be used to endorse or promote products derived
  37. X * from this software without specific prior written permission.
  38. X */
  39. X
  40. X#ifndef lint
  41. char copyright[] =
  42. X"@(#) Copyright (c) 1985, 1988 Regents of the University of California.\n\
  43. X All rights reserved.\n";
  44. X#endif not lint
  45. X
  46. X#ifndef lint
  47. static char sccsid[] = "@(#)ftpd.c    5.2 (Berkeley) 12/7/88";
  48. X#endif not lint
  49. X
  50. X/*
  51. X * FTP server.
  52. X */
  53. X#include <sys/param.h>
  54. X#include <sys/stat.h>
  55. X#include <sys/ioctl.h>
  56. X#include <sys/socket.h>
  57. X#include <sys/file.h>
  58. X#include <sys/wait.h>
  59. X
  60. X#include <netinet/in.h>
  61. X
  62. X#include <arpa/ftp.h>
  63. X#include <arpa/inet.h>
  64. X#include <arpa/telnet.h>
  65. X
  66. X#include <stdio.h>
  67. X#include <signal.h>
  68. X#include <pwd.h>
  69. X#ifdef PERMS
  70. X#include <string.h>
  71. X#include <grp.h>
  72. X#endif
  73. X#include <setjmp.h>
  74. X#include <netdb.h>
  75. X#include <errno.h>
  76. X#include <strings.h>
  77. X#include <syslog.h>
  78. X#include <varargs.h>
  79. X
  80. X/*
  81. X * File containing login names
  82. X * NOT to be used on this machine.
  83. X * Commonly used to disallow uucp.
  84. X */
  85. X#define    FTPUSERS    "/etc/ftpusers"
  86. X
  87. extern    int errno;
  88. extern    char *sys_errlist[];
  89. extern    int sys_nerr;
  90. extern    char *crypt();
  91. extern    char version[];
  92. extern    char *home;        /* pointer to home directory for glob */
  93. extern    FILE *ftpd_popen(), *fopen(), *freopen();
  94. extern    int  ftpd_pclose(), fclose();
  95. extern    char *getline();
  96. extern    char cbuf[];
  97. X
  98. struct    sockaddr_in ctrl_addr;
  99. struct    sockaddr_in data_source;
  100. struct    sockaddr_in data_dest;
  101. struct    sockaddr_in his_addr;
  102. X
  103. int    data;
  104. jmp_buf    errcatch, urgcatch;
  105. int    logged_in;
  106. struct    passwd *pw;
  107. int    debug;
  108. int    timeout = 900;    /* timeout after 15 minutes of inactivity */
  109. int    logging;
  110. int    guest;
  111. int    type;
  112. int    form;
  113. int    stru;            /* avoid C keyword */
  114. int    mode;
  115. int    usedefault = 1;        /* for data transfers */
  116. int    pdata = -1;        /* for passive mode */
  117. int    transflag;
  118. int    socksize = 24 * 1024;    /* larger socket window size for data */
  119. char    tmpline[7];
  120. char    hostname[MAXHOSTNAMELEN];
  121. char    remotehost[MAXHOSTNAMELEN];
  122. char    buf[BUFSIZ*8];        /* larger buffer to speed up binary xfers */
  123. X
  124. X/*
  125. X * Timeout intervals for retrying connections
  126. X * to hosts that don't accept PORT cmds.  This
  127. X * is a kludge, but given the problems with TCP...
  128. X */
  129. X#define    SWAITMAX    90    /* wait at most 90 seconds */
  130. X#define    SWAITINT    5    /* interval between retries */
  131. X
  132. int    swaitmax = SWAITMAX;
  133. int    swaitint = SWAITINT;
  134. X
  135. int    lostconn();
  136. int    myoob();
  137. XFILE    *getdatasock(), *dataconn();
  138. X
  139. main(argc, argv)
  140. X    int argc;
  141. X    char *argv[];
  142. X{
  143. X    int addrlen, on = 1;
  144. X    char *cp;
  145. X#ifdef PERMS
  146. X    char domainname[MAXHOSTNAMELEN];
  147. X#endif
  148. X    openlog("ftpd", LOG_PID, LOG_DAEMON);
  149. X    addrlen = sizeof (his_addr);
  150. X    if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
  151. X        syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
  152. X        exit(1);
  153. X    }
  154. X    addrlen = sizeof (ctrl_addr);
  155. X    if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
  156. X        syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
  157. X        exit(1);
  158. X    }
  159. X    data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  160. X    debug = 0;
  161. X    argc--, argv++;
  162. X    while (argc > 0 && *argv[0] == '-') {
  163. X        for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
  164. X
  165. X        case 'v':
  166. X            debug = 1;
  167. X            break;
  168. X
  169. X        case 'd':
  170. X            debug = 1;
  171. X            break;
  172. X
  173. X        case 'l':
  174. X            logging = 1;
  175. X            break;
  176. X
  177. X        case 't':
  178. X            timeout = atoi(++cp);
  179. X            goto nextopt;
  180. X            break;
  181. X
  182. X        default:
  183. X            fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
  184. X                 *cp);
  185. X            break;
  186. X        }
  187. nextopt:
  188. X        argc--, argv++;
  189. X    }
  190. X    (void) freopen("/dev/null", "w", stderr);
  191. X    (void) signal(SIGPIPE, lostconn);
  192. X    (void) signal(SIGCHLD, SIG_IGN);
  193. X    if (signal(SIGURG, myoob) == BADSIG)
  194. X        syslog(LOG_ERR, "signal: %m");
  195. X    /* handle urgent data inline */
  196. X#ifdef SO_OOBINLINE
  197. X    if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
  198. X        syslog(LOG_ERR, "setsockopt: %m");
  199. X#endif
  200. X    if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  201. X        syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  202. X    dolog(&his_addr);
  203. X    /* do telnet option negotiation here */
  204. X    /*
  205. X     * Set up default state
  206. X     */
  207. X    data = -1;
  208. X    type = TYPE_A;
  209. X    form = FORM_N;
  210. X    stru = STRU_F;
  211. X    mode = MODE_S;
  212. X    tmpline[0] = '\0';
  213. X    (void) gethostname(hostname, sizeof (hostname));
  214. X#ifdef PERMS
  215. X    if( Getdomainname(domainname, sizeof(domainname)) ) {
  216. X        reply(220, "%s.%s FTP server (%s) ready.",
  217. X            hostname, domainname, version);
  218. X    } else {
  219. X        reply(220, "%s FTP server (%s) ready.",
  220. X            hostname, version);
  221. X    }
  222. X#else
  223. X    reply(220, "%s FTP server (%s) ready.", hostname, version);
  224. X#endif
  225. X    (void) setjmp(errcatch);
  226. X    for (;;)
  227. X        (void) yyparse();
  228. X}
  229. X
  230. lostconn()
  231. X{
  232. X
  233. X    if (debug)
  234. X        syslog(LOG_DEBUG, "lost connection");
  235. X    dologout(-1);
  236. X}
  237. X
  238. static char ttyline[20];
  239. X
  240. X/*
  241. X * Helper function for sgetpwnam().
  242. X */
  243. char *
  244. sgetsave(s)
  245. X    char *s;
  246. X{
  247. X    char *malloc();
  248. X    char *new = malloc((unsigned) strlen(s) + 1);
  249. X    
  250. X    if (new == NULL) {
  251. X        reply(553, "Local resource failure: malloc");
  252. X        dologout(1);
  253. X    }
  254. X    (void) strcpy(new, s);
  255. X    return (new);
  256. X}
  257. X
  258. X/*
  259. X * Save the result of a getpwnam.  Used for USER command, since
  260. X * the data returned must not be clobbered by any other command
  261. X * (e.g., globbing).
  262. X */
  263. struct passwd *
  264. sgetpwnam(name)
  265. X    char *name;
  266. X{
  267. X    static struct passwd save;
  268. X    register struct passwd *p;
  269. X    char *sgetsave();
  270. X
  271. X    if ((p = getpwnam(name)) == NULL)
  272. X        return (p);
  273. X    if (save.pw_name) {
  274. X        free(save.pw_name);
  275. X        free(save.pw_passwd);
  276. X        free(save.pw_comment);
  277. X        free(save.pw_gecos);
  278. X        free(save.pw_dir);
  279. X        free(save.pw_shell);
  280. X    }
  281. X    save = *p;
  282. X    save.pw_name = sgetsave(p->pw_name);
  283. X    save.pw_passwd = sgetsave(p->pw_passwd);
  284. X    save.pw_comment = sgetsave(p->pw_comment);
  285. X    save.pw_gecos = sgetsave(p->pw_gecos);
  286. X    save.pw_dir = sgetsave(p->pw_dir);
  287. X    save.pw_shell = sgetsave(p->pw_shell);
  288. X    return (&save);
  289. X}
  290. X
  291. int login_attempts;        /* number of failed login attempts */
  292. int askpasswd;            /* had user command, ask for passwd */
  293. X
  294. X/*
  295. X * USER command.
  296. X * Sets global passwd pointer pw if named account exists
  297. X * and is acceptable; sets askpasswd if a PASS command is
  298. X * expected. If logged in previously, need to reset state.
  299. X * If name is "ftp" or "anonymous" and ftp account exists,
  300. X * set guest and pw, then just return.
  301. X * If account doesn't exist, ask for passwd anyway.
  302. X * Otherwise, check user requesting login privileges.
  303. X * Disallow anyone who does not have a standard
  304. X * shell returned by getusershell() (/etc/shells).
  305. X * Disallow anyone mentioned in the file FTPUSERS
  306. X * to allow people such as root and uucp to be avoided.
  307. X */
  308. user(name)
  309. X    char *name;
  310. X{
  311. X    register char *cp;
  312. X    FILE *fd;
  313. X    char *shell;
  314. X    char line[BUFSIZ], *index(), *getusershell();
  315. X
  316. X    if (logged_in) {
  317. X        if (guest) {
  318. X            reply(530, "Can't change user from guest login.");
  319. X            return;
  320. X        }
  321. X        end_login();
  322. X    }
  323. X
  324. X    guest = 0;
  325. X    if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
  326. X        if ((pw = sgetpwnam("ftp")) != NULL) {
  327. X#ifdef PERMS
  328. X            if( checkuser(pw) ) {
  329. X                reply(530, "Anon FTP not permitted here.");
  330. X                pw = (struct passwd *) NULL;
  331. X                return;
  332. X            }
  333. X#endif
  334. X            guest = 1;
  335. X            askpasswd = 1;
  336. X            reply(331, "Guest login ok, send ident as password.");
  337. X        } else
  338. X            reply(530, "User %s unknown.", name);
  339. X        return;
  340. X    }
  341. X    if (pw = sgetpwnam(name)) {
  342. X#ifdef PERMS
  343. X        if( checkuser(pw)) {
  344. X            reply(530, "User %s access denied.", name);
  345. X            pw = (struct passwd *) NULL;
  346. X            return;
  347. X        }
  348. X#endif
  349. X        if ((shell = pw->pw_shell) == NULL || *shell == 0)
  350. X            shell = "/bin/sh";
  351. X        while ((cp = getusershell()) != NULL)
  352. X            if (strcmp(cp, shell) == 0)
  353. X                break;
  354. X        endusershell();
  355. X        if (cp == NULL) {
  356. X            reply(530, "User %s access denied.", name);
  357. X            pw = (struct passwd *) NULL;
  358. X            return;
  359. X        }
  360. X        if ((fd = fopen(FTPUSERS, "r")) != NULL) {
  361. X            while (fgets(line, sizeof (line), fd) != NULL) {
  362. X            if ((cp = index(line, '\n')) != NULL)
  363. X                *cp = '\0';
  364. X            if (strcmp(line, name) == 0) {
  365. X                reply(530, "User %s access denied.", name);
  366. X                pw = (struct passwd *) NULL;
  367. X                return;
  368. X            }
  369. X            }
  370. X        }
  371. X        (void) fclose(fd);
  372. X    }
  373. X    reply(331, "Password required for %s.", name);
  374. X    askpasswd = 1;
  375. X    /*
  376. X     * Delay before reading passwd after first failed
  377. X     * attempt to slow down passwd-guessing programs.
  378. X     */
  379. X    if (login_attempts)
  380. X        sleep((unsigned) login_attempts);
  381. X}
  382. X
  383. X/*
  384. X * Terminate login as previous user, if any, resetting state;
  385. X * used when USER command is given or login fails.
  386. X */
  387. end_login()
  388. X{
  389. X
  390. X    (void) seteuid((uid_t)0);
  391. X    if (logged_in)
  392. X        logwtmp(ttyline, "", "");
  393. X    pw = NULL;
  394. X    logged_in = 0;
  395. X    guest = 0;
  396. X}
  397. X
  398. pass(passwd)
  399. X    char *passwd;
  400. X{
  401. X    char *xpasswd, *salt;
  402. X
  403. X    if (logged_in || askpasswd == 0) {
  404. X        reply(503, "Login with USER first.");
  405. X        return;
  406. X    }
  407. X    askpasswd = 0;
  408. X    if (!guest) {        /* "ftp" is only account allowed no password */
  409. X        if (pw == NULL)
  410. X            salt = "xx";
  411. X        else
  412. X            salt = pw->pw_passwd;
  413. X        xpasswd = crypt(passwd, salt);
  414. X        /* The strcmp does not catch null passwords! */
  415. X        if (pw == NULL || *pw->pw_passwd == '\0' ||
  416. X            strcmp(xpasswd, pw->pw_passwd)) {
  417. X            reply(530, "Login incorrect.");
  418. X            pw = NULL;
  419. X            if (login_attempts++ >= 5) {
  420. X                syslog(LOG_ERR,
  421. X                    "repeated login failures from %s",
  422. X                    remotehost);
  423. X                exit(0);
  424. X            }
  425. X            return;
  426. X        }
  427. X    }
  428. X    login_attempts = 0;        /* this time successful */
  429. X    (void) setegid((gid_t)pw->pw_gid);
  430. X    (void) initgroups(pw->pw_name, pw->pw_gid);
  431. X    if (chdir(pw->pw_dir)) {
  432. X        if (chdir("/")) {
  433. X            reply(550, "User %s: can't change directory to %s.",
  434. X                pw->pw_name, pw->pw_dir);
  435. X            goto bad;
  436. X        }
  437. X    }
  438. X
  439. X    /* open wtmp before chroot */
  440. X    (void)sprintf(ttyline, "ftp%d", getpid());
  441. X    logwtmp(ttyline, pw->pw_name, remotehost);
  442. X    logged_in = 1;
  443. X
  444. X    if (guest && chroot(pw->pw_dir) < 0) {
  445. X        reply(550, "Can't set guest privileges.");
  446. X        goto bad;
  447. X    }
  448. X    if (seteuid((uid_t)pw->pw_uid) < 0) {
  449. X        reply(550, "Can't set uid.");
  450. X        goto bad;
  451. X    }
  452. X    if (guest)
  453. X        reply(230, "Guest login ok, access restrictions apply.");
  454. X    else
  455. X        reply(230, "User %s logged in.", pw->pw_name);
  456. X    home = pw->pw_dir;        /* home dir for globbing */
  457. X    return;
  458. bad:
  459. X    /* Forget all about it... */
  460. X    end_login();
  461. X}
  462. X
  463. X/*
  464. X * return a printable type string
  465. X */
  466. char *print_type(t)
  467. X{
  468. X    switch (t)
  469. X    {
  470. X      case TYPE_A:    return("ASCII ");
  471. X      case TYPE_L:
  472. X      case TYPE_I:    return("Binary ");
  473. X    }
  474. X    return("");
  475. X}
  476. X
  477. retrieve(cmd, name)
  478. X    char *cmd, *name;
  479. X{
  480. X    FILE *fin, *dout;
  481. X    struct stat st;
  482. X    int (*closefunc)(), tmp;
  483. X    void (*oldpipe)();    /* Hold value of SIGPIPE during close */
  484. X
  485. X    if (cmd == 0) {
  486. X        fin = fopen(name, "r"), closefunc = fclose;
  487. X    } else {
  488. X        char line[BUFSIZ];
  489. X
  490. X        (void) sprintf(line, cmd, name), name = line;
  491. X        fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
  492. X    }
  493. X    if (fin == NULL) {
  494. X        if (errno != 0)
  495. X            perror_reply(550, name);
  496. X        return;
  497. X    }
  498. X    st.st_size = 0;
  499. X    if (cmd == 0 &&
  500. X        (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
  501. X        reply(550, "%s: not a plain file.", name);
  502. X        goto done;
  503. X    }
  504. X    dout = dataconn(name, st.st_size, "w");
  505. X    if (dout == NULL)
  506. X        goto done;
  507. X    if ((tmp = send_data(fin, dout)) > 0 || ferror(dout) > 0) {
  508. X        perror_reply(550, name);
  509. X    }
  510. X    else if (tmp == 0) {
  511. X        reply(226, "%sTransfer complete.", print_type(type));
  512. X    }
  513. X    /*
  514. X     * If the transfer failed because the data connection got aborted,
  515. X     * then the fclose may cause a SIGPIPE trying to flush the buffers
  516. X     * and abort the whole session.  Ignore SIGPIPEs during the fclose.
  517. X     */
  518. X    oldpipe = signal(SIGPIPE, SIG_IGN);
  519. X    (void) fclose(dout);
  520. X    data = -1;
  521. X    pdata = -1;
  522. X    signal(SIGPIPE, oldpipe);
  523. done:
  524. X    (*closefunc)(fin);
  525. X}
  526. X
  527. store(name, mode, unique)
  528. X    char *name, *mode;
  529. X    int unique;
  530. X{
  531. X    FILE *fout, *din;
  532. X    int (*closefunc)(), tmp;
  533. X    char *gunique();
  534. X
  535. X    {
  536. X        struct stat st;
  537. X
  538. X        if (unique && stat(name, &st) == 0 &&
  539. X            (name = gunique(name)) == NULL)
  540. X            return;
  541. X        fout = fopen(name, mode), closefunc = fclose;
  542. X    }
  543. X    if (fout == NULL) {
  544. X        perror_reply(553, name);
  545. X        return;
  546. X    }
  547. X    din = dataconn(name, (off_t)-1, "r");
  548. X    if (din == NULL)
  549. X        goto done;
  550. X    if ((tmp = receive_data(din, fout)) > 0 || ferror(fout) > 0)
  551. X        perror_reply(552, name);
  552. X    else if (tmp == 0) {
  553. X        if (ferror(fout) > 0)
  554. X            perror_reply(552, name);
  555. X        else if (unique)
  556. X            reply(226, "Transfer complete (unique file name:%s).",
  557. X                name);
  558. X        else
  559. X            reply(226, "%sTransfer complete.", print_type(type));
  560. X    }
  561. X    (void) fclose(din);
  562. X    data = -1;
  563. X    pdata = -1;
  564. done:
  565. X    (*closefunc)(fout);
  566. X}
  567. X
  568. XFILE *
  569. getdatasock(mode)
  570. X    char *mode;
  571. X{
  572. X    int s, on = 1;
  573. X
  574. X    if (data >= 0)
  575. X        return (fdopen(data, mode));
  576. X    s = socket(AF_INET, SOCK_STREAM, 0);
  577. X    if (s < 0)
  578. X        return (NULL);
  579. X    (void) seteuid((uid_t)0);
  580. X    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0)
  581. X        goto bad;
  582. X    /* anchor socket to avoid multi-homing problems */
  583. X    data_source.sin_family = AF_INET;
  584. X    data_source.sin_addr = ctrl_addr.sin_addr;
  585. X    if (bind(s, (struct sockaddr *)&data_source, sizeof (data_source)) < 0)
  586. X        goto bad;
  587. X    (void) seteuid((uid_t)pw->pw_uid);
  588. X    return (fdopen(s, mode));
  589. bad:
  590. X    (void) seteuid((uid_t)pw->pw_uid);
  591. X    (void) close(s);
  592. X    return (NULL);
  593. X}
  594. X
  595. XFILE *
  596. dataconn(name, size, mode)
  597. X    char *name;
  598. X    off_t size;
  599. X    char *mode;
  600. X{
  601. X    char sizebuf[32];
  602. X    FILE *file;
  603. X    int retry = 0;
  604. X
  605. X    if (size != (off_t) -1)
  606. X        (void) sprintf (sizebuf, " (%ld bytes)", size);
  607. X    else
  608. X        (void) strcpy(sizebuf, "");
  609. X    if (pdata >= 0) {
  610. X        struct sockaddr_in from;
  611. X        int s, fromlen = sizeof(from);
  612. X
  613. X        s = accept(pdata, (struct sockaddr *)&from, &fromlen);
  614. X        if (s < 0) {
  615. X            reply(425, "Can't open data connection.");
  616. X            (void) close(pdata);
  617. X            pdata = -1;
  618. X            return(NULL);
  619. X        }
  620. X        (void) close(pdata);
  621. X        pdata = s;
  622. X        reply(150, "%sdata connection for %s (%s,%d)%s.",
  623. X             print_type(type),
  624. X             name, inet_ntoa(from.sin_addr),
  625. X             ntohs(from.sin_port), sizebuf);
  626. X        return(fdopen(pdata, mode));
  627. X    }
  628. X    if (data >= 0) {
  629. X        reply(125, "Using existing %sdata connection for %s%s.",
  630. X            print_type(type),
  631. X            name, sizebuf);
  632. X        usedefault = 1;
  633. X        return (fdopen(data, mode));
  634. X    }
  635. X    if (usedefault)
  636. X        data_dest = his_addr;
  637. X    usedefault = 1;
  638. X    file = getdatasock(mode);
  639. X    if (file == NULL) {
  640. X        reply(425, "Can't create data socket (%s,%d): %s.",
  641. X            inet_ntoa(data_source.sin_addr),
  642. X            ntohs(data_source.sin_port),
  643. X            errno < sys_nerr ? sys_errlist[errno] : "unknown error");
  644. X        return (NULL);
  645. X    }
  646. X    data = fileno(file);
  647. X    (void) setsockopt(data, SOL_SOCKET, SO_SNDBUF, (char *)&socksize, 
  648. X                sizeof (socksize));
  649. X    (void) setsockopt(data, SOL_SOCKET, SO_RCVBUF, (char *)&socksize, 
  650. X                sizeof (socksize));
  651. X    while (connect(data, &data_dest, sizeof (data_dest)) < 0) {
  652. X        if (errno == EADDRINUSE && retry < swaitmax) {
  653. X            sleep((unsigned) swaitint);
  654. X            retry += swaitint;
  655. X            continue;
  656. X        }
  657. X        perror_reply(425, "Can't build data connection");
  658. X        (void) fclose(file);
  659. X        data = -1;
  660. X        return (NULL);
  661. X    }
  662. X    reply(150, "%sdata connection for %s (%s,%d)%s.",
  663. X        print_type(type),
  664. X        name, inet_ntoa(data_dest.sin_addr),
  665. X        ntohs(data_dest.sin_port), sizebuf);
  666. X    return (file);
  667. X}
  668. X
  669. X/*
  670. X * Envelope for 'send_data_body'.  Allow data connections to fail without
  671. X * terminating the daemon, but SIGPIPE is set to be ignored so that if
  672. X * one occurs on the data channel we'll just catch the error return on
  673. X * the write rather than causing the whole session to abort.
  674. X */
  675. X
  676. send_data(instr, outstr)
  677. X    FILE *instr;        /* Data being sent */
  678. X    FILE *outstr;        /* Connection being transmitted upon */
  679. X{
  680. X    int value;        /* Return value from send_data_body */
  681. X    void (*oldpipe)();    /* Old handler for SIGPIPE */
  682. X
  683. X    oldpipe = signal(SIGPIPE, SIG_IGN);
  684. X    value = send_data_body(instr, outstr);
  685. X    signal(SIGPIPE, oldpipe);
  686. X    return (value);    
  687. X}
  688. X
  689. X/*
  690. X * Tranfer the contents of "instr" to
  691. X * "outstr" peer using the appropriate
  692. X * encapulation of the date subject
  693. X * to Mode, Structure, and Type.
  694. X *
  695. X * NB: Form isn't handled.
  696. X */
  697. send_data_body(instr, outstr)
  698. X    FILE *instr, *outstr;
  699. X{
  700. X    register int c;
  701. X    int netfd, filefd, cnt;
  702. X
  703. X    transflag++;
  704. X    if (setjmp(urgcatch)) {
  705. X        transflag = 0;
  706. X        return(-1);
  707. X    }
  708. X    switch (type) {
  709. X
  710. X    case TYPE_A:
  711. X        while ((c = getc(instr)) != EOF) {
  712. X            if (c == '\n') {
  713. X                if (ferror (outstr)) {
  714. X                    transflag = 0;
  715. X                    return (1);
  716. X                }
  717. X                (void) putc('\r', outstr);
  718. X            }
  719. X            (void) putc(c, outstr);
  720. X        }
  721. X        transflag = 0;
  722. X        if (ferror (instr) || ferror (outstr)) {
  723. X            return (1);
  724. X        }
  725. X        return (0);
  726. X        
  727. X    case TYPE_I:
  728. X    case TYPE_L:
  729. X        netfd = fileno(outstr);
  730. X        filefd = fileno(instr);
  731. X
  732. X        while ((cnt = read(filefd, buf, sizeof (buf))) > 0) {
  733. X            if (write(netfd, buf, cnt) < 0) {
  734. X                transflag = 0;
  735. X                return (1);
  736. X            }
  737. X        }
  738. X        transflag = 0;
  739. X        return (cnt < 0);
  740. X    }
  741. X    reply(550, "Unimplemented TYPE %d in send_data", type);
  742. X    transflag = 0;
  743. X    return (-1);
  744. X}
  745. X
  746. X/*
  747. X * Transfer data from peer to
  748. X * "outstr" using the appropriate
  749. X * encapulation of the data subject
  750. X * to Mode, Structure, and Type.
  751. X *
  752. X * N.B.: Form isn't handled.
  753. X */
  754. receive_data(instr, outstr)
  755. X    FILE *instr, *outstr;
  756. X{
  757. X    register int c;
  758. X    int cnt;
  759. X
  760. X
  761. X    transflag++;
  762. X    if (setjmp(urgcatch)) {
  763. X        transflag = 0;
  764. X        return(-1);
  765. X    }
  766. X    switch (type) {
  767. X
  768. X    case TYPE_I:
  769. X    case TYPE_L:
  770. X        while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
  771. X            if (write(fileno(outstr), buf, cnt) < 0) {
  772. X                transflag = 0;
  773. X                return (1);
  774. X            }
  775. X        }
  776. X        transflag = 0;
  777. X        return (cnt < 0);
  778. X
  779. X    case TYPE_E:
  780. X        reply(553, "TYPE E not implemented.");
  781. X        transflag = 0;
  782. X        return (-1);
  783. X
  784. X    case TYPE_A:
  785. X        while ((c = getc(instr)) != EOF) {
  786. X            while (c == '\r') {
  787. X                if (ferror (outstr)) {
  788. X                    transflag = 0;
  789. X                    return (1);
  790. X                }
  791. X                if ((c = getc(instr)) != '\n')
  792. X                    (void) putc ('\r', outstr);
  793. X            }
  794. X            (void) putc (c, outstr);
  795. X        }
  796. X        transflag = 0;
  797. X        if (ferror (instr) || ferror (outstr))
  798. X            return (1);
  799. X        return (0);
  800. X    }
  801. X    transflag = 0;
  802. X    fatal("Unknown type in receive_data.");
  803. X    /*NOTREACHED*/
  804. X}
  805. X
  806. fatal(s)
  807. X    char *s;
  808. X{
  809. X    reply(451, "Error in server: %s\n", s);
  810. X    reply(221, "Closing connection due to server error.");
  811. X    dologout(0);
  812. X}
  813. X
  814. X/*VARARGS2*/
  815. reply(n, s, va_alist)
  816. X    int n;
  817. X    char *s;
  818. X    va_dcl
  819. X{
  820. X    va_list ap;
  821. X
  822. X    va_start(ap);
  823. X    printf("%d ", n);
  824. X    _doprnt(s, ap, stdout);
  825. X    printf("\r\n");
  826. X    (void) fflush(stdout);
  827. X    if (debug) {
  828. X        syslog(LOG_DEBUG, "<--- %d ", n);
  829. X        vsyslog(LOG_DEBUG, s, ap);
  830. X    }
  831. X    va_end(ap);
  832. X}
  833. X
  834. X/*VARARGS2*/
  835. lreply(n, s, va_alist)
  836. X    int n;
  837. X    char *s;
  838. X    va_dcl
  839. X{
  840. X    va_list ap;
  841. X
  842. X    va_start(ap);
  843. X    printf("%d-", n);
  844. X    _doprnt(s, ap, stdout);
  845. X    printf("\r\n");
  846. X    (void) fflush(stdout);
  847. X    if (debug) {
  848. X        syslog(LOG_DEBUG, "<--- %d- ", n);
  849. X        vsyslog(LOG_DEBUG, s, ap);
  850. X    }
  851. X    va_end(ap);
  852. X}
  853. X
  854. ack(s)
  855. X    char *s;
  856. X{
  857. X    reply(250, "%s command successful.", s);
  858. X}
  859. X
  860. nack(s)
  861. X    char *s;
  862. X{
  863. X    reply(502, "%s command not implemented.", s);
  864. X}
  865. X
  866. X/* ARGSUSED */
  867. yyerror(s)
  868. X    char *s;
  869. X{
  870. X    char *cp;
  871. X
  872. X    cp = index(cbuf,'\n');
  873. X    *cp = '\0';
  874. X    reply(500, "'%s': command not understood.",cbuf);
  875. X}
  876. X
  877. delete(name)
  878. X    char *name;
  879. X{
  880. X    struct stat st;
  881. X
  882. X    if (stat(name, &st) < 0) {
  883. X        perror_reply(550, name);
  884. X        return;
  885. X    }
  886. X    if ((st.st_mode&S_IFMT) == S_IFDIR) {
  887. X        if (rmdir(name) < 0) {
  888. X            perror_reply(550, name);
  889. X            return;
  890. X        }
  891. X        goto done;
  892. X    }
  893. X    if (unlink(name) < 0) {
  894. X        perror_reply(550, name);
  895. X        return;
  896. X    }
  897. done:
  898. X    ack("DELE");
  899. X}
  900. X
  901. cwd(path)
  902. X    char *path;
  903. X{
  904. X
  905. X    if (chdir(path) < 0) {
  906. X        perror_reply(550, path);
  907. X        return;
  908. X    }
  909. X    ack("CWD");
  910. X}
  911. X
  912. makedir(name)
  913. X    char *name;
  914. X{
  915. X    if (mkdir(name, 0777) < 0)
  916. X        perror_reply(550, name);
  917. X    else
  918. X        reply(257, "MKD command successful.");
  919. X}
  920. X
  921. removedir(name)
  922. X    char *name;
  923. X{
  924. X
  925. X    if (rmdir(name) < 0) {
  926. X        perror_reply(550, name);
  927. X        return;
  928. X    }
  929. X    ack("RMD");
  930. X}
  931. X
  932. pwd()
  933. X{
  934. X    char path[MAXPATHLEN + 1];
  935. X    extern char *getwd();
  936. X
  937. X    if (getwd(path) == (char *)NULL) {
  938. X        reply(550, "%s.", path);
  939. X        return;
  940. X    }
  941. X    reply(257, "\"%s\" is current directory.", path);
  942. X}
  943. X
  944. char *
  945. renamefrom(name)
  946. X    char *name;
  947. X{
  948. X    struct stat st;
  949. X
  950. X    if (stat(name, &st) < 0) {
  951. X        perror_reply(550, name);
  952. X        return ((char *)0);
  953. X    }
  954. X    reply(350, "File exists, ready for destination name");
  955. X    return (name);
  956. X}
  957. X
  958. renamecmd(from, to)
  959. X    char *from, *to;
  960. X{
  961. X
  962. X    if (rename(from, to) < 0) {
  963. X        perror_reply(550, "rename");
  964. X        return;
  965. X    }
  966. X    ack("RNTO");
  967. X}
  968. X
  969. dolog(sin)
  970. X    struct sockaddr_in *sin;
  971. X{
  972. X    struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
  973. X        sizeof (struct in_addr), AF_INET);
  974. X    time_t t, time();
  975. X    extern char *ctime();
  976. X
  977. X    if (hp)
  978. X        (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
  979. X    else
  980. X        (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
  981. X            sizeof (remotehost));
  982. X    if (!logging)
  983. X        return;
  984. X    t = time((time_t *) 0);
  985. X    syslog(LOG_INFO, "connection from %s at %s",
  986. X        remotehost, ctime(&t));
  987. X}
  988. X
  989. X/*
  990. X * Record logout in wtmp file
  991. X * and exit with supplied status.
  992. X */
  993. dologout(status)
  994. X    int status;
  995. X{
  996. X    if (logged_in) {
  997. X        (void) seteuid((uid_t)0);
  998. X        logwtmp(ttyline, "", "");
  999. X    }
  1000. X    /* beware of flushing buffers after a SIGPIPE */
  1001. X    _exit(status);
  1002. X}
  1003. X
  1004. myoob()
  1005. X{
  1006. X    char *cp;
  1007. X
  1008. X    /* only process if transfer occurring */
  1009. X    if (!transflag)
  1010. X        return;
  1011. X    cp = tmpline;
  1012. X    if (getline(cp, 7, stdin) == NULL) {
  1013. X        reply(221, "You could at least say goodbye.");
  1014. X        dologout(0);
  1015. X    }
  1016. X    upper(cp);
  1017. X    if (strcmp(cp, "ABOR\r\n"))
  1018. X        return;
  1019. X    tmpline[0] = '\0';
  1020. X    reply(426,"Transfer aborted. Data connection closed.");
  1021. X    reply(226,"Abort successful");
  1022. X    longjmp(urgcatch, 1);
  1023. X}
  1024. X
  1025. X/*
  1026. X * Note: The 530 reply codes could be 4xx codes, except nothing is
  1027. X * given in the state tables except 421 which implies an exit.  (RFC959)
  1028. X */
  1029. passive()
  1030. X{
  1031. X    int len;
  1032. X    struct sockaddr_in tmp;
  1033. X    register char *p, *a;
  1034. X
  1035. X    pdata = socket(AF_INET, SOCK_STREAM, 0);
  1036. X    if (pdata < 0) {
  1037. X        reply(530, "Can't open passive connection");
  1038. X        return;
  1039. X    }
  1040. X    tmp = ctrl_addr;
  1041. X    tmp.sin_port = 0;
  1042. X    (void) seteuid((uid_t)0);
  1043. X    if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) {
  1044. X        (void) seteuid((uid_t)pw->pw_uid);
  1045. X        (void) close(pdata);
  1046. X        pdata = -1;
  1047. X        reply(530, "Can't open passive connection");
  1048. X        return;
  1049. X    }
  1050. X    (void) seteuid((uid_t)pw->pw_uid);
  1051. X    len = sizeof(tmp);
  1052. X    if (getsockname(pdata, (struct sockaddr *) &tmp, &len) < 0) {
  1053. X        (void) close(pdata);
  1054. X        pdata = -1;
  1055. X        reply(530, "Can't open passive connection");
  1056. X        return;
  1057. X    }
  1058. X    if (listen(pdata, 1) < 0) {
  1059. X        (void) close(pdata);
  1060. X        pdata = -1;
  1061. X        reply(530, "Can't open passive connection");
  1062. X        return;
  1063. X    }
  1064. X    a = (char *) &tmp.sin_addr;
  1065. X    p = (char *) &tmp.sin_port;
  1066. X
  1067. X#define UC(b) (((int) b) & 0xff)
  1068. X
  1069. X    reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  1070. X        UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1071. X}
  1072. X
  1073. X/*
  1074. X * Generate unique name for file with basename "local".
  1075. X * The file named "local" is already known to exist.
  1076. X * Generates failure reply on error.
  1077. X */
  1078. char *
  1079. gunique(local)
  1080. X    char *local;
  1081. X{
  1082. X    static char new[MAXPATHLEN];
  1083. X    struct stat st;
  1084. X    char *cp = rindex(local, '/');
  1085. X    int d, count=0;
  1086. X
  1087. X    if (cp)
  1088. X        *cp = '\0';
  1089. X    d = stat(cp ? local : ".", &st);
  1090. X    if (cp)
  1091. X        *cp = '/';
  1092. X    if (d < 0) {
  1093. X        perror_reply(553, local);
  1094. X        return((char *) 0);
  1095. X    }
  1096. X    (void) strcpy(new, local);
  1097. X    cp = new + strlen(new);
  1098. X    *cp++ = '.';
  1099. X    for (count = 1; count < 100; count++) {
  1100. X        (void) sprintf(cp, "%d", count);
  1101. X        if (stat(new, &st) < 0)
  1102. X            return(new);
  1103. X    }
  1104. X    reply(452, "Unique file name cannot be created.");
  1105. X    return((char *) 0);
  1106. X}
  1107. X
  1108. X/*
  1109. X * Format and send reply containing system error number.
  1110. X */
  1111. perror_reply(code, string)
  1112. X    int code;
  1113. X    char *string;
  1114. X{
  1115. X
  1116. X    if (errno < sys_nerr)
  1117. X        reply(code, "%s: %s.", string, sys_errlist[errno]);
  1118. X    else
  1119. X        reply(code, "%s: unknown error %d.", string, errno);
  1120. X}
  1121. X
  1122. X#ifdef PERMS
  1123. int
  1124. Getdomainname(s, n)
  1125. char *s;
  1126. X{
  1127. X    FILE *f;
  1128. X    char buf[200], *p;
  1129. X    int i = 0;
  1130. X
  1131. X    f = fopen("/etc/resolv.conf", "r");
  1132. X    if(!f)
  1133. X        return 0;
  1134. X    while( fgets(buf, sizeof buf, f) ) {
  1135. X        p = buf;
  1136. X        while(*p==' ' || *p=='\t')
  1137. X            p++;
  1138. X        if( strncmp(p, "domain", 6))
  1139. X            continue;
  1140. X        p+= 6;
  1141. X        while(*p==' ' || *p=='\t')
  1142. X            p++;
  1143. X        while(*p!=' ' && *p!='\t' && *p!='\n' && *p!='\0' ) {
  1144. X            s[i++] = *p++;
  1145. X            if(i==n)
  1146. X                return 0;
  1147. X        }
  1148. X        s[i] = '\0';
  1149. X        return 1;
  1150. X    }
  1151. X}
  1152. X
  1153. checkuser(pwd)
  1154. struct passwd *pwd;
  1155. X{
  1156. X    char *grpnames[NGROUPS+1];
  1157. X    int ngrps, lp;
  1158. X    struct group *grp;
  1159. X    extern int permcheck();
  1160. X
  1161. X    setgrent();
  1162. X    ngrps = 0;
  1163. X    if(!(grp=getgrgid(pwd->pw_gid))) {
  1164. X        syslog(LOG_CRIT,
  1165. X            "cannot find group name for %d\n", pwd->pw_gid);
  1166. X        goto broken_groups;
  1167. X    }
  1168. X    grpnames[ngrps++] = strdup(grp->gr_name);
  1169. X    while( grp=getgrent() ) {
  1170. X        if(pwd->pw_gid == grp->gr_gid)
  1171. X            continue;
  1172. X        while(*grp->gr_mem) {
  1173. X            if( !strcmp(pwd->pw_name, *grp->gr_mem)) {
  1174. X                grpnames[ngrps++] = strdup(grp->gr_name);
  1175. X            }
  1176. X            grp->gr_mem++;
  1177. X        }
  1178. X    }
  1179. X    endgrent();
  1180. X    grpnames[ngrps] = NULL;
  1181. X    if( !permcheck(pw->pw_name, "ftp", grpnames, NULL) ) {
  1182. X        syslog(LOG_CRIT,
  1183. X            "%s:%s not permitted", "ftp", pw->pw_name);
  1184. X        return 1;
  1185. X    }
  1186. broken_groups:
  1187. X    return 0;
  1188. X}
  1189. X#endif
  1190. END_OF_FILE
  1191. if test 24225 -ne `wc -c <'in.ftpd/ftpd.c'`; then
  1192.     echo shar: \"'in.ftpd/ftpd.c'\" unpacked with wrong size!
  1193. fi
  1194. # end of 'in.ftpd/ftpd.c'
  1195. fi
  1196. echo shar: End of archive 3 \(of 3\).
  1197. cp /dev/null ark3isdone
  1198. MISSING=""
  1199. for I in 1 2 3 ; do
  1200.     if test ! -f ark${I}isdone ; then
  1201.     MISSING="${MISSING} ${I}"
  1202.     fi
  1203. done
  1204. if test "${MISSING}" = "" ; then
  1205.     echo You have unpacked all 3 archives.
  1206.     rm -f ark[1-9]isdone
  1207. else
  1208.     echo You still need to unpack the following archives:
  1209.     echo "        " ${MISSING}
  1210. fi
  1211. ##  End of shell archive.
  1212. exit 0
  1213.  
  1214.