blob: 2a39ec419195989f20f793a62cea6d9208c7c613 [file] [log] [blame]
Lorenzo Colitti313379e2013-07-11 01:07:11 +09001/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35char copyright[] =
36"@(#) Copyright (c) 1983 Regents of the University of California.\n\
37 All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41/*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/
42/*static char rcsid[] = "$Id: tftpd.c,v 1.3 1993/08/01 18:28:53 mycroft Exp $";*/
43#endif /* not lint */
44
45/*
46 * Trivial file transfer protocol server.
47 *
48 * This version includes many modifications by Jim Guyton <guyton@rand-unix>
49 */
50
51#include <sys/types.h>
52#include <sys/ioctl.h>
53#include <sys/stat.h>
54#include <unistd.h>
55#include <signal.h>
56#include <fcntl.h>
57
58#include <sys/socket.h>
59#include <netinet/in.h>
60#include <netdb.h>
61
62#include <setjmp.h>
63#include <syslog.h>
64#include <stdio.h>
65#include <errno.h>
66#include <ctype.h>
67#include <string.h>
68#include <stdlib.h>
69
70#include "tftp.h"
71
72#ifndef MSG_CONFIRM
73#define MSG_CONFIRM 0
74#warning Please, upgrade kernel, otherwise this tftpd has no advantages.
75#endif
76
77#define TIMEOUT 5
78
79int peer;
80int rexmtval = TIMEOUT;
81int maxtimeout = 5*TIMEOUT;
82
83#define PKTSIZE SEGSIZE+4
84char buf[PKTSIZE];
85char ackbuf[PKTSIZE];
86union {
87 struct sockaddr sa;
88 struct sockaddr_in sin;
89 struct sockaddr_in6 sin6;
90} from;
91socklen_t fromlen;
92
93#define MAXARG 1
94char *dirs[MAXARG+1];
95
96void tftp(struct tftphdr *tp, int size) __attribute__((noreturn));
97void nak(int error);
98int validate_access(char *filename, int mode);
99
100struct formats;
101
102void sendfile(struct formats *pf);
103void recvfile(struct formats *pf);
104
105
106int main(int ac, char **av)
107{
108 register struct tftphdr *tp;
109 register int n = 0;
110 int on = 1;
111
112 /* Sanity. If parent forgot to setuid() on us. */
113 if (geteuid() == 0) {
114 setgid(65534);
115 setuid(65534);
116 }
117
118 ac--; av++;
119 while (ac-- > 0 && n < MAXARG)
120 dirs[n++] = *av++;
121
122 openlog("tftpd", LOG_PID, LOG_DAEMON);
123 if (ioctl(0, FIONBIO, &on) < 0) {
124 syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
125 exit(1);
126 }
127 fromlen = sizeof (from);
128 n = recvfrom(0, buf, sizeof (buf), 0,
129 (struct sockaddr *)&from, &fromlen);
130 if (n < 0) {
131 if (errno != EAGAIN)
132 syslog(LOG_ERR, "recvfrom: %m\n");
133 exit(1);
134 }
135 /*
136 * Now that we have read the message out of the UDP
137 * socket, we fork and exit. Thus, inetd will go back
138 * to listening to the tftp port, and the next request
139 * to come in will start up a new instance of tftpd.
140 *
141 * We do this so that inetd can run tftpd in "wait" mode.
142 * The problem with tftpd running in "nowait" mode is that
143 * inetd may get one or more successful "selects" on the
144 * tftp port before we do our receive, so more than one
145 * instance of tftpd may be started up. Worse, if tftpd
146 * break before doing the above "recvfrom", inetd would
147 * spawn endless instances, clogging the system.
148 */
149 {
150 int pid;
151 int i;
152 socklen_t j;
153
154 for (i = 1; i < 20; i++) {
155 pid = fork();
156 if (pid < 0) {
157 sleep(i);
158 /*
159 * flush out to most recently sent request.
160 *
161 * This may drop some request, but those
162 * will be resent by the clients when
163 * they timeout. The positive effect of
164 * this flush is to (try to) prevent more
165 * than one tftpd being started up to service
166 * a single request from a single client.
167 */
168 j = sizeof from;
169 i = recvfrom(0, buf, sizeof (buf), 0,
170 (struct sockaddr *)&from, &j);
171 if (i > 0) {
172 n = i;
173 fromlen = j;
174 }
175 } else {
176 break;
177 }
178 }
179 if (pid < 0) {
180 syslog(LOG_ERR, "fork: %m\n");
181 exit(1);
182 } else if (pid != 0) {
183 exit(0);
184 }
185 }
186 alarm(0);
187 close(0);
188 close(1);
189 peer = socket(from.sa.sa_family, SOCK_DGRAM, 0);
190 if (peer < 0) {
191 syslog(LOG_ERR, "socket: %m\n");
192 exit(1);
193 }
194 if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
195 syslog(LOG_ERR, "connect: %m\n");
196 exit(1);
197 }
198 tp = (struct tftphdr *)buf;
199 tp->th_opcode = ntohs(tp->th_opcode);
200 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
201 tftp(tp, n);
202 exit(1);
203}
204
205struct formats {
206 char *f_mode;
207 int (*f_validate)(char *filename, int mode);
208 void (*f_send)(struct formats*);
209 void (*f_recv)(struct formats*);
210 int f_convert;
211} formats[] = {
212 { "netascii", validate_access, sendfile, recvfile, 1 },
213 { "octet", validate_access, sendfile, recvfile, 0 },
214#ifdef notdef
215 { "mail", validate_user, sendmail, recvmail, 1 },
216#endif
217 { 0 }
218};
219
220/*
221 * Handle initial connection protocol.
222 */
223void tftp(struct tftphdr *tp, int size)
224{
225 register char *cp;
226 int first = 1, ecode;
227 register struct formats *pf;
228 char *filename, *mode = NULL;
229
230 filename = cp = tp->th_stuff;
231again:
232 while (cp < buf + size) {
233 if (*cp == '\0')
234 break;
235 cp++;
236 }
237 if (*cp != '\0') {
238 nak(EBADOP);
239 exit(1);
240 }
241 if (first) {
242 mode = ++cp;
243 first = 0;
244 goto again;
245 }
246 for (cp = mode; *cp; cp++)
247 if (isupper(*cp))
248 *cp = tolower(*cp);
249 for (pf = formats; pf->f_mode; pf++)
250 if (strcmp(pf->f_mode, mode) == 0)
251 break;
252 if (pf->f_mode == 0) {
253 nak(EBADOP);
254 exit(1);
255 }
256 ecode = (*pf->f_validate)(filename, tp->th_opcode);
257 if (ecode) {
258 nak(ecode);
259 exit(1);
260 }
261 if (tp->th_opcode == WRQ)
262 (*pf->f_recv)(pf);
263 else
264 (*pf->f_send)(pf);
265 exit(0);
266}
267
268
269FILE *file;
270
271/*
272 * Validate file access. Since we
273 * have no uid or gid, for now require
274 * file to exist and be publicly
275 * readable/writable.
276 * If we were invoked with arguments
277 * from inetd then the file must also be
278 * in one of the given directory prefixes.
279 * Note also, full path name must be
280 * given as we have no login directory.
281 */
282int validate_access(char *filename, int mode)
283{
284 struct stat stbuf;
285 int fd;
286 char *cp;
287 char fnamebuf[1024+512];
288
289 for (cp = filename; *cp; cp++) {
290 if(*cp == '.' && (cp == filename || strncmp(cp-1, "/../", 4) == 0)) {
291 syslog(LOG_ERR, "bad path %s", filename);
292 return(EACCESS);
293 }
294 }
295
296 if (*filename == '/')
297 filename++;
298
299 if (!*dirs) {
300 syslog(LOG_ERR, "no dirs");
301 return EACCESS;
302 }
303 snprintf(fnamebuf, sizeof(fnamebuf)-1, "%s/%s", *dirs, filename);
304 filename = fnamebuf;
305
306 if (stat(filename, &stbuf) < 0) {
307 syslog(LOG_ERR, "stat %s : %m", filename);
308 return (errno == ENOENT ? ENOTFOUND : EACCESS);
309 }
310 if (mode == RRQ) {
311 if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) {
312 syslog(LOG_ERR, "not readable %s", filename);
313 return (EACCESS);
314 }
315 } else {
316 if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) {
317 syslog(LOG_ERR, "not writable %s", filename);
318 return (EACCESS);
319 }
320 }
321 fd = open(filename, mode == RRQ ? 0 : 1);
322 if (fd < 0) {
323 syslog(LOG_ERR, "cannot open %s: %m", filename);
324 return (errno + 100);
325 }
326 file = fdopen(fd, (mode == RRQ)? "r":"w");
327 if (file == NULL) {
328 return errno+100;
329 }
330 return (0);
331}
332
333int confirmed;
334int timeout;
335jmp_buf timeoutbuf;
336
337void timer(int signo)
338{
339 confirmed = 0;
340 timeout += rexmtval;
341 if (timeout >= maxtimeout)
342 exit(1);
343 longjmp(timeoutbuf, 1);
344}
345
346/*
347 * Send the requested file.
348 */
349void sendfile(struct formats *pf)
350{
351 struct tftphdr *dp;
352 register struct tftphdr *ap; /* ack packet */
353 volatile int block = 1;
354 int size, n;
355
356 confirmed = 0;
357 signal(SIGALRM, timer);
358 dp = r_init();
359 ap = (struct tftphdr *)ackbuf;
360 do {
361 size = readit(file, &dp, pf->f_convert);
362 if (size < 0) {
363 nak(errno + 100);
364 goto abort;
365 }
366 dp->th_opcode = htons((u_short)DATA);
367 dp->th_block = htons((u_short)block);
368 timeout = 0;
369 (void) setjmp(timeoutbuf);
370
371send_data:
372 if (send(peer, dp, size + 4, confirmed) != size + 4) {
373 syslog(LOG_ERR, "tftpd: write: %m\n");
374 goto abort;
375 }
376 confirmed = 0;
377 read_ahead(file, pf->f_convert);
378 for ( ; ; ) {
379 alarm(rexmtval); /* read the ack */
380 n = recv(peer, ackbuf, sizeof (ackbuf), 0);
381 alarm(0);
382 if (n < 0) {
383 syslog(LOG_ERR, "tftpd: read: %m\n");
384 goto abort;
385 }
386 ap->th_opcode = ntohs((u_short)ap->th_opcode);
387 ap->th_block = ntohs((u_short)ap->th_block);
388
389 if (ap->th_opcode == ERROR)
390 goto abort;
391
392 if (ap->th_opcode == ACK) {
393 if (ap->th_block == block) {
394 confirmed = MSG_CONFIRM;
395 break;
396 }
397 /* Re-synchronize with the other side */
398 synchnet(peer);
399 if (ap->th_block == (block -1)) {
400 goto send_data;
401 }
402 }
403
404 }
405 block++;
406 } while (size == SEGSIZE);
407abort:
408 (void) fclose(file);
409}
410
411void justquit(int signo)
412{
413 exit(0);
414}
415
416
417/*
418 * Receive a file.
419 */
420void recvfile(struct formats *pf)
421{
422 struct tftphdr *dp;
423 register struct tftphdr *ap; /* ack buffer */
424 volatile int block = 0, n, size;
425
426 confirmed = 0;
427 signal(SIGALRM, timer);
428 dp = w_init();
429 ap = (struct tftphdr *)ackbuf;
430 do {
431 timeout = 0;
432 ap->th_opcode = htons((u_short)ACK);
433 ap->th_block = htons((u_short)block);
434 block++;
435 (void) setjmp(timeoutbuf);
436send_ack:
437 if (send(peer, ackbuf, 4, confirmed) != 4) {
438 syslog(LOG_ERR, "tftpd: write: %m\n");
439 goto abort;
440 }
441 confirmed = 0;
442 write_behind(file, pf->f_convert);
443 for ( ; ; ) {
444 alarm(rexmtval);
445 n = recv(peer, dp, PKTSIZE, 0);
446 alarm(0);
447 if (n < 0) { /* really? */
448 syslog(LOG_ERR, "tftpd: read: %m\n");
449 goto abort;
450 }
451 dp->th_opcode = ntohs((u_short)dp->th_opcode);
452 dp->th_block = ntohs((u_short)dp->th_block);
453 if (dp->th_opcode == ERROR)
454 goto abort;
455 if (dp->th_opcode == DATA) {
456 if (dp->th_block == block) {
457 confirmed = MSG_CONFIRM;
458 break; /* normal */
459 }
460 /* Re-synchronize with the other side */
461 (void) synchnet(peer);
462 if (dp->th_block == (block-1))
463 goto send_ack; /* rexmit */
464 }
465 }
466 /* size = write(file, dp->th_data, n - 4); */
467 size = writeit(file, &dp, n - 4, pf->f_convert);
468 if (size != (n-4)) { /* ahem */
469 if (size < 0) nak(errno + 100);
470 else nak(ENOSPACE);
471 goto abort;
472 }
473 } while (size == SEGSIZE);
474 write_behind(file, pf->f_convert);
475 (void) fclose(file); /* close data file */
476
477 ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
478 ap->th_block = htons((u_short)(block));
479 (void) send(peer, ackbuf, 4, confirmed);
480
481 signal(SIGALRM, justquit); /* just quit on timeout */
482 alarm(rexmtval);
483 n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
484 alarm(0);
485 if (n >= 4 && /* if read some data */
486 dp->th_opcode == DATA && /* and got a data block */
487 block == dp->th_block) { /* then my last ack was lost */
488 (void) send(peer, ackbuf, 4, 0); /* resend final ack */
489 }
490abort:
491 return;
492}
493
494struct errmsg {
495 int e_code;
496 char *e_msg;
497} errmsgs[] = {
498 { EUNDEF, "Undefined error code" },
499 { ENOTFOUND, "File not found" },
500 { EACCESS, "Access violation" },
501 { ENOSPACE, "Disk full or allocation exceeded" },
502 { EBADOP, "Illegal TFTP operation" },
503 { EBADID, "Unknown transfer ID" },
504 { EEXISTS, "File already exists" },
505 { ENOUSER, "No such user" },
506 { -1, 0 }
507};
508
509/*
510 * Send a nak packet (error message).
511 * Error code passed in is one of the
512 * standard TFTP codes, or a UNIX errno
513 * offset by 100.
514 */
515void nak(int error)
516{
517 register struct tftphdr *tp;
518 int length;
519 register struct errmsg *pe;
520
521 tp = (struct tftphdr *)buf;
522 tp->th_opcode = htons((u_short)ERROR);
523 tp->th_code = htons((u_short)error);
524 for (pe = errmsgs; pe->e_code >= 0; pe++)
525 if (pe->e_code == error)
526 break;
527 if (pe->e_code < 0) {
528 pe->e_msg = strerror(error - 100);
529 tp->th_code = EUNDEF; /* set 'undef' errorcode */
530 }
531 strcpy(tp->th_msg, pe->e_msg);
532 length = strlen(pe->e_msg);
533 tp->th_msg[length] = '\0';
534 length += 5;
535 if (send(peer, buf, length, 0) != length)
536 syslog(LOG_ERR, "nak: %m\n");
537}