home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / FTPSERV.C < prev    next >
Text File  |  1994-06-15  |  28KB  |  903 lines

  1. /* Internet FTP Server server machine - see RFC 959
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <ctype.h>
  5. #include <time.h>
  6. #ifdef  __TURBOC__
  7. #include <io.h>
  8. #include <dir.h>
  9. #endif
  10. #ifdef LINUX
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #endif
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "socket.h"
  17. #include "ftp.h"
  18. #include "ftpserv.h"
  19. #include "proc.h"
  20. #include "dirutil.h"
  21. #include "files.h"
  22. #include "commands.h"
  23. #include "config.h"
  24. #include "cmdparse.h"
  25. #include "mailutil.h"
  26. #ifdef  LZW
  27. #include "lzw.h"
  28. #endif
  29.   
  30. static void ftpserv __ARGS((int s,void *unused,void *p));
  31. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  32. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  33. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  34. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  35. static void sendmsgfile __ARGS((int s,int num,char *buf,int size,FILE *fp));
  36. int doftptdisc __ARGS((int argc, char *argv[], void *p));
  37.   
  38. #ifdef FTPSERVER
  39.   
  40. extern char System[];
  41. int FtpUsers;
  42.   
  43. /* Command table */
  44. static char *commands[] = {
  45.     "user",
  46.     "acct",
  47.     "pass",
  48.     "type",
  49.     "list",
  50.     "cwd",
  51.     "dele",
  52.     "name",
  53.     "quit",
  54.     "retr",
  55.     "stor",
  56.     "port",
  57.     "nlst",
  58.     "pwd",
  59.     "xpwd",                 /* For compatibility with 4.2BSD */
  60.     "mkd ",
  61.     "xmkd",                 /* For compatibility with 4.2BSD */
  62.     "xrmd",                 /* For compatibility with 4.2BSD */
  63.     "rmd ",
  64.     "stru",
  65.     "mode",
  66.     "rsme",                 /* Added by IW0CNB, for resuming interrupted trasnfers */
  67.     "rput",
  68.     "noop",                 /* For OS/2 compatibility   kf5mg*/
  69.     "syst",
  70. #ifdef LZW
  71.     "xlzw",                 /* LZW FTP Compression      kf5mg*/
  72. #endif
  73.     NULLCHAR
  74. };
  75.   
  76. /* Response messages */
  77. static char banner[] = "220- %s, JNOS FTP version %s\n";
  78. static char banner1[] = "220  Ready on %s";
  79. static char badcmd[] = "500 Unknown command\n";
  80. static char binwarn[] = "100 Warning: type is ASCII and %s appears to be binary\n";
  81. static char unsupp[] = "500 Unsupported command or option\n";
  82. static char AnonymousLogin[] = "331- Anonymous login OK. Please give e-mail address as password!\n";
  83. static char givepass[] = "331 Enter PASS command\n";
  84. /* static char challenge[] = "399 PASS challenge : %016lx\r\n"; */
  85. static char logged[] = "230 Logged in\n";
  86. static char loggeda[] = "230 Logged in as anonymous, restrictions apply\n";
  87. static char typeok[] = "200 Type %s OK\n";
  88. static char only8[] = "501 Only logical bytesize 8 supported\n";
  89. static char deleok[] = "250 File deleted\n";
  90. static char mkdok[] = "200 MKD ok\n";
  91. static char delefail[] = "550 Delete failed: %s\n";
  92. static char pwdmsg[] = "257 \"%s\" is current directory\n";
  93. static char badtype[] = "501 Unknown type \"%s\"\n";
  94. static char badport[] = "501 Bad port syntax\n";
  95. static char unimp[] = "502 Command not yet implemented\n";
  96. static char bye[] = "221 Goodbye!\n";
  97. static char nodir[] = "553 Can't read directory \"%s\": %s\n";
  98. static char cantopen[] = "550 Can't read file \"%s\": %s\n";
  99. static char sending[] = "150 Opening data connection for %s %s %s\n"; /*N1BEE*/
  100. static char cantmake[] = "553 Can't create \"%s\": %s\n";
  101. static char writerr[] = "552 Write error: %s\n";
  102. static char portok[] = "200 Port command okay\n";
  103. static char rxok[] = "226 File received OK\n";
  104. static char txok[] = "226 File sent OK\n";
  105. static char noperm[] = "550 Permission denied\n";
  106. static char noconn[] = "425 Data connection reset\n";
  107. static char badcheck[] = "425 Bad checksum\n";
  108. static char lowmem[] = "421 System overloaded, try again later\n";
  109. static char notlog[] = "530 Please log in with USER and PASS\n";
  110. static char userfirst[] = "503 Login with USER first.\n";
  111. static char okay[] = "200 Ok\n";
  112. static char syst[] = "215 %s Type: L8 Version: %s\n";
  113.   
  114. #ifdef  LZW
  115. static char LZWOk[] = "299 %d %d LZW OK\n";
  116. extern int Ftpslzw;
  117. extern int Ftpclzw;
  118. #endif
  119.   
  120. int32 Ftptdiscinit;
  121.   
  122. /* Set ftp redundancy timer */
  123. int
  124. doftptdisc(argc,argv,p)
  125. int argc;
  126. char *argv[];
  127. void *p;
  128. {
  129.     return setlong(&Ftptdiscinit,"Ftp redundancy timer (sec)",argc,argv);
  130. }
  131.   
  132. /* Start up FTP service */
  133. int
  134. ftpstart(argc,argv,p)
  135. int argc;
  136. char *argv[];
  137. void *p;
  138. {
  139.     int16 port;
  140.   
  141.     if(argc < 2)
  142.         port = IPPORT_FTP;
  143.     else
  144.         port = atoi(argv[1]);
  145. #ifdef LZW
  146.     /* Both the Server and Client will default to trying to  */
  147.     /* use lzw compressiom.                                  */
  148.     Ftpslzw = 1;
  149.     Ftpclzw = 1;
  150. #endif
  151.   
  152.     return start_tcp(port,"FTP Server",ftpserv,2048);
  153. }
  154.   
  155. static void sendmsgfile(int s,int num,char *buf,int size,FILE *fp) {
  156.   
  157.     while(fgets(buf,size,fp)) {
  158.         rip(buf);
  159.         usprintf(s,"%d- %s\n",num,buf);
  160.     }
  161. }
  162.   
  163. static void
  164. ftpserv(s,unused,p)
  165. int s;  /* Socket with user connection */
  166. void *unused;
  167. void *p;
  168. {
  169.     struct ftpserv ftp;
  170.     char **cmdp,buf[512],*arg,*cp,*file,*mode;
  171.     long t;
  172.     int cnt,i;
  173.     struct sockaddr_in socket;
  174.     FILE *fp,*fpm;
  175.   
  176.     sockmode(s,SOCK_ASCII);
  177.     memset((char *)&ftp,0,sizeof(ftp));     /* Start with clear slate */
  178.     ftp.data = -1;
  179.   
  180.     sockowner(s,Curproc);           /* We own it now */
  181.     ftp.control = s;
  182.     /* Set default data port */
  183.     i = SOCKSIZE;
  184.     getpeername(s,(char *)&socket,&i);
  185.     socket.sin_port = IPPORT_FTPD;
  186.     ASSIGN(ftp.port,socket);
  187. #ifdef LZW
  188.     /* Socket assumes that lzw is off for socket. */
  189.     ftp.uselzw = 0;
  190. #endif
  191.   
  192.     log(s,"open FTP");
  193.     FtpUsers++;
  194.   
  195.     /* now go say 'hello' */
  196.     usprintf(s,banner,Hostname,Version);
  197.     if((fp = fopen(Ftpmotd,"r")) != NULL) {
  198.         while(fgets(buf,128,fp)) {
  199.             rip(buf);
  200.             usprintf(s,"220- %s\n",buf);
  201.         }
  202.         fclose(fp);
  203.     }
  204.     time(&t);
  205.     cp = ctime(&t);
  206.     usprintf(s,banner1,cp);
  207.   
  208.     loop:
  209.     /* Time-out after some inactivity time - WG7J */
  210.     alarm((long)(Ftptdiscinit*1000L));
  211.     if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  212.         /* He closed on us */
  213.         goto finish;
  214.     }
  215.     alarm(0L);
  216.   
  217.     if(cnt == 0){
  218.         /* Can't be a legal FTP command */
  219.         usputs(ftp.control,badcmd);
  220.         goto loop;
  221.     }
  222.     rip(buf);
  223.     /* Translate first word to lower case */
  224.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  225.         *cp = tolower(*cp);
  226.     /* Find command in table; if not present, return syntax error */
  227.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  228.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  229.             break;
  230.     if(*cmdp == NULLCHAR){
  231.         usputs(ftp.control,badcmd);
  232.         goto loop;
  233.     }
  234.     /* Allow only USER, PASS and QUIT before logging in */
  235.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  236.         switch(cmdp-commands){
  237.             case USER_CMD:
  238.             case PASS_CMD:
  239.             case QUIT_CMD:
  240.                 break;
  241.             default:
  242.                 usputs(ftp.control,notlog);
  243.                 goto loop;
  244.         }
  245.     }
  246.     arg = &buf[strlen(*cmdp)];
  247.     while(*arg == ' ')
  248.         arg++;
  249.   
  250.     /* Execute specific command */
  251.     switch(cmdp-commands){
  252. #ifdef LZW
  253.         case LZW_CMD:
  254.             if(!Ftpslzw) {
  255.             /* if the server doens't want to use LZW compression, issue
  256.              * the bad command message.
  257.              */
  258.                 usputs(ftp.control,badcmd);
  259.                 ftp.uselzw  = 0;
  260.             } else {
  261.             /* Get bits and mode from clients XLZW request. */
  262.                 ftp.lzwmode = ftp.lzwbits = 0;
  263.                 sscanf(arg,"%d %d",&ftp.lzwbits,&ftp.lzwmode);
  264.                 if(!((ftp.lzwmode == 0 || ftp.lzwmode == 1)
  265.                 && (ftp.lzwbits > 8 && ftp.lzwbits < 17))) {
  266.                 /* bad args... DON'T use LZW and tell the client. */
  267.                     ftp.lzwmode = LZWCOMPACT;
  268.                     ftp.lzwbits = LZWBITS;
  269.                     usputs(ftp.control,badcmd);
  270.                     ftp.uselzw  = 0;
  271.                 } else {
  272.                 /* Tell the client that the command was accepted.    */
  273.                     usprintf(ftp.control,LZWOk,ftp.lzwbits,ftp.lzwmode);
  274.                 /* And set the uselzw flag on the FTP socket struct. */
  275.                     ftp.uselzw  = 1;
  276.                 }
  277.             }
  278.             break;
  279. #endif /* LZW */
  280.         case USER_CMD:
  281.             free(ftp.username);
  282.             ftp.username = strdup(arg);
  283.             free(ftp.cd);   /* In case another 'user' command is issued - WG7J */
  284.             free(ftp.path);
  285.             ftp.cd = NULL;
  286.             ftp.path = NULL;
  287.         /* See if this would be an anonymous login */
  288.         {
  289.             int anony = 0;
  290.             char *path;
  291.   
  292.             path = mallocw(200);
  293.             userlogin(ftp.username,NULL,&path,200,&anony,"ftpdef");
  294.             if(anony)
  295.                 usputs(ftp.control,AnonymousLogin);
  296.             free(path);
  297.         }
  298.             usputs(ftp.control,givepass);
  299.             break;
  300.         case TYPE_CMD:
  301.         switch(arg[0]){
  302.             case 'A':
  303.             case 'a':       /* Ascii */
  304.                 ftp.type = ASCII_TYPE;
  305.                 usprintf(ftp.control,typeok,arg);
  306.                 break;
  307.             case 'l':
  308.             case 'L':
  309.                 while(*arg != ' ' && *arg != '\0')
  310.                     arg++;
  311.                 if(*arg == '\0' || *++arg != '8'){
  312.                     usputs(ftp.control,only8);
  313.                     break;
  314.                 }
  315.                 ftp.type = LOGICAL_TYPE;
  316.                 ftp.logbsize = 8;
  317.                 usprintf(ftp.control,typeok,arg);
  318.                 break;
  319.             case 'B':
  320.             case 'b':       /* Binary */
  321.             case 'I':
  322.             case 'i':       /* Image */
  323.                 ftp.type = IMAGE_TYPE;
  324.                 usprintf(ftp.control,typeok,arg);
  325.                 break;
  326.             default:        /* Invalid */
  327.                 usprintf(ftp.control,badtype,arg);
  328.                 break;
  329.         }
  330.             break;
  331.         case QUIT_CMD:
  332.             usputs(ftp.control,bye);
  333.             goto finish;
  334.         case RETR_CMD:
  335.         case RSME_CMD:
  336.             file = pathname(ftp.cd,arg);
  337.         switch(ftp.type){
  338.             case IMAGE_TYPE:
  339.             case LOGICAL_TYPE:
  340.                 mode = READ_BINARY;
  341.                 break;
  342.             case ASCII_TYPE:
  343.                 mode = READ_TEXT;
  344.                 break;
  345.         }
  346.             if(!permcheck(ftp.path,RETR_CMD,file)){
  347.                 usputs(ftp.control,noperm);
  348.             } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  349.                 usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  350.             } else {
  351.                 if((cmdp-commands) == RSME_CMD) {
  352.                     log(ftp.control,"RSME %s",file);
  353.                     if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  354.                         usprintf(ftp.control,binwarn,file);
  355.                     }
  356.                     sendit(&ftp,"RSME",file);
  357.                 } else {
  358.                     log(ftp.control,"RETR %s",file);
  359.                     if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  360.                         usprintf(ftp.control,binwarn,file);
  361.                     }
  362.                     sendit(&ftp,"RETR",file);
  363.                 }
  364.             }
  365.             free(file);
  366.             break;
  367.         case STOR_CMD:
  368.         case RPUT_CMD:
  369.             file = pathname(ftp.cd,arg);
  370.         switch(ftp.type){
  371.             case IMAGE_TYPE:
  372.             case LOGICAL_TYPE:
  373.                 if(cmdp-commands == RPUT_CMD)
  374.                     mode = APPEND_BINARY;
  375.                 else
  376.                     mode = WRITE_BINARY;
  377.                 break;
  378.             case ASCII_TYPE:
  379.                 if(cmdp-commands == RPUT_CMD)
  380.                     mode = APPEND_TEXT;
  381.                 else
  382.                     mode = WRITE_TEXT;
  383.                 break;
  384.         }
  385.             if(cmdp-commands == RPUT_CMD){
  386.                 if(!permcheck(ftp.path,RPUT_CMD,file)){
  387.                     usputs(ftp.control,noperm);
  388.                 } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  389.                     usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  390.                 } else {
  391.                     log(ftp.control,"RPUT %s",file);
  392.                     recvit(&ftp,"RPUT",file);
  393.                 }
  394.             } else {
  395.                 if(!permcheck(ftp.path,STOR_CMD,file)){
  396.                     usputs(ftp.control,noperm);
  397.                 } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  398.                     usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  399.                 } else {
  400.                     log(ftp.control,"STOR %s",file);
  401.                     recvit(&ftp,"STOR",file);
  402.                 }
  403.             }
  404.             free(file);
  405.             break;
  406.         case PORT_CMD:
  407.             if(pport(&ftp.port,arg) == -1){
  408.                 usputs(ftp.control,badport);
  409.             } else {
  410.                 usputs(ftp.control,portok);
  411.             }
  412.             break;
  413. #ifndef CPM
  414.         case LIST_CMD:
  415.             file = pathname(ftp.cd,arg);
  416.             if(!permcheck(ftp.path,RETR_CMD,file)){
  417.                 usputs(ftp.control,noperm);
  418.             } else if((ftp.fp = dir(file,1)) == NULLFILE){
  419.                 usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  420.             } else {
  421.                 sendit(&ftp,"LIST",file);
  422.             }
  423.             free(file);
  424.             break;
  425.         case NLST_CMD:
  426.             file = pathname(ftp.cd,arg);
  427.             if(!permcheck(ftp.path,RETR_CMD,file)){
  428.                 usputs(ftp.control,noperm);
  429.             } else if((ftp.fp = dir(file,0)) == NULLFILE){
  430.                 usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  431.             } else {
  432.                 sendit(&ftp,"NLST",file);
  433.             }
  434.             free(file);
  435.             break;
  436.         case CWD_CMD:
  437.             file = pathname(ftp.cd,arg);
  438.             if(!permcheck(ftp.path,RETR_CMD,file)){
  439.                 usputs(ftp.control,noperm);
  440.                 free(file);
  441. #ifdef  MSDOS
  442.         /* Don'tcha just LOVE %%$#@!! MS-DOS? */
  443.             } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  444. #else
  445.             } else if(access(file,0) == 0){ /* See if it exists */
  446. #endif
  447.             /* Succeeded, record in control block */
  448.                 free(ftp.cd);
  449.                 ftp.cd = file;
  450.   
  451.             /* If exists, send the contents of 'desc.ftp' in the new
  452.              * directory...
  453.              */
  454.                 strcpy(buf,file);
  455.                 if((fpm = fopen(strcat(buf,"/desc.ftp"),"r")) != NULL) {
  456.                     sendmsgfile(ftp.control,257,buf,sizeof(buf),fpm);
  457.                     fclose(fpm);
  458.                 }
  459.   
  460.                 usprintf(ftp.control,pwdmsg,file);
  461.             } else {
  462.             /* Failed, don't change anything */
  463.                 usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  464.                 free(file);
  465.             }
  466.             break;
  467.         case XPWD_CMD:
  468.         case PWD_CMD:
  469.             usprintf(ftp.control,pwdmsg,ftp.cd);
  470.             break;
  471. #else
  472.         case LIST_CMD:
  473.         case NLST_CMD:
  474.         case CWD_CMD:
  475.         case XPWD_CMD:
  476.         case PWD_CMD:
  477. #endif
  478.         case ACCT_CMD:
  479.             usputs(ftp.control,unimp);
  480.             break;
  481.         case DELE_CMD:
  482.             file = pathname(ftp.cd,arg);
  483.             if(!permcheck(ftp.path,DELE_CMD,file)){
  484.                 usputs(ftp.control,noperm);
  485.             } else if(unlink(file) == 0){
  486.                 log(ftp.control,"DELE %s",file);
  487.                 usputs(ftp.control,deleok);
  488.             } else {
  489.                 usprintf(ftp.control,delefail,sys_errlist[errno]);
  490.             }
  491.             free(file);
  492.             break;
  493.         case PASS_CMD:
  494.             if(ftp.username == NULLCHAR)
  495.                 usputs(ftp.control,userfirst);
  496.             else
  497.                 ftplogin(&ftp,arg);
  498.             break;
  499. #ifndef CPM
  500.         case XMKD_CMD:
  501.         case MKD_CMD:
  502.             file = pathname(ftp.cd,arg);
  503.             if(!permcheck(ftp.path,MKD_CMD,file)){
  504.                 usputs(ftp.control,noperm);
  505. #ifdef  UNIX
  506.             } else if(mkdir(file,0777) == 0){
  507. #else
  508.             } else if(mkdir(file) == 0){
  509. #endif
  510.                 log(ftp.control,"MKD %s",file);
  511.                 usputs(ftp.control,mkdok);
  512.             } else {
  513.                 usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  514.             }
  515.             free(file);
  516.             break;
  517.         case XRMD_CMD:
  518.         case RMD_CMD:
  519.             file = pathname(ftp.cd,arg);
  520.             if(!permcheck(ftp.path,RMD_CMD,file)){
  521.                 usputs(ftp.control,noperm);
  522.             } else if(rmdir(file) == 0){
  523.                 log(ftp.control,"RMD %s",file);
  524.                 usputs(ftp.control,deleok);
  525.             } else {
  526.                 usprintf(ftp.control,delefail,sys_errlist[errno]);
  527.             }
  528.             free(file);
  529.             break;
  530.         case STRU_CMD:
  531.             if(tolower(arg[0]) != 'f')
  532.                 usputs(ftp.control,unsupp);
  533.             else
  534.                 usputs(ftp.control,okay);
  535.             break;
  536.         case MODE_CMD:
  537.             if(tolower(arg[0]) != 's')
  538.                 usputs(ftp.control,unsupp);
  539.             else
  540.                 usputs(ftp.control,okay);
  541.             break;
  542.         case SYST_CMD:
  543.             usprintf(ftp.control,syst,System,shortversion);
  544.             break;
  545.     }
  546. #endif
  547.     goto loop;
  548.     finish:
  549.   
  550.     FtpUsers--;
  551.     log(ftp.control,"close FTP");
  552.     /* Clean up */
  553.     close_s(ftp.control);
  554.     if(ftp.data != -1)
  555.         close_s(ftp.data);
  556.     if(ftp.fp != NULLFILE)
  557.         fclose(ftp.fp);
  558.     free(ftp.username);
  559.     free(ftp.path);
  560.     free(ftp.cd);
  561. }
  562.   
  563. /* Shut down FTP server */
  564. int
  565. ftp0(argc,argv,p)
  566. int argc;
  567. char *argv[];
  568. void *p;
  569. {
  570.     int16 port;
  571.   
  572.     if(argc < 2)
  573.         port = IPPORT_FTP;
  574.     else
  575.         port = atoi(argv[1]);
  576.     return stop_tcp(port);
  577. }
  578.   
  579. static
  580. int
  581. pport(sock,arg)
  582. struct sockaddr_in *sock;
  583. char *arg;
  584. {
  585.     int32 n;
  586.     int i;
  587.   
  588.     n = 0;
  589.     for(i=0;i<4;i++){
  590.         n = atoi(arg) + (n << 8);
  591.         if((arg = strchr(arg,',')) == NULLCHAR)
  592.             return -1;
  593.         arg++;
  594.     }
  595.     sock->sin_addr.s_addr = n;
  596.     n = atoi(arg);
  597.     if((arg = strchr(arg,',')) == NULLCHAR)
  598.         return -1;
  599.     arg++;
  600.     n = atoi(arg) + (n << 8);
  601.     sock->sin_port = n;
  602.     return 0;
  603. }
  604.   
  605. /* Attempt to log in the user whose name is in ftp->username and password
  606.  * in pass
  607.  */
  608. static void
  609. ftplogin(ftp,pass)
  610. struct ftpserv *ftp;
  611. char *pass;
  612. {
  613.     char *path;
  614.     char *p;
  615.     int len,anony = 0;
  616.     FILE *fp;
  617.     char buf[128];
  618.   
  619.     path = mallocw(200);
  620.     if(userlogin(ftp->username,pass,&path,200,&anony,"ftpdef") == -1) {
  621.         usputs(ftp->control,noperm);
  622.         free(path);
  623.         return;
  624.     }
  625.     /* Set up current directory and path prefix */
  626.     ftp->path = strdup(path);
  627.     ftp->cd = firstpath(path);
  628.     free(path);
  629.   
  630.     strcpy(buf,ftp->cd);
  631.     /* If path ends on /, cut if off; this allows the message to be
  632.      * send when login is to the root dir - WG7J
  633.      */
  634.     len = strlen(buf);
  635.     if(buf[len-1] == '/')
  636.         buf[len-1] = '\0';
  637.   
  638.     if((fp = fopen(strcat(buf,"/message.ftp"),"r")) != NULL) {
  639.         sendmsgfile(ftp->control,230,buf,sizeof(buf),fp);
  640.         fclose(fp);
  641.     }
  642.   
  643.     if(!anony){
  644.         usputs(ftp->control,logged);
  645.         log(ftp->control,"%s logged in",ftp->username);
  646.     } else {
  647.         usputs(ftp->control,loggeda);
  648.         log(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  649.     }
  650. }
  651.   
  652. static int
  653. sendit(ftp,command,file)
  654. struct ftpserv *ftp;
  655. char *command;
  656. char *file;
  657. {
  658.     long total, starting;
  659.     unsigned long check;
  660.     struct sockaddr_in dport;
  661.     char *cp;
  662.     char fsizetext[20] = "";                /* N1BEE */
  663.   
  664.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  665.     dport.sin_family = AF_INET;
  666.     dport.sin_addr.s_addr = INADDR_ANY;
  667.     dport.sin_port = IPPORT_FTPD;
  668.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  669.     sprintf(fsizetext, "(%lu bytes)", filelength(fileno(ftp->fp)));
  670.     usprintf(ftp->control,sending,command,file,fsizetext);  /* N1BEE */
  671.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  672.         fclose(ftp->fp);
  673.         ftp->fp = NULLFILE;
  674.         close_s(ftp->data);
  675.         ftp->data = -1;
  676.         usputs(ftp->control,noconn);
  677.         return -1;
  678.     }
  679. #ifdef LZW
  680.     if(ftp->uselzw == 1)
  681.         /* do lzwinit() for socket. */
  682.         lzwinit(ftp->data,ftp->lzwbits,ftp->lzwmode);
  683. #endif
  684.     if(strcmp(command,"RSME") == 0) {
  685.         cp = mallocw(40);
  686.         recvline(ftp->control,cp,40);
  687.         starting = atol(cp);
  688.         /* If checksum field is not present go on anyway, for compatibility
  689.          * with previous scheme. If present check it and barf if wrong.
  690.          */
  691.         if(strchr(cp,' ') != NULL){
  692.             check = (unsigned long)atol(strchr(cp,' '));
  693.             check -= checksum(ftp->fp,starting);
  694.             if(check != 0){
  695.                 free(cp);
  696.                 usputs(ftp->control,badcheck);
  697.                 shutdown(ftp->data,1);  /* Blow away data connection */
  698.                 goto send_err;
  699.             }
  700.         } else if(fseek(ftp->fp,starting,SEEK_SET) != 0) {
  701.             free(cp);
  702.             usputs(ftp->control,noconn);
  703.             shutdown(ftp->data,2);  /* Blow away data connection */
  704.             goto send_err;
  705.         }
  706.     }
  707.   
  708.     /* Do the actual transfer */
  709.     total = sendfile(ftp->fp,ftp->data,ftp->type,0,NULL);
  710.   
  711.     if(total == -1){
  712.         /* An error occurred on the data connection */
  713.         usputs(ftp->control,noconn);
  714.         shutdown(ftp->data,2);  /* Blow away data connection */
  715.     } else {
  716.         usputs(ftp->control,txok);
  717.     }
  718.     send_err:       fclose(ftp->fp);
  719.     ftp->fp = NULLFILE;
  720.     close_s(ftp->data);
  721.     ftp->data = -1;
  722. #ifdef LZW
  723.     /* Done with data socket. Turn off lzw for now */
  724.     ftp->uselzw = 0;
  725. #endif
  726.     if(total == -1)
  727.         return -1;
  728.     else
  729.         return 0;
  730. }
  731. static int
  732. recvit(ftp,command,file)
  733. struct ftpserv *ftp;
  734. char *command;
  735. char *file;
  736. {
  737.     struct sockaddr_in dport;
  738.     long total, starting;
  739.   
  740.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  741.     dport.sin_family = AF_INET;
  742.     dport.sin_addr.s_addr = INADDR_ANY;
  743.     dport.sin_port = IPPORT_FTPD;
  744.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  745.     usprintf(ftp->control,sending,command,file,"");
  746.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  747.         fclose(ftp->fp);
  748.         ftp->fp = NULLFILE;
  749.         close_s(ftp->data);
  750.         ftp->data = -1;
  751.         usputs(ftp->control,noconn);
  752.         return -1;
  753.     }
  754. #ifdef LZW
  755.     if(ftp->uselzw == 1)
  756.         /* do lzwinit() for socket. */
  757.         lzwinit(ftp->data,ftp->lzwbits,ftp->lzwmode);
  758. #endif
  759.     if(strcmp(command,"RPUT") == 0){
  760.         if((starting = getsize(ftp->fp)) == -1)
  761.             starting = 0L;
  762.         usprintf(ftp->control,"%ld %lu\n",starting,checksum(ftp->fp,starting));
  763.         fseek(ftp->fp,starting,SEEK_SET);
  764.     }
  765.   
  766.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  767.   
  768. #ifdef  CPM
  769.     if(ftp->type == ASCII_TYPE)
  770.         putc(CTLZ,ftp->fp);
  771. #endif
  772.     if(total == -1) {
  773.         /* An error occurred while writing the file */
  774.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  775.         shutdown(ftp->data,2);  /* Blow it away */
  776.     } else
  777.         usputs(ftp->control,rxok);
  778.   
  779.     close_s(ftp->data);
  780.     ftp->data = -1;
  781.     fclose(ftp->fp);
  782.     ftp->fp = NULLFILE;
  783. #ifdef LZW
  784.     /* Done with data socket. Turn off lzw for now */
  785.     ftp->uselzw = 0;
  786. #endif
  787.     if(total == -1)
  788.         return -1;
  789.     else
  790.         return 0;
  791. }
  792.   
  793. #endif /* FTPSERVER */
  794.   
  795. #ifdef  MSDOS
  796. /* Illegal characters in a DOS filename */
  797. static char badchars[] = "\"[]|<>+=;,";
  798. #endif
  799.   
  800. /* Return 1 if the file operation is allowed, 0 otherwise */
  801. int
  802. permcheck(path,op,file)
  803. char *path;
  804. int op;
  805. char *file;
  806. {
  807.     char *cp,*privs;
  808.     long perms;
  809.   
  810.     if(file == NULLCHAR || path == NULLCHAR)
  811.         return 0;       /* Probably hasn't logged in yet */
  812.   
  813. #ifdef  MSDOS
  814.     /* Check for characters illegal in MS-DOS file names */
  815.   
  816. #ifdef notdef
  817.     for(cp = file;*cp != '\0';cp++){
  818.         if(*cp != '\\' && *cp != '/' && *cp != '.' && *cp != ':'
  819.             && *cp != '?' && *cp != '*' && dosfnchr(*cp) == 0)
  820.             return 0;
  821.     }
  822. #endif
  823.   
  824.     if(strpbrk(file,badchars) != NULLCHAR)
  825.         return 0;
  826.   
  827. #endif
  828.   
  829. #ifndef MAC
  830.     /* The target file must be under the user's allowed search path */
  831.     /* We let them specify multiple paths using path;path... -russ */
  832.     /* Now full form: path[;path...] perm path[;path...] perm ... */
  833.     {
  834.         int pathlen;
  835.   
  836.         for(cp = path;;){
  837.             /* Make sure format is valid, privs field should be present! */
  838.             if((privs=strpbrk(cp," \t")) == NULLCHAR)
  839.                 return 0;
  840.             /* Find length of path */
  841.             pathlen = strcspn(cp,"; \t");
  842.             while(pathlen) {
  843.                 /* Check filename with path */
  844.                 if(strncmp(file,cp,pathlen) == 0 && (
  845.                     /* Some path validation */
  846.                     file[pathlen] == '\0' ||
  847.                     file[pathlen] == '/' ||
  848.                     file[pathlen-1] == '/'))
  849.                     break;
  850.                 /* Check next path */
  851.                 cp += pathlen;
  852.                 if(*cp == ';')  /* There is more in this compound path ! */
  853.                     pathlen = strcspn(++cp,"; \t");
  854.                 else
  855.                     pathlen = 0;
  856.             }
  857.             if(pathlen) /* we found a match, no check privs */
  858.                 break;
  859.             /* now see if there is more after the privs... */
  860.             privs = skipwhite(privs);
  861.             if((cp = strpbrk(privs," \t")) == NULL)
  862.                 return 0;   /* Nothing there ! */
  863.             /* skip spaces or tabs to get start of next 'path perm' entry */
  864.             cp = skipwhite(cp);
  865.         }
  866.     }
  867. #endif
  868.   
  869.     /* Now find start of privs */
  870.     privs = skipwhite(privs);
  871.     if(strnicmp(privs,"0x",2) == 0)
  872.         perms = htol(privs);
  873.     else
  874.         perms = atol(privs);
  875.   
  876.     switch(op){
  877.         case RETR_CMD:
  878.         /* User must have permission to read files */
  879.             if(perms & FTP_READ)
  880.                 return 1;
  881.             return 0;
  882.         case DELE_CMD:
  883.         case RMD_CMD:
  884.         case RPUT_CMD:
  885.         /* User must have permission to (over)write files */
  886.             if(perms & FTP_WRITE)
  887.                 return 1;
  888.             return 0;
  889.         case STOR_CMD:
  890.         case MKD_CMD:
  891.         /* User must have permission to (over)write files, or permission
  892.          * to create them if the file doesn't already exist
  893.          */
  894.             if(perms & FTP_WRITE)
  895.                 return 1;
  896.             if(access(file,2) == -1 && (perms & FTP_CREATE))
  897.                 return 1;
  898.             return 0;
  899.     }
  900.     return 0;       /* "can't happen" -- keep lint happy */
  901. }
  902.   
  903.