home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / FTP / c / FTPSERV < prev    next >
Text File  |  1995-01-24  |  21KB  |  845 lines

  1. /* FTP Server state machine - see RFC 959 */
  2.  
  3. #define LINELEN         128     /* Length of command buffer */
  4.  
  5. #include <stdarg.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <time.h>
  11. #include "global.h"
  12. #include "mbuf.h"
  13. #include "netuser.h"
  14. #include "timer.h"
  15. #include "tcp.h"
  16. #include "ftp.h"
  17. #include "misc.h"
  18. #include "arc.h"
  19. #include "session.h"
  20.  
  21. static void ftpscs(struct tcb *, char, char);
  22. static void ftpscr(struct tcb *, int16);
  23. static void ftpcommand(struct ftp *);
  24. static int  pport(struct socket *, char *);
  25. static void ftplogin(struct ftp *, char *);
  26. int do_banner(char *file, char *pfx, struct tcb *c);
  27.  
  28. extern char bnrftpanon[];
  29. extern char bnrftppriv[];
  30.  
  31. /* Command table */
  32. static char *commands[] = {
  33.   "user",
  34. #define USER_CMD        0
  35.   "acct",
  36. #define ACCT_CMD        1
  37.   "pass",
  38. #define PASS_CMD        2
  39.   "type",
  40. #define TYPE_CMD        3
  41.   "list",
  42. #define LIST_CMD        4
  43.   "cwd",
  44. #define CWD_CMD         5
  45.   "dele",
  46. #define DELE_CMD        6
  47.   "name",
  48. #define NAME_CMD        7
  49.   "quit",
  50. #define QUIT_CMD        8
  51.   "retr",
  52. #define RETR_CMD        9
  53.   "stor",
  54. #define STOR_CMD        10
  55.   "port",
  56. #define PORT_CMD        11
  57.   "nlst",
  58. #define NLST_CMD        12
  59.   "pwd",
  60. #define PWD_CMD         13
  61.   "xpwd",                 /* For compatibility with 4.2BSD */
  62. #define XPWD_CMD        14
  63.   "mkd ",
  64. #define MKD_CMD         15
  65.   "xmkd",                 /* For compatibility with 4.2BSD */
  66. #define XMKD_CMD        16
  67.   "xrmd",                 /* For compatibility with 4.2BSD */
  68. #define XRMD_CMD        17
  69.   "rmd ",
  70. #define RMD_CMD         18
  71.   "stru",
  72. #define STRU_CMD        19
  73.   "mode",
  74. #define MODE_CMD        20
  75.   "rest",
  76. #define REST_CMD        21
  77.   NULLCHAR
  78. };
  79.  
  80. /* Response messages */
  81. static char banner[]   = "220 %s FTP server ready at %s\r\n";
  82. static char badcmd[]   = "500 Unknown command\r\n";
  83. static char unsupp[]   = "500 Unsupported command or option\r\n";
  84. static char givepass[] = "331 Enter PASS command\r\n";
  85. static char logged[]   = "230 Logged in\r\n";
  86. static char loggeda[]  = "230 Logged in as anonymous, restrictions apply\r\n";
  87. static char typeiok[]  = "200 Image type OK\r\n";
  88. static char typeaok[]  = "200 Ascii type OK\r\n";
  89. static char only8[]    = "501 Only logical bytesize 8 supported\r\n";
  90. static char deleok[]   = "250 File deleted\r\n";
  91. static char mkdok[]    = "200 MKD ok\r\n";
  92. static char delefail[] = "550 Delete failed\r\n";
  93. static char pwdmsg[]   = "257 \"%s\" is current directory\r\n";
  94. static char badtype[]  = "501 Unknown type \"%s\"\r\n";
  95. static char badport[]  = "501 Bad port syntax\r\n";
  96. static char unimp[]    = "502 Command not yet implemented\r\n";
  97. static char bye[]      = "221 Goodbye!\r\n";
  98. static char nodir[]    = "553 Can't read directory \"%s\"\r\n";
  99. static char cantopen[] = "550 Can't read file \"%s\"\r\n";
  100. static char sending[]  = "150 Opening data connection for %s %s\r\n";
  101. static char cantmake[] = "553 Can't create \"%s\"\r\n";
  102. static char portok[]   = "200 Port command okay\r\n";
  103. static char rxok[]     = "226 File received OK\r\n";
  104. static char txok[]     = "226 File sent OK\r\n";
  105. static char noperm[]   = "550 Permission denied\r\n";
  106. static char noconn[]   = "425 Data connection reset\r\n";
  107. static char notlog[]   = "530 Please log in with USER and PASS\r\n";
  108. static char okay[]     = "200 Ok\r\n";
  109. static char restart[]  = "350 Restarting at %lu\r\n";
  110.  
  111. static struct tcb *ftp_tcb;
  112.  
  113. /* Start up FTP service */
  114. int ftp1(int argc, char **argv)
  115. {
  116.   struct socket lsocket;
  117.  
  118.   lsocket.address = ip_addr;
  119.   if(argc < 2)
  120.     lsocket.port = FTP_PORT;
  121.   else
  122.       lsocket.port = atoi(argv[1]);
  123.  
  124.   ftp_tcb = open_tcp(&lsocket, NULLSOCK, TCP_SERVER, 0, (void(*)())ftpscr, NULLVFP, (void(*)())ftpscs, 0, (char *) NULL);
  125.   return(0);
  126. }
  127. /* Shut down FTP server */
  128. int ftp0(void)
  129. {
  130.   if(ftp_tcb != NULLTCB)
  131.     close_tcp(ftp_tcb);
  132.   return(0);
  133. }
  134.  
  135.  
  136. /* FTP Server Control channel State change upcall handler */
  137. static void ftpscs(struct tcb *tcb, char old, char new)
  138. {
  139.   extern char hostname[];
  140.   struct ftp *ftp;
  141.   time_t t;
  142.   char *cp,*cp1;
  143.  
  144.   old = old;
  145.  
  146.   switch(new)
  147.   {
  148.     /* Setting QUICKSTART piggybacks the server's banner on the SYN/ACK segment;
  149.      * leaving it unset waits for the three-way handshake to complete before
  150.      * sending the banner. Piggybacking unfortunately breaks some old TCPs,
  151.      * so its use is not (yet) recommended.
  152.     */
  153. #ifdef  QUICKSTART
  154.   case SYN_RECEIVED:
  155. #else
  156.   case ESTABLISHED:
  157. #endif
  158.     if((ftp = ftp_create(LINELEN)) == NULLFTP)
  159.     {
  160.       /* No space, kill connection */
  161.       close_tcp(tcb);
  162.       return;
  163.     }
  164.     ftp->control = tcb;             /* Downward link */
  165.     tcb->user = (char *)ftp;        /* Upward link */
  166.  
  167.     /* Set default data port */
  168.     ftp->port.address = tcb->conn.remote.address;
  169.     ftp->port.port = FTPD_PORT;
  170.  
  171.     /* Note current directory */
  172.  
  173.     set_server_vars("ftp",tcb);
  174.     log_event(tcb,"open FTP");
  175.     time(&t);
  176.     cp = ctime(&t);
  177.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  178.       *cp1 = '\0';
  179.     cwprintf(NULL, "%s : Incoming FTP session from %s\r\n",cp,psocket(&tcb->conn.remote));
  180.     tprintf(ftp->control,banner,hostname,cp);
  181.     break;
  182.   case CLOSE_WAIT:
  183.     close_tcp(tcb);
  184.     break;
  185.   case CLOSED:
  186.     log_event(tcb,"close FTP");
  187.     if((ftp = (struct ftp *)tcb->user) != NULLFTP)
  188.       ftp_delete(ftp);
  189.     /* Check if server is being shut down */
  190.     if(tcb == ftp_tcb)
  191.       ftp_tcb = NULLTCB;
  192.     del_tcp(tcb);
  193.     break;
  194.   }
  195. }
  196.  
  197. /* FTP Server Control channel Receiver upcall handler */
  198. static void ftpscr(struct tcb *tcb, int16 cnt)
  199. {
  200.   register struct ftp *ftp;
  201.   char c;
  202.   struct mbuf *bp;
  203.  
  204.   cnt = cnt;
  205.  
  206.   if((ftp = (struct ftp *)tcb->user) == NULLFTP){
  207.     /* Unknown connection, just kill it */
  208.     close_tcp(tcb);
  209.     return;
  210.   }
  211.   switch(ftp->state)
  212.   {
  213.   case COMMAND_STATE:
  214.     /* Assemble an input line in the session buffer. Return if incomplete */
  215.     recv_tcp(tcb,&bp,0);
  216.     while(pullone(&bp,&c) == 1)
  217.     {
  218.       switch(c)
  219.       {
  220.       case '\r':      /* Strip cr's */
  221.         continue;
  222.       case '\n':      /* Complete line; process it */
  223.         ftp->buf[ftp->cnt] = '\0';
  224.         ftpcommand(ftp);
  225.         ftp->cnt = 0;
  226.         break;
  227.       default:        /* Assemble line */
  228.         if(ftp->cnt != LINELEN-1)
  229.           ftp->buf[ftp->cnt++] = c;
  230.         break;
  231.       }
  232.     }
  233.     /* else no linefeed present yet to terminate command */
  234.     break;
  235.   case SENDING_FILE_STATE:
  236.   case SENDING_DATA_STATE:
  237.   case RECEIVING_STATE:
  238.     /* Leave commands pending on receive queue until
  239.                      * present command is done
  240.                      */
  241.     break;
  242.   }
  243. }
  244.  
  245. /* FTP server data channel connection state change upcall handler */
  246. void ftpsds(struct tcb *tcb, char old, char new)
  247. {
  248.   register struct ftp *ftp;
  249.  
  250.   if((ftp = (struct ftp *)tcb->user) == NULLFTP)
  251.   {
  252.     /* Unknown connection. Kill it */
  253.     del_tcp(tcb);
  254.   }
  255.   else if((old == FINWAIT1 || old == CLOSING) && (ftp->state == SENDING_FILE_STATE || ftp->state == SENDING_DATA_STATE)){
  256.     /* We've received an ack of our FIN while sending; we're done */
  257.     ftp->state = COMMAND_STATE;
  258.     tprintf(ftp->control,txok);
  259.     /* Kick command parser if something is waiting */
  260.     if(ftp->control->rcvcnt != 0)
  261.       ftpscr(ftp->control,ftp->control->rcvcnt);
  262.   }
  263.   else if(ftp->state == RECEIVING_STATE && new == CLOSE_WAIT)
  264.   {
  265.     /* FIN received on incoming file */
  266.     close_tcp(tcb);
  267.     if(ftp->fp != stdout)
  268.       fclose(ftp->fp);
  269.     ftp->fp = NULLFILE;
  270.     ftp->state = COMMAND_STATE;
  271.     tprintf(ftp->control,rxok);
  272.     /* Kick command parser if something is waiting */
  273.     if(ftp->control->rcvcnt != 0)
  274.       ftpscr(ftp->control,ftp->control->rcvcnt);
  275.   }
  276.   else if(new == CLOSED)
  277.   {
  278.     if(tcb->reason != NORMAL)
  279.     {
  280.       /* Data connection was reset, complain about it */
  281.       tprintf(ftp->control,noconn);
  282.       /* And clean up */
  283.       if(ftp->fp != NULLFILE && ftp->fp != stdout)
  284.         fclose(ftp->fp);
  285.       ftp->fp = NULLFILE;
  286.       ftp->state = COMMAND_STATE;
  287.       /* Kick command parser if something is waiting */
  288.       if(ftp->control->rcvcnt != 0)
  289.         ftpscr(ftp->control,ftp->control->rcvcnt);
  290.     }
  291.     /* Clear only if another transfer hasn't a