|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)tftpd.c 5.6 (Berkeley) 5/13/86";
15: #endif not lint
16:
17:
18: /*
19: * Trivial file transfer protocol server.
20: *
21: * This version includes many modifications by Jim Guyton <guyton@rand-unix>
22: */
23:
24: #include <sys/types.h>
25: #include <sys/socket.h>
26: #include <sys/ioctl.h>
27: #include <sys/wait.h>
28: #include <sys/stat.h>
29:
30: #include <netinet/in.h>
31:
32: #include <arpa/tftp.h>
33:
34: #include <signal.h>
35: #include <stdio.h>
36: #include <errno.h>
37: #include <ctype.h>
38: #include <netdb.h>
39: #include <setjmp.h>
40: #include <syslog.h>
41:
42: #define TIMEOUT 5
43:
44: extern int errno;
45: struct sockaddr_in sin = { AF_INET };
46: int peer;
47: int rexmtval = TIMEOUT;
48: int maxtimeout = 5*TIMEOUT;
49:
50: #define PKTSIZE SEGSIZE+4
51: char buf[PKTSIZE];
52: char ackbuf[PKTSIZE];
53: struct sockaddr_in from;
54: int fromlen;
55:
56: main()
57: {
58: register struct tftphdr *tp;
59: register int n;
60: int on = 1;
61:
62: openlog("tftpd", LOG_PID, LOG_DAEMON);
63: if (ioctl(0, FIONBIO, &on) < 0) {
64: syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
65: exit(1);
66: }
67: fromlen = sizeof (from);
68: n = recvfrom(0, buf, sizeof (buf), 0,
69: (caddr_t)&from, &fromlen);
70: if (n < 0) {
71: syslog(LOG_ERR, "recvfrom: %m\n");
72: exit(1);
73: }
74: /*
75: * Now that we have read the message out of the UDP
76: * socket, we fork and exit. Thus, inetd will go back
77: * to listening to the tftp port, and the next request
78: * to come in will start up a new instance of tftpd.
79: *
80: * We do this so that inetd can run tftpd in "wait" mode.
81: * The problem with tftpd running in "nowait" mode is that
82: * inetd may get one or more successful "selects" on the
83: * tftp port before we do our receive, so more than one
84: * instance of tftpd may be started up. Worse, if tftpd
85: * break before doing the above "recvfrom", inetd would
86: * spawn endless instances, clogging the system.
87: */
88: {
89: int pid;
90: int i, j;
91:
92: for (i = 1; i < 20; i++) {
93: pid = fork();
94: if (pid < 0) {
95: sleep(i);
96: /*
97: * flush out to most recently sent request.
98: *
99: * This may drop some request, but those
100: * will be resent by the clients when
101: * they timeout. The positive effect of
102: * this flush is to (try to) prevent more
103: * than one tftpd being started up to service
104: * a single request from a single client.
105: */
106: j = sizeof from;
107: i = recvfrom(0, buf, sizeof (buf), 0,
108: (caddr_t)&from, &j);
109: if (i > 0) {
110: n = i;
111: fromlen = j;
112: }
113: } else {
114: break;
115: }
116: }
117: if (pid < 0) {
118: syslog(LOG_ERR, "fork: %m\n");
119: exit(1);
120: } else if (pid != 0) {
121: exit(0);
122: }
123: }
124: from.sin_family = AF_INET;
125: alarm(0);
126: close(0);
127: close(1);
128: peer = socket(AF_INET, SOCK_DGRAM, 0);
129: if (peer < 0) {
130: syslog(LOG_ERR, "socket: %m\n");
131: exit(1);
132: }
133: if (bind(peer, (caddr_t)&sin, sizeof (sin)) < 0) {
134: syslog(LOG_ERR, "bind: %m\n");
135: exit(1);
136: }
137: if (connect(peer, (caddr_t)&from, sizeof(from)) < 0) {
138: syslog(LOG_ERR, "connect: %m\n");
139: exit(1);
140: }
141: tp = (struct tftphdr *)buf;
142: tp->th_opcode = ntohs(tp->th_opcode);
143: if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
144: tftp(tp, n);
145: exit(1);
146: }
147:
148: int validate_access();
149: int sendfile(), recvfile();
150:
151: struct formats {
152: char *f_mode;
153: int (*f_validate)();
154: int (*f_send)();
155: int (*f_recv)();
156: int f_convert;
157: } formats[] = {
158: { "netascii", validate_access, sendfile, recvfile, 1 },
159: { "octet", validate_access, sendfile, recvfile, 0 },
160: #ifdef notdef
161: { "mail", validate_user, sendmail, recvmail, 1 },
162: #endif
163: { 0 }
164: };
165:
166: /*
167: * Handle initial connection protocol.
168: */
169: tftp(tp, size)
170: struct tftphdr *tp;
171: int size;
172: {
173: register char *cp;
174: int first = 1, ecode;
175: register struct formats *pf;
176: char *filename, *mode;
177:
178: filename = cp = tp->th_stuff;
179: again:
180: while (cp < buf + size) {
181: if (*cp == '\0')
182: break;
183: cp++;
184: }
185: if (*cp != '\0') {
186: nak(EBADOP);
187: exit(1);
188: }
189: if (first) {
190: mode = ++cp;
191: first = 0;
192: goto again;
193: }
194: for (cp = mode; *cp; cp++)
195: if (isupper(*cp))
196: *cp = tolower(*cp);
197: for (pf = formats; pf->f_mode; pf++)
198: if (strcmp(pf->f_mode, mode) == 0)
199: break;
200: if (pf->f_mode == 0) {
201: nak(EBADOP);
202: exit(1);
203: }
204: ecode = (*pf->f_validate)(filename, tp->th_opcode);
205: if (ecode) {
206: nak(ecode);
207: exit(1);
208: }
209: if (tp->th_opcode == WRQ)
210: (*pf->f_recv)(pf);
211: else
212: (*pf->f_send)(pf);
213: exit(0);
214: }
215:
216:
217: FILE *file;
218:
219: /*
220: * Validate file access. Since we
221: * have no uid or gid, for now require
222: * file to exist and be publicly
223: * readable/writable.
224: * Note also, full path name must be
225: * given as we have no login directory.
226: */
227: validate_access(filename, mode)
228: char *filename;
229: int mode;
230: {
231: struct stat stbuf;
232: int fd;
233:
234: if (*filename != '/')
235: return (EACCESS);
236: if (stat(filename, &stbuf) < 0)
237: return (errno == ENOENT ? ENOTFOUND : EACCESS);
238: if (mode == RRQ) {
239: if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
240: return (EACCESS);
241: } else {
242: if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
243: return (EACCESS);
244: }
245: fd = open(filename, mode == RRQ ? 0 : 1);
246: if (fd < 0)
247: return (errno + 100);
248: file = fdopen(fd, (mode == RRQ)? "r":"w");
249: if (file == NULL) {
250: return errno+100;
251: }
252: return (0);
253: }
254:
255: int timeout;
256: jmp_buf timeoutbuf;
257:
258: timer()
259: {
260:
261: timeout += rexmtval;
262: if (timeout >= maxtimeout)
263: exit(1);
264: longjmp(timeoutbuf, 1);
265: }
266:
267: /*
268: * Send the requested file.
269: */
270: sendfile(pf)
271: struct formats *pf;
272: {
273: struct tftphdr *dp, *r_init();
274: register struct tftphdr *ap; /* ack packet */
275: register int block = 1, size, n;
276:
277: signal(SIGALRM, timer);
278: dp = r_init();
279: ap = (struct tftphdr *)ackbuf;
280: do {
281: size = readit(file, &dp, pf->f_convert);
282: if (size < 0) {
283: nak(errno + 100);
284: goto abort;
285: }
286: dp->th_opcode = htons((u_short)DATA);
287: dp->th_block = htons((u_short)block);
288: timeout = 0;
289: (void) setjmp(timeoutbuf);
290:
291: send_data:
292: if (send(peer, dp, size + 4, 0) != size + 4) {
293: syslog(LOG_ERR, "tftpd: write: %m\n");
294: goto abort;
295: }
296: read_ahead(file, pf->f_convert);
297: for ( ; ; ) {
298: alarm(rexmtval); /* read the ack */
299: n = recv(peer, ackbuf, sizeof (ackbuf), 0);
300: alarm(0);
301: if (n < 0) {
302: syslog(LOG_ERR, "tftpd: read: %m\n");
303: goto abort;
304: }
305: ap->th_opcode = ntohs((u_short)ap->th_opcode);
306: ap->th_block = ntohs((u_short)ap->th_block);
307:
308: if (ap->th_opcode == ERROR)
309: goto abort;
310:
311: if (ap->th_opcode == ACK) {
312: if (ap->th_block == block) {
313: break;
314: }
315: /* Re-synchronize with the other side */
316: (void) synchnet(peer);
317: if (ap->th_block == (block -1)) {
318: goto send_data;
319: }
320: }
321:
322: }
323: block++;
324: } while (size == SEGSIZE);
325: abort:
326: (void) fclose(file);
327: }
328:
329: justquit()
330: {
331: exit(0);
332: }
333:
334:
335: /*
336: * Receive a file.
337: */
338: recvfile(pf)
339: struct formats *pf;
340: {
341: struct tftphdr *dp, *w_init();
342: register struct tftphdr *ap; /* ack buffer */
343: register int block = 0, n, size;
344:
345: signal(SIGALRM, timer);
346: dp = w_init();
347: ap = (struct tftphdr *)ackbuf;
348: do {
349: timeout = 0;
350: ap->th_opcode = htons((u_short)ACK);
351: ap->th_block = htons((u_short)block);
352: block++;
353: (void) setjmp(timeoutbuf);
354: send_ack:
355: if (send(peer, ackbuf, 4, 0) != 4) {
356: syslog(LOG_ERR, "tftpd: write: %m\n");
357: goto abort;
358: }
359: write_behind(file, pf->f_convert);
360: for ( ; ; ) {
361: alarm(rexmtval);
362: n = recv(peer, dp, PKTSIZE, 0);
363: alarm(0);
364: if (n < 0) { /* really? */
365: syslog(LOG_ERR, "tftpd: read: %m\n");
366: goto abort;
367: }
368: dp->th_opcode = ntohs((u_short)dp->th_opcode);
369: dp->th_block = ntohs((u_short)dp->th_block);
370: if (dp->th_opcode == ERROR)
371: goto abort;
372: if (dp->th_opcode == DATA) {
373: if (dp->th_block == block) {
374: break; /* normal */
375: }
376: /* Re-synchronize with the other side */
377: (void) synchnet(peer);
378: if (dp->th_block == (block-1))
379: goto send_ack; /* rexmit */
380: }
381: }
382: /* size = write(file, dp->th_data, n - 4); */
383: size = writeit(file, &dp, n - 4, pf->f_convert);
384: if (size != (n-4)) { /* ahem */
385: if (size < 0) nak(errno + 100);
386: else nak(ENOSPACE);
387: goto abort;
388: }
389: } while (size == SEGSIZE);
390: write_behind(file, pf->f_convert);
391: (void) fclose(file); /* close data file */
392:
393: ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
394: ap->th_block = htons((u_short)(block));
395: (void) send(peer, ackbuf, 4, 0);
396:
397: signal(SIGALRM, justquit); /* just quit on timeout */
398: alarm(rexmtval);
399: n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
400: alarm(0);
401: if (n >= 4 && /* if read some data */
402: dp->th_opcode == DATA && /* and got a data block */
403: block == dp->th_block) { /* then my last ack was lost */
404: (void) send(peer, ackbuf, 4, 0); /* resend final ack */
405: }
406: abort:
407: return;
408: }
409:
410: struct errmsg {
411: int e_code;
412: char *e_msg;
413: } errmsgs[] = {
414: { EUNDEF, "Undefined error code" },
415: { ENOTFOUND, "File not found" },
416: { EACCESS, "Access violation" },
417: { ENOSPACE, "Disk full or allocation exceeded" },
418: { EBADOP, "Illegal TFTP operation" },
419: { EBADID, "Unknown transfer ID" },
420: { EEXISTS, "File already exists" },
421: { ENOUSER, "No such user" },
422: { -1, 0 }
423: };
424:
425: /*
426: * Send a nak packet (error message).
427: * Error code passed in is one of the
428: * standard TFTP codes, or a UNIX errno
429: * offset by 100.
430: */
431: nak(error)
432: int error;
433: {
434: register struct tftphdr *tp;
435: int length;
436: register struct errmsg *pe;
437: extern char *sys_errlist[];
438:
439: tp = (struct tftphdr *)buf;
440: tp->th_opcode = htons((u_short)ERROR);
441: tp->th_code = htons((u_short)error);
442: for (pe = errmsgs; pe->e_code >= 0; pe++)
443: if (pe->e_code == error)
444: break;
445: if (pe->e_code < 0) {
446: pe->e_msg = sys_errlist[error - 100];
447: tp->th_code = EUNDEF; /* set 'undef' errorcode */
448: }
449: strcpy(tp->th_msg, pe->e_msg);
450: length = strlen(pe->e_msg);
451: tp->th_msg[length] = '\0';
452: length += 5;
453: if (send(peer, buf, length, 0) != length)
454: syslog(LOG_ERR, "nak: %m\n");
455: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.