home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / tcpipsrc / ftpserv.c < prev    next >
C/C++ Source or Header  |  1991-01-26  |  18KB  |  726 lines

  1. /* Internet FTP Server
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <time.h>
  7. #ifdef    __TURBOC__
  8. #include <io.h>
  9. #include <dir.h>
  10. #endif
  11. #include "global.h"
  12. #include "mbuf.h"
  13. #include "socket.h"
  14. #include "ftp.h"
  15. #include "ftpserv.h"
  16. #include "proc.h"
  17. #include "dirutil.h"
  18. #include "commands.h"
  19.  
  20. static void ftpserv __ARGS((int s,void *unused,void *p));
  21. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  22. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  23. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  24. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  25.  
  26. /* Command table */
  27. static char *commands[] = {
  28.     "user",
  29.     "acct",
  30.     "pass",
  31.     "type",
  32.     "list",
  33.     "cwd",
  34.     "dele",
  35.     "name",
  36.     "quit",
  37.     "retr",
  38.     "stor",
  39.     "port",
  40.     "nlst",
  41.     "pwd",
  42.     "xpwd",            /* For compatibility with 4.2BSD */
  43.     "mkd ",
  44.     "xmkd",            /* For compatibility with 4.2BSD */
  45.     "xrmd",            /* For compatibility with 4.2BSD */
  46.     "rmd ",
  47.     "stru",
  48.     "mode",
  49.     NULLCHAR
  50. };
  51.  
  52. /* Response messages */
  53. static char banner[] = "220 %s FTP version %s ready at %s\n";
  54. static char badcmd[] = "500 Unknown command\n";
  55. static char binwarn[] = "100 Warning: type is ASCII and %s appears to be binary\n";
  56. static char unsupp[] = "500 Unsupported command or option\n";
  57. static char givepass[] = "331 Enter PASS command\n";
  58. static char logged[] = "230 Logged in\n";
  59. static char typeok[] = "200 Type %s OK\n";
  60. static char only8[] = "501 Only logical bytesize 8 supported\n";
  61. static char deleok[] = "250 File deleted\n";
  62. static char mkdok[] = "200 MKD ok\n";
  63. static char delefail[] = "550 Delete failed: %s\n";
  64. static char pwdmsg[] = "257 \"%s\" is current directory\n";
  65. static char badtype[] = "501 Unknown type \"%s\"\n";
  66. static char badport[] = "501 Bad port syntax\n";
  67. static char unimp[] = "502 Command not yet implemented\n";
  68. static char bye[] = "221 Goodbye!\n";
  69. static char nodir[] = "553 Can't read directory \"%s\": %s\n";
  70. static char cantopen[] = "550 Can't read file \"%s\": %s\n";
  71. static char sending[] = "150 Opening data connection for %s %s\n";
  72. static char cantmake[] = "553 Can't create \"%s\": %s\n";
  73. static char writerr[] = "552 Write error: %s\n";
  74. static char portok[] = "200 Port command okay\n";
  75. static char rxok[] = "226 File received OK\n";
  76. static char txok[] = "226 File sent OK\n";
  77. static char noperm[] = "550 Permission denied\n";
  78. static char noconn[] = "425 Data connection reset\n";
  79. static char lowmem[] = "421 System overloaded, try again later\n";
  80. static char notlog[] = "530 Please log in with USER and PASS\n";
  81. static char userfirst[] = "503 Login with USER first.\n";
  82. static char okay[] = "200 Ok\n";
  83.  
  84. static int Sftp = -1;    /* Prototype socket for service */
  85.  
  86. /* Start up FTP service */
  87. int
  88. ftpstart(argc,argv,p)
  89. int argc;
  90. char *argv[];
  91. void *p;
  92. {
  93.     struct sockaddr_in lsocket;
  94.     int s;
  95.  
  96.     if(Sftp != -1){
  97.         /* Already running! */
  98.         return 0;
  99.     }
  100.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  101.     chname(Curproc,"FTP listener");
  102.  
  103.     lsocket.sin_family = AF_INET;
  104.     lsocket.sin_addr.s_addr = INADDR_ANY;
  105.     if(argc < 2)
  106.         lsocket.sin_port = IPPORT_FTP;
  107.     else
  108.         lsocket.sin_port = atoi(argv[1]);
  109.  
  110.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  111.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  112.     listen(Sftp,1);
  113.     for(;;){
  114.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  115.             break;    /* Service is shutting down */
  116.  
  117.         if(availmem() < Memthresh){
  118.             usprintf(s,lowmem);
  119.             shutdown(s,1);
  120.         } else {
  121.             /* Spawn a server */
  122.             newproc("ftpserv",2048,ftpserv,s,NULL,NULL,0);
  123.         }
  124.     }
  125.     return 0;
  126. }
  127. static void
  128. ftpserv(s,unused,p)
  129. int s;    /* Socket with user connection */
  130. void *unused;
  131. void *p;
  132. {
  133.     struct ftpserv ftp;
  134.     char **cmdp,buf[512],*arg,*cp,*cp1,*file,*mode;
  135.     long t;
  136.     int cnt,i;
  137.     struct sockaddr_in socket;
  138.  
  139.     sockmode(s,SOCK_ASCII);
  140.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  141.     ftp.data = -1;
  142.  
  143.     sockowner(s,Curproc);        /* We own it now */
  144.     ftp.control = s;
  145.     /* Set default data port */
  146.     i = SOCKSIZE;
  147.     getpeername(s,(char *)&socket,&i);
  148.     socket.sin_port = IPPORT_FTPD;
  149.     ASSIGN(ftp.port,socket);
  150.  
  151.     log(s,"open FTP");
  152.     time(&t);
  153.     cp = ctime(&t);
  154.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  155.         *cp1 = '\0';
  156.     usprintf(s,banner,Hostname,Version,cp);
  157. loop:    if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  158.         /* He closed on us */
  159.         goto finish;
  160.     }
  161.     if(cnt == 0){
  162.         /* Can't be a legal FTP command */
  163.         usprintf(ftp.control,badcmd);
  164.         goto loop;
  165.     }    
  166.     rip(buf);
  167. #ifdef    UNIX
  168.     /* Translate first word to lower case */
  169.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  170.         *cp = tolower(*cp);
  171. #else
  172.     /* Translate entire buffer to lower case */
  173.     for(cp = buf;*cp != '\0';cp++)
  174.         *cp = tolower(*cp);
  175. #endif
  176.     /* Find command in table; if not present, return syntax error */
  177.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  178.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  179.             break;
  180.     if(*cmdp == NULLCHAR){
  181.         usprintf(ftp.control,badcmd);
  182.         goto loop;
  183.     }
  184.     /* Allow only USER, PASS and QUIT before logging in */
  185.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  186.         switch(cmdp-commands){
  187.         case USER_CMD:
  188.         case PASS_CMD:
  189.         case QUIT_CMD:
  190.             break;
  191.         default:
  192.             usprintf(ftp.control,notlog);
  193.             goto loop;
  194.         }
  195.     }
  196.     arg = &buf[strlen(*cmdp)];
  197.     while(*arg == ' ')
  198.         arg++;
  199.  
  200.     /* Execute specific command */
  201.     switch(cmdp-commands){
  202.     case USER_CMD:
  203.         free(ftp.username);
  204.         ftp.username = strdup(arg);
  205.         usprintf(ftp.control,givepass);
  206.         break;
  207.     case TYPE_CMD:
  208.         switch(arg[0]){
  209.         case 'A':
  210.         case 'a':    /* Ascii */
  211.             ftp.type = ASCII_TYPE;
  212.             usprintf(ftp.control,typeok,arg);
  213.             break;
  214.         case 'l':
  215.         case 'L':
  216.             while(*arg != ' ' && *arg != '\0')
  217.                 arg++;
  218.             if(*arg == '\0' || *++arg != '8'){
  219.                 usprintf(ftp.control,only8);
  220.                 break;
  221.             }
  222.             ftp.type = LOGICAL_TYPE;
  223.             ftp.logbsize = 8;
  224.             usprintf(ftp.control,typeok,arg);
  225.             break;
  226.         case 'B':
  227.         case 'b':    /* Binary */
  228.         case 'I':
  229.         case 'i':    /* Image */
  230.             ftp.type = IMAGE_TYPE;
  231.             usprintf(ftp.control,typeok,arg);
  232.             break;
  233.         default:    /* Invalid */
  234.             usprintf(ftp.control,badtype,arg);
  235.             break;
  236.         }
  237.         break;
  238.     case QUIT_CMD:
  239.         usprintf(ftp.control,bye);
  240.         goto finish;
  241.     case RETR_CMD:
  242.         file = pathname(ftp.cd,arg);
  243.         switch(ftp.type){
  244.         case IMAGE_TYPE:
  245.         case LOGICAL_TYPE:
  246.             mode = READ_BINARY;
  247.             break;
  248.         case ASCII_TYPE:
  249.             mode = READ_TEXT;
  250.             break;
  251.         }
  252.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  253.              usprintf(ftp.control,noperm);
  254.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  255.             usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  256.         } else {
  257.             log(ftp.control,"RETR %s",file);
  258.             if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  259.                 usprintf(ftp.control,binwarn,file);
  260.             }
  261.             sendit(&ftp,"RETR",file);
  262.         }
  263.         free(file);
  264.         break;
  265.     case STOR_CMD:
  266.         file = pathname(ftp.cd,arg);
  267.         switch(ftp.type){
  268.         case IMAGE_TYPE:
  269.         case LOGICAL_TYPE:
  270.             mode = WRITE_BINARY;
  271.             break;
  272.         case ASCII_TYPE:
  273.             mode = WRITE_TEXT;
  274.             break;
  275.         }
  276.         if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file)){
  277.              usprintf(ftp.control,noperm);
  278.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  279.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  280.         } else {
  281.             log(ftp.control,"STOR %s",file);
  282.             recvit(&ftp,"STOR",file);
  283.         }
  284.         free(file);
  285.         break;
  286.     case PORT_CMD:
  287.         if(pport(&ftp.port,arg) == -1){
  288.             usprintf(ftp.control,badport);
  289.         } else {
  290.             usprintf(ftp.control,portok);
  291.         }
  292.         break;
  293. #ifndef CPM
  294.     case LIST_CMD:
  295.         file = pathname(ftp.cd,arg);
  296.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  297.              usprintf(ftp.control,noperm);
  298.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  299.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  300.         } else {
  301.             sendit(&ftp,"LIST",file);
  302.         }
  303.         free(file);
  304.         break;
  305.     case NLST_CMD:
  306.         file = pathname(ftp.cd,arg);
  307.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  308.              usprintf(ftp.control,noperm);
  309.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  310.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  311.         } else {
  312.             sendit(&ftp,"NLST",file);
  313.         }
  314.         free(file);
  315.         break;
  316.     case CWD_CMD:
  317.         file = pathname(ftp.cd,arg);
  318.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  319.              usprintf(ftp.control,noperm);
  320.             free(file);
  321. #ifdef    MSDOS
  322.         /* Don'tcha just LOVE %%$#@!! MS-DOS? */
  323.         } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  324. #else
  325.         } else if(access(file,0) == 0){    /* See if it exists */
  326. #endif
  327.             /* Succeeded, record in control block */
  328.             free(ftp.cd);
  329.             ftp.cd = file;
  330.             usprintf(ftp.control,pwdmsg,file);
  331.         } else {
  332.             /* Failed, don't change anything */
  333.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  334.             free(file);
  335.         }
  336.         break;
  337.     case XPWD_CMD:
  338.     case PWD_CMD:
  339.         usprintf(ftp.control,pwdmsg,ftp.cd);
  340.         break;
  341. #else
  342.     case LIST_CMD:
  343.     case NLST_CMD:
  344.     case CWD_CMD:
  345.     case XPWD_CMD:
  346.     case PWD_CMD:
  347. #endif
  348.     case ACCT_CMD:        
  349.         usprintf(ftp.control,unimp);
  350.         break;
  351.     case DELE_CMD:
  352.         file = pathname(ftp.cd,arg);
  353.         if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file)){
  354.              usprintf(ftp.control,noperm);
  355.         } else if(unlink(file) == 0){
  356.             log(ftp.control,"DELE %s",file);
  357.             usprintf(ftp.control,deleok);
  358.         } else {
  359.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  360.         }
  361.         free(file);
  362.         break;
  363.     case PASS_CMD:
  364.         if(ftp.username == NULLCHAR)
  365.             usprintf(ftp.control,userfirst);
  366.         else
  367.             ftplogin(&ftp,arg);            
  368.         break;
  369. #ifndef    CPM
  370.     case XMKD_CMD:
  371.     case MKD_CMD:
  372.         file = pathname(ftp.cd,arg);
  373.         if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file)){
  374.             usprintf(ftp.control,noperm);
  375. #ifdef    UNIX
  376.         } else if(mkdir(file,0777) == 0){
  377. #else
  378.         } else if(mkdir(file) == 0){
  379. #endif
  380.             log(ftp.control,"MKD %s",file);
  381.             usprintf(ftp.control,mkdok);
  382.         } else {
  383.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  384.         }
  385.         free(file);
  386.         break;
  387.     case XRMD_CMD:
  388.     case RMD_CMD:
  389.         file = pathname(ftp.cd,arg);
  390.         if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file)){
  391.              usprintf(ftp.control,noperm);
  392.         } else if(rmdir(file) == 0){
  393.             log(ftp.control,"RMD %s",file);
  394.             usprintf(ftp.control,deleok);
  395.         } else {
  396.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  397.         }
  398.         free(file);
  399.         break;
  400.     case STRU_CMD:
  401.         if(tolower(arg[0]) != 'f')
  402.             usprintf(ftp.control,unsupp);
  403.         else
  404.             usprintf(ftp.control,okay);
  405.         break;
  406.     case MODE_CMD:
  407.         if(tolower(arg[0]) != 's')
  408.             usprintf(ftp.control,unsupp);
  409.         else
  410.             usprintf(ftp.control,okay);
  411.         break;
  412.     }
  413. #endif
  414.     goto loop;
  415. finish:
  416.     log(ftp.control,"close FTP");
  417.     /* Clean up */
  418.     close_s(ftp.control);
  419.     if(ftp.data != -1)
  420.         close_s(ftp.data);
  421.     if(ftp.fp != NULLFILE)
  422.         fclose(ftp.fp);
  423.     free(ftp.username);
  424.     free(ftp.path);
  425.     free(ftp.cd);
  426. }
  427.  
  428. /* Shut down FTP server */
  429. int
  430. ftp0(argc,argv,p)
  431. int argc;
  432. char *argv[];
  433. void *p;
  434. {
  435.     close_s(Sftp);
  436.     Sftp = -1;
  437.     return 0;
  438. }
  439. static
  440. int
  441. pport(sock,arg)
  442. struct sockaddr_in *sock;
  443. char *arg;
  444. {
  445.     int32 n;
  446.     int i;
  447.  
  448.     n = 0;
  449.     for(i=0;i<4;i++){
  450.         n = atoi(arg) + (n << 8);
  451.         if((arg = strchr(arg,',')) == NULLCHAR)
  452.             return -1;
  453.         arg++;
  454.     }
  455.     sock->sin_addr.s_addr = n;
  456.     n = atoi(arg);
  457.     if((arg = strchr(arg,',')) == NULLCHAR)
  458.         return -1;
  459.     arg++;
  460.     n = atoi(arg) + (n << 8);
  461.     sock->sin_port = n;
  462.     return 0;
  463. }
  464.  
  465. /* Subroutine for logging in the user whose name is name and password is pass.
  466.    The buffer path should be long enough to keep a line from the userfile.
  467.    If pwdignore is true, the password check will be overridden.
  468.    The return value is the permissions field or -1 if the login failed.
  469.    Path is set to point at the path field, and pwdignore will be true if no
  470.    particular password was needed for this user.
  471.  */
  472. int
  473. userlogin(name,pass,path,len,pwdignore)
  474. char *name;
  475. char *pass;
  476. char **path;
  477. int len;            /* Length of buffer pointed at by *path */
  478. int *pwdignore;
  479. {
  480.     char *cp,*cp1;
  481.     FILE *fp;
  482.     int anony,perm;
  483.  
  484.     if((fp = fopen(Userfile,READ_TEXT)) == NULLFILE)
  485.         /* Userfile doesn't exist */
  486.         return -1;
  487.     while(fgets(*path,len,fp),!feof(fp)){
  488.         if(*path[0] == '#')
  489.             continue;    /* Comment */
  490.         if((cp = strchr(*path,' ')) == NULLCHAR)
  491.             /* Bogus entry */
  492.             continue;
  493.         *cp++ = '\0';        /* Now points to password */
  494.         if(stricmp(name,*path) == 0)
  495.             break;        /* Found user name */
  496.     }
  497.     if(feof(fp)){
  498.         /* User name not found in file */
  499.         fclose(fp);
  500.         return -1;
  501.     }
  502.     fclose(fp);
  503.     /* Look for space after password field in file */
  504.     if((cp1 = strchr(cp,' ')) == NULLCHAR)
  505.         /* Invalid file entry */
  506.         return -1;
  507.     *cp1++ = '\0';    /* Now points to path field */
  508.     anony = *pwdignore;
  509.     if(strcmp(cp,"*") == 0)
  510.         anony = 1;    /* User ID is password-free */
  511.     if(!anony && strcmp(cp,pass) != 0)
  512.         /* Password required, but wrong one given */
  513.         return -1;
  514.     if((cp = strchr(cp1,' ')) == NULLCHAR)
  515.         /* Permission field missing */
  516.         return -1;
  517.     *cp++ = '\0';    /* now points to permission field */
  518.     perm = atoi(cp);
  519. #if   defined(AMIGA)
  520.     /*
  521.      * Well, on the Amiga, a file can be referenced by many names:
  522.      * device names (DF0:) or volume names (My_Disk:).  This hunk of code
  523.      * passed the pathname specified in the ftpusers file, and gets the
  524.      * absolute path copied into the user's buffer.  We really should just
  525.      * allocate the buffer and return a pointer to it, since the caller
  526.      * really doesn't have a good idea how long the path string is..
  527.      */
  528.     cp1 = pathname("", cp1);
  529.     if (cp1)
  530.         strcpy(*path, cp1);
  531.     else
  532.         **path = '\0';
  533.     free(cp1);
  534. #else
  535.     strcpy(*path,cp1);
  536.     /* Convert any backslashes to forward slashes, for backward
  537.      * compatibility with the old NET
  538.      */
  539.     while((cp = strchr(*path,'\\')) != NULLCHAR)
  540.         *cp = '/';
  541. #endif
  542.     *pwdignore = anony;
  543.     /* Finally return the permission bits */
  544.     return perm;
  545. }
  546.     
  547. /* Attempt to log in the user whose name is in ftp->username and password
  548.  * in pass
  549.  */
  550. static void
  551. ftplogin(ftp,pass)
  552. struct ftpserv *ftp;
  553. char *pass;
  554. {
  555.     char *path;
  556.     int anony = 0;
  557.  
  558.     path = mallocw(200);
  559.     if((ftp->perms = userlogin(ftp->username,pass,&path,200,&anony))
  560.        == -1){
  561.         usprintf(ftp->control,noperm);
  562.         free(path);
  563.         return;
  564.     }
  565.     /* Set up current directory and path prefix */
  566. #if    defined(AMIGAGONE)
  567.     ftp->cd = pathname("", path);
  568.     ftp->path = strdup(ftp->cd);
  569.     free(path);
  570. #else
  571.     ftp->cd = path;
  572.     ftp->path = strdup(path);
  573. #endif
  574.  
  575.     usprintf(ftp->control,logged);
  576.     if(!anony)
  577.         log(ftp->control,"%s logged in",ftp->username);
  578.     else
  579.         log(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  580. }
  581.  
  582. #ifdef    MSDOS
  583. /* Illegal characters in a DOS filename */
  584. static char badchars[] = "\"[]:|<>+=;,";
  585. #endif
  586.  
  587. /* Return 1 if the file operation is allowed, 0 otherwise */
  588. int
  589. permcheck(path,perms,op,file)
  590. char *path;
  591. int perms;
  592. int op;
  593. char *file;
  594. {
  595. #ifdef    MSDOS
  596.     char *cp;
  597. #endif
  598.  
  599.     if(file == NULLCHAR || path == NULLCHAR)
  600.         return 0;    /* Probably hasn't logged in yet */
  601. #ifdef    MSDOS
  602.     /* Check for characters illegal in MS-DOS file names */
  603.     for(cp = badchars;*cp != '\0';cp++){
  604.         if(strchr(file,*cp) != NULLCHAR)
  605.             return 0;    
  606.     }
  607. #endif
  608. #ifndef MAC
  609.     /* The target file must be under the user's allowed search path */
  610.     if(strncmp(file,path,strlen(path)) != 0)
  611.         return 0;
  612. #endif
  613.  
  614.     switch(op){
  615.     case RETR_CMD:
  616.         /* User must have permission to read files */
  617.         if(perms & FTP_READ)
  618.             return 1;
  619.         return 0;
  620.     case DELE_CMD:
  621.     case RMD_CMD:
  622.         /* User must have permission to (over)write files */
  623.         if(perms & FTP_WRITE)
  624.             return 1;
  625.         return 0;
  626.     case STOR_CMD:
  627.     case MKD_CMD:
  628.         /* User must have permission to (over)write files, or permission
  629.          * to create them if the file doesn't already exist
  630.          */
  631.         if(perms & FTP_WRITE)
  632.             return 1;
  633.         if(access(file,2) == -1 && (perms & FTP_CREATE))
  634.             return 1;
  635.         return 0;
  636.     }
  637.     return 0;    /* "can't happen" -- keep lint happy */
  638. }
  639. static int
  640. sendit(ftp,command,file)
  641. struct ftpserv *ftp;
  642. char *command;
  643. char *file;
  644. {
  645.     long total;
  646.     struct sockaddr_in dport;
  647.  
  648.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  649.     dport.sin_family = AF_INET;
  650.     dport.sin_addr.s_addr = INADDR_ANY;
  651.     dport.sin_port = IPPORT_FTPD;
  652.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  653.     usprintf(ftp->control,sending,command,file);
  654.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  655.         fclose(ftp->fp);
  656.         ftp->fp = NULLFILE;
  657.         close_s(ftp->data);
  658.         ftp->data = -1;
  659.         usprintf(ftp->control,noconn);
  660.         return -1;
  661.     }
  662.     /* Do the actual transfer */
  663.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  664.  
  665.     if(total == -1){
  666.         /* An error occurred on the data connection */
  667.         usprintf(ftp->control,noconn);
  668.         shutdown(ftp->data,2);    /* Blow away data connection */
  669.     } else {
  670.         usprintf(ftp->control,txok);
  671.     }
  672.     fclose(ftp->fp);
  673.     ftp->fp = NULLFILE;
  674.     close_s(ftp->data);
  675.     ftp->data = -1;
  676.     if(total == -1)
  677.         return -1;
  678.     else
  679.         return 0;
  680. }
  681. static int
  682. recvit(ftp,command,file)
  683. struct ftpserv *ftp;
  684. char *command;
  685. char *file;
  686. {
  687.     struct sockaddr_in dport;
  688.     long total;
  689.  
  690.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  691.     dport.sin_family = AF_INET;
  692.     dport.sin_addr.s_addr = INADDR_ANY;
  693.     dport.sin_port = IPPORT_FTPD;
  694.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  695.     usprintf(ftp->control,sending,command,file);
  696.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  697.         fclose(ftp->fp);
  698.         ftp->fp = NULLFILE;
  699.         close_s(ftp->data);
  700.         ftp->data = -1;
  701.         usprintf(ftp->control,noconn);
  702.         return -1;
  703.     }
  704.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  705.  
  706. #ifdef    CPM
  707.     if(ftp->type == ASCII_TYPE)
  708.         putc(CTLZ,ftp->fp);
  709. #endif
  710.     if(total == -1) {
  711.         /* An error occurred while writing the file */
  712.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  713.         shutdown(ftp->data,2);    /* Blow it away */
  714.     } else {
  715.         usprintf(ftp->control,rxok);
  716.         close_s(ftp->data);
  717.     }
  718.     ftp->data = -1;
  719.     fclose(ftp->fp);
  720.     ftp->fp = NULLFILE;
  721.     if(total == -1)
  722.         return -1;
  723.     else
  724.         return 0;
  725. }
  726.