home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / libexec / tftpd / tftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-12  |  12.0 KB  |  506 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)tftpd.c    5.13 (Berkeley) 2/26/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * Trivial file transfer protocol server.
  46.  *
  47.  * This version includes many modifications by Jim Guyton <guyton@rand-unix>
  48.  */
  49.  
  50. #include <sys/types.h>
  51. #include <sys/ioctl.h>
  52. #include <sys/stat.h>
  53. #include <signal.h>
  54. #include <fcntl.h>
  55.  
  56. #include <sys/socket.h>
  57. #include <netinet/in.h>
  58. #include <arpa/tftp.h>
  59. #include <netdb.h>
  60.  
  61. #include <setjmp.h>
  62. #include <syslog.h>
  63. #include <stdio.h>
  64. #include <errno.h>
  65. #include <ctype.h>
  66. #include <string.h>
  67. #include <stdlib.h>
  68.  
  69. #define    TIMEOUT        5
  70.  
  71. extern    int errno;
  72. struct    sockaddr_in sin = { AF_INET };
  73. int    peer;
  74. int    rexmtval = TIMEOUT;
  75. int    maxtimeout = 5*TIMEOUT;
  76.  
  77. #define    PKTSIZE    SEGSIZE+4
  78. char    buf[PKTSIZE];
  79. char    ackbuf[PKTSIZE];
  80. struct    sockaddr_in from;
  81. int    fromlen;
  82.  
  83. #define MAXARG    4
  84. char    *dirs[MAXARG+1];
  85.  
  86. main(ac, av)
  87.     char **av;
  88. {
  89.     register struct tftphdr *tp;
  90.     register int n = 0;
  91.     int on = 1;
  92.  
  93.     ac--; av++;
  94.     while (ac-- > 0 && n < MAXARG)
  95.         dirs[n++] = *av++;
  96.     openlog("tftpd", LOG_PID, LOG_DAEMON);
  97.     if (ioctl(0, FIONBIO, &on) < 0) {
  98.         syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
  99.         exit(1);
  100.     }
  101.     fromlen = sizeof (from);
  102.     n = recvfrom(0, buf, sizeof (buf), 0,
  103.         (struct sockaddr *)&from, &fromlen);
  104.     if (n < 0) {
  105.         syslog(LOG_ERR, "recvfrom: %m\n");
  106.         exit(1);
  107.     }
  108.     /*
  109.      * Now that we have read the message out of the UDP
  110.      * socket, we fork and exit.  Thus, inetd will go back
  111.      * to listening to the tftp port, and the next request
  112.      * to come in will start up a new instance of tftpd.
  113.      *
  114.      * We do this so that inetd can run tftpd in "wait" mode.
  115.      * The problem with tftpd running in "nowait" mode is that
  116.      * inetd may get one or more successful "selects" on the
  117.      * tftp port before we do our receive, so more than one
  118.      * instance of tftpd may be started up.  Worse, if tftpd
  119.      * break before doing the above "recvfrom", inetd would
  120.      * spawn endless instances, clogging the system.
  121.      */
  122.     {
  123.         int pid;
  124.         int i, j;
  125.  
  126.         for (i = 1; i < 20; i++) {
  127.             pid = fork();
  128.             if (pid < 0) {
  129.                 sleep(i);
  130.                 /*
  131.                  * flush out to most recently sent request.
  132.                  *
  133.                  * This may drop some request, but those
  134.                  * will be resent by the clients when
  135.                  * they timeout.  The positive effect of
  136.                  * this flush is to (try to) prevent more
  137.                  * than one tftpd being started up to service
  138.                  * a single request from a single client.
  139.                  */
  140.                 j = sizeof from;
  141.                 i = recvfrom(0, buf, sizeof (buf), 0,
  142.                     (struct sockaddr *)&from, &j);
  143.                 if (i > 0) {
  144.                     n = i;
  145.                     fromlen = j;
  146.                 }
  147.             } else {
  148.                 break;
  149.             }
  150.         }
  151.         if (pid < 0) {
  152.             syslog(LOG_ERR, "fork: %m\n");
  153.             exit(1);
  154.         } else if (pid != 0) {
  155.             exit(0);
  156.         }
  157.     }
  158.     from.sin_family = AF_INET;
  159.     alarm(0);
  160.     close(0);
  161.     close(1);
  162.     peer = socket(AF_INET, SOCK_DGRAM, 0);
  163.     if (peer < 0) {
  164.         syslog(LOG_ERR, "socket: %m\n");
  165.         exit(1);
  166.     }
  167.     if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  168.         syslog(LOG_ERR, "bind: %m\n");
  169.         exit(1);
  170.     }
  171.     if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
  172.         syslog(LOG_ERR, "connect: %m\n");
  173.         exit(1);
  174.     }
  175.     tp = (struct tftphdr *)buf;
  176.     tp->th_opcode = ntohs(tp->th_opcode);
  177.     if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
  178.         tftp(tp, n);
  179.     exit(1);
  180. }
  181.  
  182. int    validate_access();
  183. int    sendfile(), recvfile();
  184.  
  185. struct formats {
  186.     char    *f_mode;
  187.     int    (*f_validate)();
  188.     int    (*f_send)();
  189.     int    (*f_recv)();
  190.     int    f_convert;
  191. } formats[] = {
  192.     { "netascii",    validate_access,    sendfile,    recvfile, 1 },
  193.     { "octet",    validate_access,    sendfile,    recvfile, 0 },
  194. #ifdef notdef
  195.     { "mail",    validate_user,        sendmail,    recvmail, 1 },
  196. #endif
  197.     { 0 }
  198. };
  199.  
  200. /*
  201.  * Handle initial connection protocol.
  202.  */
  203. tftp(tp, size)
  204.     struct tftphdr *tp;
  205.     int size;
  206. {
  207.     register char *cp;
  208.     int first = 1, ecode;
  209.     register struct formats *pf;
  210.     char *filename, *mode;
  211.  
  212.     filename = cp = tp->th_stuff;
  213. again:
  214.     while (cp < buf + size) {
  215.         if (*cp == '\0')
  216.             break;
  217.         cp++;
  218.     }
  219.     if (*cp != '\0') {
  220.         nak(EBADOP);
  221.         exit(1);
  222.     }
  223.     if (first) {
  224.         mode = ++cp;
  225.         first = 0;
  226.         goto again;
  227.     }
  228.     for (cp = mode; *cp; cp++)
  229.         if (isupper(*cp))
  230.             *cp = tolower(*cp);
  231.     for (pf = formats; pf->f_mode; pf++)
  232.         if (strcmp(pf->f_mode, mode) == 0)
  233.             break;
  234.     if (pf->f_mode == 0) {
  235.         nak(EBADOP);
  236.         exit(1);
  237.     }
  238.     ecode = (*pf->f_validate)(filename, tp->th_opcode);
  239.     if (ecode) {
  240.         nak(ecode);
  241.         exit(1);
  242.     }
  243.     if (tp->th_opcode == WRQ)
  244.         (*pf->f_recv)(pf);
  245.     else
  246.         (*pf->f_send)(pf);
  247.     exit(0);
  248. }
  249.  
  250.  
  251. FILE *file;
  252.  
  253. /*
  254.  * Validate file access.  Since we
  255.  * have no uid or gid, for now require
  256.  * file to exist and be publicly
  257.  * readable/writable.
  258.  * If we were invoked with arguments
  259.  * from inetd then the file must also be
  260.  * in one of the given directory prefixes.
  261.  * Note also, full path name must be
  262.  * given as we have no login directory.
  263.  */
  264. validate_access(filename, mode)
  265.     char *filename;
  266.     int mode;
  267. {
  268.     struct stat stbuf;
  269.     int    fd;
  270.     char *cp, **dirp;
  271.  
  272.     if (*filename != '/')
  273.         return (EACCESS);
  274.     /*
  275.      * prevent tricksters from getting around the directory restrictions
  276.      */
  277.     for (cp = filename + 1; *cp; cp++)
  278.         if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0)
  279.             return(EACCESS);
  280.     for (dirp = dirs; *dirp; dirp++)
  281.         if (strncmp(filename, *dirp, strlen(*dirp)) == 0)
  282.             break;
  283.     if (*dirp==0 && dirp!=dirs)
  284.         return (EACCESS);
  285.     if (stat(filename, &stbuf) < 0)
  286.         return (errno == ENOENT ? ENOTFOUND : EACCESS);
  287.     if (mode == RRQ) {
  288.         if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
  289.             return (EACCESS);
  290.     } else {
  291.         if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
  292.             return (EACCESS);
  293.     }
  294.     fd = open(filename, mode == RRQ ? 0 : 1);
  295.     if (fd < 0)
  296.         return (errno + 100);
  297.     file = fdopen(fd, (mode == RRQ)? "r":"w");
  298.     if (file == NULL) {
  299.         return errno+100;
  300.     }
  301.     return (0);
  302. }
  303.  
  304. int    timeout;
  305. jmp_buf    timeoutbuf;
  306.  
  307. void
  308. timer()
  309. {
  310.  
  311.     timeout += rexmtval;
  312.     if (timeout >= maxtimeout)
  313.         exit(1);
  314.     longjmp(timeoutbuf, 1);
  315. }
  316.  
  317. /*
  318.  * Send the requested file.
  319.  */
  320. sendfile(pf)
  321.     struct formats *pf;
  322. {
  323.     struct tftphdr *dp, *r_init();
  324.     register struct tftphdr *ap;    /* ack packet */
  325.     register int block = 1, size, n;
  326.  
  327.     signal(SIGALRM, timer);
  328.     dp = r_init();
  329.     ap = (struct tftphdr *)ackbuf;
  330.     do {
  331.         size = readit(file, &dp, pf->f_convert);
  332.         if (size < 0) {
  333.             nak(errno + 100);
  334.             goto abort;
  335.         }
  336.         dp->th_opcode = htons((u_short)DATA);
  337.         dp->th_block = htons((u_short)block);
  338.         timeout = 0;
  339.         (void) setjmp(timeoutbuf);
  340.  
  341. send_data:
  342.         if (send(peer, dp, size + 4, 0) != size + 4) {
  343.             syslog(LOG_ERR, "tftpd: write: %m\n");
  344.             goto abort;
  345.         }
  346.         read_ahead(file, pf->f_convert);
  347.         for ( ; ; ) {
  348.             alarm(rexmtval);        /* read the ack */
  349.             n = recv(peer, ackbuf, sizeof (ackbuf), 0);
  350.             alarm(0);
  351.             if (n < 0) {
  352.                 syslog(LOG_ERR, "tftpd: read: %m\n");
  353.                 goto abort;
  354.             }
  355.             ap->th_opcode = ntohs((u_short)ap->th_opcode);
  356.             ap->th_block = ntohs((u_short)ap->th_block);
  357.  
  358.             if (ap->th_opcode == ERROR)
  359.                 goto abort;
  360.             
  361.             if (ap->th_opcode == ACK) {
  362.                 if (ap->th_block == block) {
  363.                     break;
  364.                 }
  365.                 /* Re-synchronize with the other side */
  366.                 (void) synchnet(peer);
  367.                 if (ap->th_block == (block -1)) {
  368.                     goto send_data;
  369.                 }
  370.             }
  371.  
  372.         }
  373.         block++;
  374.     } while (size == SEGSIZE);
  375. abort:
  376.     (void) fclose(file);
  377. }
  378.  
  379. void
  380. justquit()
  381. {
  382.     exit(0);
  383. }
  384.  
  385.  
  386. /*
  387.  * Receive a file.
  388.  */
  389. recvfile(pf)
  390.     struct formats *pf;
  391. {
  392.     struct tftphdr *dp, *w_init();
  393.     register struct tftphdr *ap;    /* ack buffer */
  394.     register int block = 0, n, size;
  395.  
  396.     signal(SIGALRM, timer);
  397.     dp = w_init();
  398.     ap = (struct tftphdr *)ackbuf;
  399.     do {
  400.         timeout = 0;
  401.         ap->th_opcode = htons((u_short)ACK);
  402.         ap->th_block = htons((u_short)block);
  403.         block++;
  404.         (void) setjmp(timeoutbuf);
  405. send_ack:
  406.         if (send(peer, ackbuf, 4, 0) != 4) {
  407.             syslog(LOG_ERR, "tftpd: write: %m\n");
  408.             goto abort;
  409.         }
  410.         write_behind(file, pf->f_convert);
  411.         for ( ; ; ) {
  412.             alarm(rexmtval);
  413.             n = recv(peer, dp, PKTSIZE, 0);
  414.             alarm(0);
  415.             if (n < 0) {            /* really? */
  416.                 syslog(LOG_ERR, "tftpd: read: %m\n");
  417.                 goto abort;
  418.             }
  419.             dp->th_opcode = ntohs((u_short)dp->th_opcode);
  420.             dp->th_block = ntohs((u_short)dp->th_block);
  421.             if (dp->th_opcode == ERROR)
  422.                 goto abort;
  423.             if (dp->th_opcode == DATA) {
  424.                 if (dp->th_block == block) {
  425.                     break;   /* normal */
  426.                 }
  427.                 /* Re-synchronize with the other side */
  428.                 (void) synchnet(peer);
  429.                 if (dp->th_block == (block-1))
  430.                     goto send_ack;          /* rexmit */
  431.             }
  432.         }
  433.         /*  size = write(file, dp->th_data, n - 4); */
  434.         size = writeit(file, &dp, n - 4, pf->f_convert);
  435.         if (size != (n-4)) {                    /* ahem */
  436.             if (size < 0) nak(errno + 100);
  437.             else nak(ENOSPACE);
  438.             goto abort;
  439.         }
  440.     } while (size == SEGSIZE);
  441.     write_behind(file, pf->f_convert);
  442.     (void) fclose(file);            /* close data file */
  443.  
  444.     ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
  445.     ap->th_block = htons((u_short)(block));
  446.     (void) send(peer, ackbuf, 4, 0);
  447.  
  448.     signal(SIGALRM, justquit);      /* just quit on timeout */
  449.     alarm(rexmtval);
  450.     n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
  451.     alarm(0);
  452.     if (n >= 4 &&                   /* if read some data */
  453.         dp->th_opcode == DATA &&    /* and got a data block */
  454.         block == dp->th_block) {    /* then my last ack was lost */
  455.         (void) send(peer, ackbuf, 4, 0);     /* resend final ack */
  456.     }
  457. abort:
  458.     return;
  459. }
  460.  
  461. struct errmsg {
  462.     int    e_code;
  463.     char    *e_msg;
  464. } errmsgs[] = {
  465.     { EUNDEF,    "Undefined error code" },
  466.     { ENOTFOUND,    "File not found" },
  467.     { EACCESS,    "Access violation" },
  468.     { ENOSPACE,    "Disk full or allocation exceeded" },
  469.     { EBADOP,    "Illegal TFTP operation" },
  470.     { EBADID,    "Unknown transfer ID" },
  471.     { EEXISTS,    "File already exists" },
  472.     { ENOUSER,    "No such user" },
  473.     { -1,        0 }
  474. };
  475.  
  476. /*
  477.  * Send a nak packet (error message).
  478.  * Error code passed in is one of the
  479.  * standard TFTP codes, or a UNIX errno
  480.  * offset by 100.
  481.  */
  482. nak(error)
  483.     int error;
  484. {
  485.     register struct tftphdr *tp;
  486.     int length;
  487.     register struct errmsg *pe;
  488.  
  489.     tp = (struct tftphdr *)buf;
  490.     tp->th_opcode = htons((u_short)ERROR);
  491.     tp->th_code = htons((u_short)error);
  492.     for (pe = errmsgs; pe->e_code >= 0; pe++)
  493.         if (pe->e_code == error)
  494.             break;
  495.     if (pe->e_code < 0) {
  496.         pe->e_msg = strerror(error - 100);
  497.         tp->th_code = EUNDEF;   /* set 'undef' errorcode */
  498.     }
  499.     strcpy(tp->th_msg, pe->e_msg);
  500.     length = strlen(pe->e_msg);
  501.     tp->th_msg[length] = '\0';
  502.     length += 5;
  503.     if (send(peer, buf, length, 0) != length)
  504.         syslog(LOG_ERR, "nak: %m\n");
  505. }
  506.