ftpd.c

Go to the documentation of this file.
00001 /* ftpd.c Copyright 1992-2000 by Michael Temari All Rights Reserved
00002  *
00003  * ftpd         An FTP server program for use with Minix.
00004  *
00005  * Usage:       Minix usage: tcpd ftp ftpd
00006  *
00007  * 06/14/92 Tnet Release        Michael Temari
00008  * 01/15/96 0.30                Michael Temari
00009  * 01/25/96 0.90                Michael Temari
00010  * 03/17/96 0.91                Michael Temari
00011  * 06/27/96 0.92                Michael Temari
00012  * 07/02/96 0.93                Michael Temari
00013  * 07/15/96 0.94                Michael Temari
00014  * 08/27/96 0.95                Michael Temari
00015  * 02/09/97 0.96                Michael Temari
00016  * 02/10/97 0.97                Michael Temari
00017  * 09/25/97 0.98                Michael Temari
00018  * 03/10/00 0.99                Michael Temari, <Michael@TemWare.Com>
00019  * 12/12/03 1.00                Michael Temari, <Michael@TemWare.Com>
00020  * 02/06/05 1.01                Michael Temari, <Michael@TemWare.Com>
00021  * 02/12/05 2.00                Michael Temari, <Michael@TemWare.Com>
00022  */
00023 
00024 char *FtpdVersion = "2.00";
00025 
00026 #include <sys/types.h>
00027 #include <signal.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <ctype.h>
00031 #include <string.h>
00032 #include <time.h>
00033 #include <unistd.h>
00034 #include <net/gen/in.h>
00035 #include <net/gen/tcp.h>
00036 
00037 #include "ftpd.h"
00038 #include "access.h"
00039 #include "file.h"
00040 #include "net.h"
00041 
00042 _PROTOTYPE(static void init, (void));
00043 _PROTOTYPE(static int doHELP, (char *buff));
00044 _PROTOTYPE(static int doNOOP, (char *buff));
00045 _PROTOTYPE(static int doUNIMP, (char *buff));
00046 _PROTOTYPE(static int getline, (char *line, int len));
00047 
00048 FILE *msgfile = (FILE *)NULL;
00049 
00050 /* The following defines the inactivity timeout in seconds */
00051 #define INACTIVITY_TIMEOUT      60*5
00052 
00053 char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
00054 char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
00055                   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
00056 
00057 char line[512];
00058 
00059 int type, format, mode, structure;
00060 int ftpdata_fd = -1;
00061 int loggedin, gotuser, anonymous;
00062 char username[80];
00063 char anonpass[128];
00064 char newroot[128];
00065 
00066 ipaddr_t myipaddr, rmtipaddr, dataaddr;
00067 tcpport_t myport, rmtport, dataport;
00068 
00069 char myhostname[256], rmthostname[256];
00070 
00071 #define FTPD_LOG        "/usr/adm/ftpd.log"
00072 #define FTPD_MSG        "/etc/ftpd_msg"
00073 
00074 FILE *logfile;
00075 
00076 int timeout = 0;
00077 
00078 _PROTOTYPE(static int doHELP, (char *buff));
00079 _PROTOTYPE(int readline, (char **args));
00080 _PROTOTYPE(void Timeout, (int sig));
00081 _PROTOTYPE(int main, (int argc, char *argv[]));
00082 
00083 struct commands {
00084         char *name;
00085         _PROTOTYPE(int (*func), (char *buff));
00086 };
00087 
00088 struct commands commands[] = {
00089         "ABOR", doUNIMP,
00090         "ACCT", doUNIMP,
00091         "ALLO", doALLO,
00092         "APPE", doAPPE,
00093         "CDUP", doCDUP,
00094         "CWD",  doCWD,
00095         "DELE", doDELE,
00096         "HELP", doHELP,
00097         "LIST", doLIST,
00098         "MDTM", doMDTM,
00099         "MKD",  doMKD,
00100         "MODE", doMODE,
00101         "NLST", doNLST,
00102         "NOOP", doNOOP,
00103         "PASS", doPASS,
00104         "PASV", doPASV,
00105         "PORT", doPORT,
00106         "PWD",  doPWD,
00107         "QUIT", doQUIT,
00108         "REIN", doUNIMP,
00109         "REST", doREST,
00110         "RETR", doRETR,
00111         "RMD",  doRMD,
00112         "RNFR", doRNFR,
00113         "RNTO", doRNTO,
00114         "SITE", doSITE,
00115         "SIZE", doSIZE,
00116         "SMNT", doUNIMP,
00117         "STAT", doSTAT,
00118         "STOR", doSTOR,
00119         "STOU", doSTOU,
00120         "STRU", doSTRU,
00121         "SYST", doSYST,
00122         "TYPE", doTYPE,
00123         "USER", doUSER,
00124         "XCUP", doCDUP,
00125         "XCWD", doCWD,
00126         "XMKD", doMKD,
00127         "XPWD", doPWD,
00128         "XRMD", doRMD,
00129         "",     (int (*)())0
00130 };
00131 
00132 static void init()
00133 {
00134    loggedin = 0;
00135    gotuser = 0;
00136    anonymous = 0;
00137    newroot[0] = '\0';
00138    type = TYPE_A;
00139    format = 0;
00140    mode = MODE_S;
00141    structure = 0;
00142    ftpdata_fd = -1;
00143    username[0] = '\0';
00144    anonpass[0] = '\0';
00145 }
00146 
00147 /* nothing, nada, zilch... */
00148 static int doNOOP(buff)
00149 char *buff;
00150 {
00151    printf("200 NOOP to you too!\r\n");
00152 
00153    return(GOOD);
00154 }
00155 
00156 /* giv'em help, what a USER! */
00157 static int doHELP(buff)
00158 char *buff;
00159 {
00160 struct commands *cmd;
00161 char star;
00162 int i;
00163 char *space = "    ";
00164 
00165    printf("214-Here is a list of available ftp commands\r\n");
00166    printf("    Those with '*' are not yet implemented.\r\n");
00167 
00168    i = 0;
00169    for(cmd = commands; *cmd->name != '\0'; cmd++) {
00170         if(cmd->func == doUNIMP)
00171                 star = '*';
00172         else
00173                 star = ' ';
00174         printf("     %s%c%s", cmd->name, star, space + strlen(cmd->name));
00175         if(++i == 6) {
00176                 printf("\r\n");
00177                 i = 0;
00178         }
00179    }
00180 
00181    if(i)
00182         printf("\r\n");
00183 
00184    printf("214 That's all the help you get.\r\n");
00185 
00186    return(GOOD);
00187 }
00188 
00189 /* not implemented */
00190 static int doUNIMP(buff)
00191 char *buff;
00192 {
00193    printf("502 Command \"%s\" not implemented!\r\n", line);
00194 
00195    return(GOOD);
00196 }
00197 
00198 /* convert line for use */
00199 void cvtline(args)
00200 char **args;
00201 {
00202 char *p;
00203 
00204    p = line + strlen(line);
00205    while(--p >= line)
00206         if(*p == '\r' || *p == '\n' || isspace(*p))
00207                 *p = '\0';
00208         else
00209                 break;
00210 
00211   p = line;
00212 
00213 #ifdef DEBUG
00214   logit("COMMAND", line);
00215 #endif
00216 
00217   while(*p && !isspace(*p)) {
00218         *p = toupper(*p);
00219         p++;
00220   }
00221 
00222   if(*p) {
00223         *p = '\0';
00224         p++;
00225         while(*p && isspace(*p))
00226                 p++;
00227    }
00228 
00229    *args = p;
00230 
00231    return;
00232 }
00233 
00234 static int getline(line, len)
00235 char *line;
00236 int len;
00237 {
00238 int s;
00239 int gotcr;
00240 
00241    /* leave room for at end for null */
00242    len--;
00243 
00244    /* got to be able to put in at least 1 character */
00245    if(len < 1)
00246         return(-1);
00247 
00248    gotcr = 0;
00249    while(len-- > 0) {
00250         s = read(0, line, 1);
00251         if(s != 1)
00252                 return(-1);
00253         if(*line == '\n')
00254                 break;
00255         gotcr = (*line == '\r');
00256         line++;
00257    }
00258    if(gotcr)
00259         --line;
00260 
00261    *line = '\0';
00262 
00263    return(0);
00264 }
00265 
00266 int readline(args)
00267 char **args;
00268 {
00269    if(getline(line, sizeof(line)))
00270         return(BAD);
00271 
00272    cvtline(args);
00273 
00274    return(GOOD);
00275 }
00276 
00277 /* signal handler for inactivity timeout */
00278 void Timeout(sig)
00279 int sig;
00280 {
00281    timeout = 1;
00282 
00283    printf("421 Inactivity timer expired.\r\n");
00284 }
00285 
00286 /* logit */
00287 void logit(type, parm)
00288 char *type;
00289 char *parm;
00290 {
00291 time_t now;
00292 struct tm *tm;
00293 
00294    if(logfile == (FILE *)NULL)
00295         return;
00296 
00297    time(&now);
00298    tm = localtime(&now);
00299    fprintf(logfile, "%4d%02d%02d%02d%02d%02d ",
00300         1900+tm->tm_year,
00301         tm->tm_mon + 1,
00302         tm->tm_mday,
00303         tm->tm_hour, tm->tm_min, tm->tm_sec);
00304    fprintf(logfile, "%s %s %s %s %s\n",
00305         rmthostname, username, anonymous ? anonpass : username, type, parm);
00306    fflush(logfile);
00307 }
00308 
00309 void showmsg(reply, filename)
00310 char *reply;
00311 char *filename;
00312 {
00313 FILE *mfp;
00314 char *pe;
00315 static char mline[256];
00316 
00317    if(filename == (char *)NULL)
00318         mfp = msgfile;
00319    else
00320         mfp = fopen(filename, "r");
00321 
00322    if(mfp == (FILE *)NULL)
00323         return;
00324 
00325    while(fgets(mline, sizeof(mline), mfp) != (char *)NULL) {
00326         pe = mline + strlen(mline);
00327         while(--pe >= mline)
00328                 if(*pe == '\r' || *pe == '\n')
00329                         *pe = '\0';
00330                 else
00331                         break;
00332         printf("%s- %s\r\n", reply, mline);
00333    }
00334 
00335    if(filename != (char *)NULL)
00336         fclose(mfp);
00337 }
00338 
00339 int main(argc, argv)
00340 int argc;
00341 char *argv[];
00342 {
00343 struct commands *cmd;
00344 char *args;
00345 int status;
00346 time_t now;
00347 struct tm *tm;
00348 int s;
00349 
00350    GetNetInfo();
00351 
00352    /* open transfer log file if it exists */
00353    if((logfile = fopen(FTPD_LOG, "r")) != (FILE *)NULL) {
00354         fclose(logfile);
00355         logfile = fopen(FTPD_LOG, "a");
00356    }
00357 
00358    /* open login msg file */
00359    msgfile = fopen(FTPD_MSG, "r");
00360 
00361    /* Let's initialize some stuff */
00362    init();
00363 
00364    /* Log the connection */
00365    logit("CONNECT", "");
00366 
00367    /* Tell 'em we are ready */
00368    time(&now);
00369    tm = localtime(&now);
00370    printf("220 FTP service (Ftpd %s) ready on %s at ",
00371         FtpdVersion, myhostname);
00372    printf("%s, %02d %s %d %02d:%02d:%02d %s\r\n", days[tm->tm_wday],
00373         tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
00374         tm->tm_hour, tm->tm_min, tm->tm_sec,
00375         tzname[tm->tm_isdst]);
00376    fflush(stdout);
00377 
00378    /* Loop here getting commands */
00379    while(1) {
00380         signal(SIGALRM, Timeout);
00381         alarm(INACTIVITY_TIMEOUT);
00382         if(readline(&args) != GOOD) {
00383                 if(!timeout)
00384                         printf("221 Control connection closing (EOF).\r\n");
00385                 break;
00386         }
00387         alarm(0);
00388         for(cmd = commands; *cmd->name != '\0'; cmd++)
00389                 if(!strcmp(line, cmd->name))
00390                         break;
00391         if(*cmd->name != '\0')
00392                 status = (*cmd->func)(args);
00393         else {
00394                 printf("500 Command \"%s\" not recognized.\r\n", line);
00395                 status = GOOD;
00396         }
00397         fflush(stdout);
00398         if(status != GOOD)
00399                 break;
00400    }
00401 
00402    CleanUpPasv();
00403 
00404    return(-1);
00405 }

Generated on Fri Apr 14 22:56:54 2006 for minix by  doxygen 1.4.6