port of netbsd's tr
[minix.git] / commands / ftpd200 / ftpd.c
blob5727f1b6d22b0a11443ef7dc7718f6c8082abea8
1 /* ftpd.c Copyright 1992-2000 by Michael Temari All Rights Reserved
3 * ftpd An FTP server program for use with Minix.
5 * Usage: Minix usage: tcpd ftp ftpd
7 * 06/14/92 Tnet Release Michael Temari
8 * 01/15/96 0.30 Michael Temari
9 * 01/25/96 0.90 Michael Temari
10 * 03/17/96 0.91 Michael Temari
11 * 06/27/96 0.92 Michael Temari
12 * 07/02/96 0.93 Michael Temari
13 * 07/15/96 0.94 Michael Temari
14 * 08/27/96 0.95 Michael Temari
15 * 02/09/97 0.96 Michael Temari
16 * 02/10/97 0.97 Michael Temari
17 * 09/25/97 0.98 Michael Temari
18 * 03/10/00 0.99 Michael Temari, <Michael@TemWare.Com>
19 * 12/12/03 1.00 Michael Temari, <Michael@TemWare.Com>
20 * 02/06/05 1.01 Michael Temari, <Michael@TemWare.Com>
21 * 02/12/05 2.00 Michael Temari, <Michael@TemWare.Com>
24 char *FtpdVersion = "2.00";
26 #include <sys/types.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <net/gen/in.h>
35 #include <net/gen/tcp.h>
37 #include "ftpd.h"
38 #include "access.h"
39 #include "file.h"
40 #include "net.h"
42 _PROTOTYPE(static void init, (void));
43 _PROTOTYPE(static int doHELP, (char *buff));
44 _PROTOTYPE(static int doNOOP, (char *buff));
45 _PROTOTYPE(static int doUNIMP, (char *buff));
46 _PROTOTYPE(static int getline, (char *line, int len));
48 FILE *msgfile = (FILE *)NULL;
50 /* The following defines the inactivity timeout in seconds */
51 #define INACTIVITY_TIMEOUT 60*5
53 char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
54 char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
55 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
57 char line[512];
59 int type, format, mode, structure;
60 int ftpdata_fd = -1;
61 int loggedin, gotuser, anonymous;
62 char username[80];
63 char anonpass[128];
64 char newroot[128];
66 ipaddr_t myipaddr, rmtipaddr, dataaddr;
67 tcpport_t myport, rmtport, dataport;
69 char myhostname[256], rmthostname[256];
71 #define FTPD_LOG "/usr/adm/ftpd.log"
72 #define FTPD_MSG "/etc/ftpd_msg"
74 FILE *logfile;
76 int timeout = 0;
78 _PROTOTYPE(static int doHELP, (char *buff));
79 _PROTOTYPE(int readline, (char **args));
80 _PROTOTYPE(void Timeout, (int sig));
81 _PROTOTYPE(int main, (int argc, char *argv[]));
83 struct commands {
84 char *name;
85 _PROTOTYPE(int (*func), (char *buff));
88 struct commands commands[] = {
89 "ABOR", doUNIMP,
90 "ACCT", doUNIMP,
91 "ALLO", doALLO,
92 "APPE", doAPPE,
93 "CDUP", doCDUP,
94 "CWD", doCWD,
95 "DELE", doDELE,
96 "HELP", doHELP,
97 "LIST", doLIST,
98 "MDTM", doMDTM,
99 "MKD", doMKD,
100 "MODE", doMODE,
101 "NLST", doNLST,
102 "NOOP", doNOOP,
103 "PASS", doPASS,
104 "PASV", doPASV,
105 "PORT", doPORT,
106 "PWD", doPWD,
107 "QUIT", doQUIT,
108 "REIN", doUNIMP,
109 "REST", doREST,
110 "RETR", doRETR,
111 "RMD", doRMD,
112 "RNFR", doRNFR,
113 "RNTO", doRNTO,
114 "SITE", doSITE,
115 "SIZE", doSIZE,
116 "SMNT", doUNIMP,
117 "STAT", doSTAT,
118 "STOR", doSTOR,
119 "STOU", doSTOU,
120 "STRU", doSTRU,
121 "SYST", doSYST,
122 "TYPE", doTYPE,
123 "USER", doUSER,
124 "XCUP", doCDUP,
125 "XCWD", doCWD,
126 "XMKD", doMKD,
127 "XPWD", doPWD,
128 "XRMD", doRMD,
129 "", (int (*)())0
132 static void init()
134 loggedin = 0;
135 gotuser = 0;
136 anonymous = 0;
137 newroot[0] = '\0';
138 type = TYPE_A;
139 format = 0;
140 mode = MODE_S;
141 structure = 0;
142 ftpdata_fd = -1;
143 username[0] = '\0';
144 anonpass[0] = '\0';
147 /* nothing, nada, zilch... */
148 static int doNOOP(buff)
149 char *buff;
151 printf("200 NOOP to you too!\r\n");
153 return(GOOD);
156 /* giv'em help, what a USER! */
157 static int doHELP(buff)
158 char *buff;
160 struct commands *cmd;
161 char star;
162 int i;
163 char *space = " ";
165 printf("214-Here is a list of available ftp commands\r\n");
166 printf(" Those with '*' are not yet implemented.\r\n");
168 i = 0;
169 for(cmd = commands; *cmd->name != '\0'; cmd++) {
170 if(cmd->func == doUNIMP)
171 star = '*';
172 else
173 star = ' ';
174 printf(" %s%c%s", cmd->name, star, space + strlen(cmd->name));
175 if(++i == 6) {
176 printf("\r\n");
177 i = 0;
181 if(i)
182 printf("\r\n");
184 printf("214 That's all the help you get.\r\n");
186 return(GOOD);
189 /* not implemented */
190 static int doUNIMP(buff)
191 char *buff;
193 printf("502 Command \"%s\" not implemented!\r\n", line);
195 return(GOOD);
198 /* convert line for use */
199 void cvtline(args)
200 char **args;
202 char *p;
204 p = line + strlen(line);
205 while(--p >= line)
206 if(*p == '\r' || *p == '\n' || isspace(*p))
207 *p = '\0';
208 else
209 break;
211 p = line;
213 #ifdef DEBUG
214 logit("COMMAND", line);
215 #endif
217 while(*p && !isspace(*p)) {
218 *p = toupper(*p);
219 p++;
222 if(*p) {
223 *p = '\0';
224 p++;
225 while(*p && isspace(*p))
226 p++;
229 *args = p;
231 return;
234 static int getline(line, len)
235 char *line;
236 int len;
238 int s;
239 int gotcr;
241 /* leave room for at end for null */
242 len--;
244 /* got to be able to put in at least 1 character */
245 if(len < 1)
246 return(-1);
248 gotcr = 0;
249 while(len-- > 0) {
250 s = read(0, line, 1);
251 if(s != 1)
252 return(-1);
253 if(*line == '\n')
254 break;
255 gotcr = (*line == '\r');
256 line++;
258 if(gotcr)
259 --line;
261 *line = '\0';
263 return(0);
266 int readline(args)
267 char **args;
269 if(getline(line, sizeof(line)))
270 return(BAD);
272 cvtline(args);
274 return(GOOD);
277 /* signal handler for inactivity timeout */
278 void Timeout(sig)
279 int sig;
281 timeout = 1;
283 printf("421 Inactivity timer expired.\r\n");
286 /* logit */
287 void logit(type, parm)
288 char *type;
289 char *parm;
291 time_t now;
292 struct tm *tm;
294 if(logfile == (FILE *)NULL)
295 return;
297 time(&now);
298 tm = localtime(&now);
299 fprintf(logfile, "%4d%02d%02d%02d%02d%02d ",
300 1900+tm->tm_year,
301 tm->tm_mon + 1,
302 tm->tm_mday,
303 tm->tm_hour, tm->tm_min, tm->tm_sec);
304 fprintf(logfile, "%s %s %s %s %s\n",
305 rmthostname, username, anonymous ? anonpass : username, type, parm);
306 fflush(logfile);
309 void showmsg(reply, filename)
310 char *reply;
311 char *filename;
313 FILE *mfp;
314 char *pe;
315 static char mline[256];
317 if(filename == (char *)NULL)
318 mfp = msgfile;
319 else
320 mfp = fopen(filename, "r");
322 if(mfp == (FILE *)NULL)
323 return;
325 while(fgets(mline, sizeof(mline), mfp) != (char *)NULL) {
326 pe = mline + strlen(mline);
327 while(--pe >= mline)
328 if(*pe == '\r' || *pe == '\n')
329 *pe = '\0';
330 else
331 break;
332 printf("%s- %s\r\n", reply, mline);
335 if(filename != (char *)NULL)
336 fclose(mfp);
339 int main(argc, argv)
340 int argc;
341 char *argv[];
343 struct commands *cmd;
344 char *args;
345 int status;
346 time_t now;
347 struct tm *tm;
348 int s;
350 GetNetInfo();
352 /* open transfer log file if it exists */
353 if((logfile = fopen(FTPD_LOG, "r")) != (FILE *)NULL) {
354 fclose(logfile);
355 logfile = fopen(FTPD_LOG, "a");
358 /* open login msg file */
359 msgfile = fopen(FTPD_MSG, "r");
361 /* Let's initialize some stuff */
362 init();
364 /* Log the connection */
365 logit("CONNECT", "");
367 /* Tell 'em we are ready */
368 time(&now);
369 tm = localtime(&now);
370 printf("220 FTP service (Ftpd %s) ready on %s at ",
371 FtpdVersion, myhostname);
372 printf("%s, %02d %s %d %02d:%02d:%02d %s\r\n", days[tm->tm_wday],
373 tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
374 tm->tm_hour, tm->tm_min, tm->tm_sec,
375 tzname[tm->tm_isdst]);
376 fflush(stdout);
378 /* Loop here getting commands */
379 while(1) {
380 signal(SIGALRM, Timeout);
381 alarm(INACTIVITY_TIMEOUT);
382 if(readline(&args) != GOOD) {
383 if(!timeout)
384 printf("221 Control connection closing (EOF).\r\n");
385 break;
387 alarm(0);
388 for(cmd = commands; *cmd->name != '\0'; cmd++)
389 if(!strcmp(line, cmd->name))
390 break;
391 if(*cmd->name != '\0')
392 status = (*cmd->func)(args);
393 else {
394 printf("500 Command \"%s\" not recognized.\r\n", line);
395 status = GOOD;
397 fflush(stdout);
398 if(status != GOOD)
399 break;
402 CleanUpPasv();
404 return(-1);