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