Deleted Added
full compact
tftpd.c (173852) tftpd.c (207608)
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. 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

--- 27 unchanged lines hidden (view full) ---

36"@(#) Copyright (c) 1983, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
43#endif
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. 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

--- 27 unchanged lines hidden (view full) ---

36"@(#) Copyright (c) 1983, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
43#endif
44static const char rcsid[] =
45 "$FreeBSD: head/libexec/tftpd/tftpd.c 173852 2007-11-23 00:05:29Z edwin $";
46#endif /* not lint */
44#endif /* not lint */
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: head/libexec/tftpd/tftpd.c 207608 2010-05-04 06:19:19Z imp $");
47
48/*
49 * Trivial file transfer protocol server.
50 *
51 * This version includes many modifications by Jim Guyton
52 * <guyton@rand-unix>.
53 */
54
55#include <sys/param.h>
56#include <sys/ioctl.h>
57#include <sys/stat.h>
58#include <sys/socket.h>
47
48/*
49 * Trivial file transfer protocol server.
50 *
51 * This version includes many modifications by Jim Guyton
52 * <guyton@rand-unix>.
53 */
54
55#include <sys/param.h>
56#include <sys/ioctl.h>
57#include <sys/stat.h>
58#include <sys/socket.h>
59#include <sys/types.h>
60#include <sys/time.h>
61
62#include <netinet/in.h>
63#include <arpa/tftp.h>
59
60#include <netinet/in.h>
61#include <arpa/tftp.h>
64#include <arpa/inet.h>
65
66#include <ctype.h>
67#include <errno.h>
68#include <fcntl.h>
62
63#include <ctype.h>
64#include <errno.h>
65#include <fcntl.h>
69#include <libutil.h>
70#include <netdb.h>
71#include <pwd.h>
66#include <netdb.h>
67#include <pwd.h>
72#include <setjmp.h>
73#include <signal.h>
74#include <stdio.h>
75#include <stdlib.h>
76#include <string.h>
77#include <syslog.h>
68#include <stdio.h>
69#include <stdlib.h>
70#include <string.h>
71#include <syslog.h>
72#include <tcpd.h>
78#include <unistd.h>
79
73#include <unistd.h>
74
80#include "tftpsubs.h"
75#include "tftp-file.h"
76#include "tftp-io.h"
77#include "tftp-utils.h"
78#include "tftp-transfer.h"
79#include "tftp-options.h"
81
80
82#define TIMEOUT 5
83#define MAX_TIMEOUTS 5
81static void tftp_wrq(int peer, char *, ssize_t);
82static void tftp_rrq(int peer, char *, ssize_t);
84
83
85int peer;
86int rexmtval = TIMEOUT;
87int max_rexmtval = 2*TIMEOUT;
88
89#define PKTSIZE SEGSIZE+4
90char buf[PKTSIZE];
91char ackbuf[PKTSIZE];
92struct sockaddr_storage from;
93
94void tftp(struct tftphdr *, int);
95static void unmappedaddr(struct sockaddr_in6 *);
96
97/*
98 * Null-terminated directory prefix list for absolute pathname requests and
99 * search list for relative pathname requests.
100 *
101 * MAXDIRS should be at least as large as the number of arguments that
102 * inetd allows (currently 20).
103 */
104#define MAXDIRS 20
105static struct dirlist {
106 const char *name;
107 int len;
108} dirs[MAXDIRS+1];
109static int suppress_naks;
110static int logging;
111static int ipchroot;
112static int create_new = 0;
113static char *newfile_format = "%Y%m%d";
114static int increase_name = 0;
84/*
85 * Null-terminated directory prefix list for absolute pathname requests and
86 * search list for relative pathname requests.
87 *
88 * MAXDIRS should be at least as large as the number of arguments that
89 * inetd allows (currently 20).
90 */
91#define MAXDIRS 20
92static struct dirlist {
93 const char *name;
94 int len;
95} dirs[MAXDIRS+1];
96static int suppress_naks;
97static int logging;
98static int ipchroot;
99static int create_new = 0;
100static char *newfile_format = "%Y%m%d";
101static int increase_name = 0;
115static mode_t mask = S_IWGRP|S_IWOTH;
102static mode_t mask = S_IWGRP | S_IWOTH;
116
103
117static const char *errtomsg(int);
118static void nak(int);
119static void oack(void);
104struct formats;
105static void tftp_recvfile(int peer, const char *mode);
106static void tftp_xmitfile(int peer, const char *mode);
107static int validate_access(int peer, char **, int);
108static char peername[NI_MAXHOST];
120
109
121static void timer(int);
122static void justquit(int);
110FILE *file;
123
111
112struct formats {
113 const char *f_mode;
114 int f_convert;
115} formats[] = {
116 { "netascii", 1 },
117 { "octet", 0 },
118 { NULL, 0 }
119};
120
124int
125main(int argc, char *argv[])
126{
127 struct tftphdr *tp;
121int
122main(int argc, char *argv[])
123{
124 struct tftphdr *tp;
128 socklen_t fromlen, len;
129 int n;
130 int ch, on;
131 struct sockaddr_storage me;
132 char *chroot_dir = NULL;
133 struct passwd *nobody;
134 const char *chuser = "nobody";
125 int peer;
126 socklen_t peerlen, len;
127 ssize_t n;
128 int ch;
129 char *chroot_dir = NULL;
130 struct passwd *nobody;
131 const char *chuser = "nobody";
132 char recvbuffer[MAXPKTSIZE];
133 int allow_ro = 1, allow_wo = 1;
135
136 tzset(); /* syslog in localtime */
134
135 tzset(); /* syslog in localtime */
136 acting_as_client = 0;
137
137
138 openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
139 while ((ch = getopt(argc, argv, "cCF:lns:u:U:wW")) != -1) {
138 tftp_openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
139 while ((ch = getopt(argc, argv, "cCd:F:lnoOp:s:u:U:wW")) != -1) {
140 switch (ch) {
141 case 'c':
142 ipchroot = 1;
143 break;
144 case 'C':
145 ipchroot = 2;
146 break;
140 switch (ch) {
141 case 'c':
142 ipchroot = 1;
143 break;
144 case 'C':
145 ipchroot = 2;
146 break;
147 case 'd':
148 if (atoi(optarg) != 0)
149 debug += atoi(optarg);
150 else
151 debug |= debug_finds(optarg);
152 break;
147 case 'F':
148 newfile_format = optarg;
149 break;
150 case 'l':
151 logging = 1;
152 break;
153 case 'n':
154 suppress_naks = 1;
155 break;
153 case 'F':
154 newfile_format = optarg;
155 break;
156 case 'l':
157 logging = 1;
158 break;
159 case 'n':
160 suppress_naks = 1;
161 break;
162 case 'o':
163 options_rfc_enabled = 0;
164 break;
165 case 'O':
166 options_extra_enabled = 0;
167 break;
168 case 'p':
169 packetdroppercentage = atoi(optarg);
170 tftp_log(LOG_INFO,
171 "Randomly dropping %d out of 100 packets",
172 packetdroppercentage);
173 break;
156 case 's':
157 chroot_dir = optarg;
158 break;
159 case 'u':
160 chuser = optarg;
161 break;
162 case 'U':
163 mask = strtol(optarg, NULL, 0);
164 break;
165 case 'w':
166 create_new = 1;
167 break;
168 case 'W':
169 create_new = 1;
170 increase_name = 1;
171 break;
172 default:
174 case 's':
175 chroot_dir = optarg;
176 break;
177 case 'u':
178 chuser = optarg;
179 break;
180 case 'U':
181 mask = strtol(optarg, NULL, 0);
182 break;
183 case 'w':
184 create_new = 1;
185 break;
186 case 'W':
187 create_new = 1;
188 increase_name = 1;
189 break;
190 default:
173 syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
191 tftp_log(LOG_WARNING,
192 "ignoring unknown option -%c", ch);
174 }
175 }
176 if (optind < argc) {
177 struct dirlist *dirp;
178
179 /* Get list of directory prefixes. Skip relative pathnames. */
180 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
181 optind++) {

--- 4 unchanged lines hidden (view full) ---

186 }
187 }
188 }
189 else if (chroot_dir) {
190 dirs->name = "/";
191 dirs->len = 1;
192 }
193 if (ipchroot > 0 && chroot_dir == NULL) {
193 }
194 }
195 if (optind < argc) {
196 struct dirlist *dirp;
197
198 /* Get list of directory prefixes. Skip relative pathnames. */
199 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
200 optind++) {

--- 4 unchanged lines hidden (view full) ---

205 }
206 }
207 }
208 else if (chroot_dir) {
209 dirs->name = "/";
210 dirs->len = 1;
211 }
212 if (ipchroot > 0 && chroot_dir == NULL) {
194 syslog(LOG_ERR, "-c requires -s");
213 tftp_log(LOG_ERR, "-c requires -s");
195 exit(1);
196 }
197
198 umask(mask);
199
214 exit(1);
215 }
216
217 umask(mask);
218
200 on = 1;
201 if (ioctl(0, FIONBIO, &on) < 0) {
202 syslog(LOG_ERR, "ioctl(FIONBIO): %m");
203 exit(1);
219 {
220 int on = 1;
221 if (ioctl(0, FIONBIO, &on) < 0) {
222 tftp_log(LOG_ERR, "ioctl(FIONBIO): %s", strerror(errno));
223 exit(1);
224 }
204 }
225 }
205 fromlen = sizeof (from);
206 n = recvfrom(0, buf, sizeof (buf), 0,
207 (struct sockaddr *)&from, &fromlen);
226
227 /* Find out who we are talking to and what we are going to do */
228 peerlen = sizeof(peer_sock);
229 n = recvfrom(0, recvbuffer, MAXPKTSIZE, 0,
230 (struct sockaddr *)&peer_sock, &peerlen);
208 if (n < 0) {
231 if (n < 0) {
209 syslog(LOG_ERR, "recvfrom: %m");
232 tftp_log(LOG_ERR, "recvfrom: %s", strerror(errno));
210 exit(1);
211 }
233 exit(1);
234 }
235 getnameinfo((struct sockaddr *)&peer_sock, peer_sock.ss_len,
236 peername, sizeof(peername), NULL, 0, NI_NUMERICHOST);
237
212 /*
213 * Now that we have read the message out of the UDP
214 * socket, we fork and exit. Thus, inetd will go back
215 * to listening to the tftp port, and the next request
216 * to come in will start up a new instance of tftpd.
217 *
218 * We do this so that inetd can run tftpd in "wait" mode.
219 * The problem with tftpd running in "nowait" mode is that

--- 15 unchanged lines hidden (view full) ---

235 *
236 * This may drop some request, but those
237 * will be resent by the clients when
238 * they timeout. The positive effect of
239 * this flush is to (try to) prevent more
240 * than one tftpd being started up to service
241 * a single request from a single client.
242 */
238 /*
239 * Now that we have read the message out of the UDP
240 * socket, we fork and exit. Thus, inetd will go back
241 * to listening to the tftp port, and the next request
242 * to come in will start up a new instance of tftpd.
243 *
244 * We do this so that inetd can run tftpd in "wait" mode.
245 * The problem with tftpd running in "nowait" mode is that

--- 15 unchanged lines hidden (view full) ---

261 *
262 * This may drop some request, but those
263 * will be resent by the clients when
264 * they timeout. The positive effect of
265 * this flush is to (try to) prevent more
266 * than one tftpd being started up to service
267 * a single request from a single client.
268 */
243 fromlen = sizeof from;
244 i = recvfrom(0, buf, sizeof (buf), 0,
245 (struct sockaddr *)&from, &fromlen);
269 peerlen = sizeof peer_sock;
270 i = recvfrom(0, recvbuffer, MAXPKTSIZE, 0,
271 (struct sockaddr *)&peer_sock, &peerlen);
246 if (i > 0) {
247 n = i;
248 }
249 } else {
250 break;
251 }
252 }
253 if (pid < 0) {
272 if (i > 0) {
273 n = i;
274 }
275 } else {
276 break;
277 }
278 }
279 if (pid < 0) {
254 syslog(LOG_ERR, "fork: %m");
280 tftp_log(LOG_ERR, "fork: %s", strerror(errno));
255 exit(1);
256 } else if (pid != 0) {
257 exit(0);
258 }
259 }
260
261 /*
281 exit(1);
282 } else if (pid != 0) {
283 exit(0);
284 }
285 }
286
287 /*
288 * See if the client is allowed to talk to me.
289 * (This needs to be done before the chroot())
290 */
291 {
292 struct request_info req;
293
294 request_init(&req, RQ_CLIENT_ADDR, peername, 0);
295 request_set(&req, RQ_DAEMON, "tftpd", 0);
296
297 if (hosts_access(&req) == 0) {
298 if (debug&DEBUG_ACCESS)
299 tftp_log(LOG_WARNING,
300 "Access denied by 'tftpd' entry "
301 "in /etc/hosts.allow");
302
303 /*
304 * Full access might be disabled, but maybe the
305 * client is allowed to do read-only access.
306 */
307 request_set(&req, RQ_DAEMON, "tftpd-ro", 0);
308 allow_ro = hosts_access(&req);
309
310 request_set(&req, RQ_DAEMON, "tftpd-wo", 0);
311 allow_wo = hosts_access(&req);
312
313 if (allow_ro == 0 && allow_wo == 0) {
314 tftp_log(LOG_WARNING,
315 "Unauthorized access from %s", peername);
316 exit(1);
317 }
318
319 if (debug&DEBUG_ACCESS) {
320 if (allow_ro)
321 tftp_log(LOG_WARNING,
322 "But allowed readonly access "
323 "via 'tftpd-ro' entry");
324 if (allow_wo)
325 tftp_log(LOG_WARNING,
326 "But allowed writeonly access "
327 "via 'tftpd-wo' entry");
328 }
329 } else
330 if (debug&DEBUG_ACCESS)
331 tftp_log(LOG_WARNING,
332 "Full access allowed"
333 "in /etc/hosts.allow");
334 }
335
336 /*
262 * Since we exit here, we should do that only after the above
263 * recvfrom to keep inetd from constantly forking should there
264 * be a problem. See the above comment about system clogging.
265 */
266 if (chroot_dir) {
267 if (ipchroot > 0) {
268 char *tempchroot;
269 struct stat sb;
270 int statret;
271 struct sockaddr_storage ss;
272 char hbuf[NI_MAXHOST];
273
337 * Since we exit here, we should do that only after the above
338 * recvfrom to keep inetd from constantly forking should there
339 * be a problem. See the above comment about system clogging.
340 */
341 if (chroot_dir) {
342 if (ipchroot > 0) {
343 char *tempchroot;
344 struct stat sb;
345 int statret;
346 struct sockaddr_storage ss;
347 char hbuf[NI_MAXHOST];
348
274 memcpy(&ss, &from, from.ss_len);
349 statret = -1;
350 memcpy(&ss, &peer_sock, peer_sock.ss_len);
275 unmappedaddr((struct sockaddr_in6 *)&ss);
276 getnameinfo((struct sockaddr *)&ss, ss.ss_len,
277 hbuf, sizeof(hbuf), NULL, 0,
278 NI_NUMERICHOST);
279 asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
280 if (ipchroot == 2)
281 statret = stat(tempchroot, &sb);
282 if (ipchroot == 1 ||
283 (statret == 0 && (sb.st_mode & S_IFDIR)))
284 chroot_dir = tempchroot;
285 }
286 /* Must get this before chroot because /etc might go away */
287 if ((nobody = getpwnam(chuser)) == NULL) {
351 unmappedaddr((struct sockaddr_in6 *)&ss);
352 getnameinfo((struct sockaddr *)&ss, ss.ss_len,
353 hbuf, sizeof(hbuf), NULL, 0,
354 NI_NUMERICHOST);
355 asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
356 if (ipchroot == 2)
357 statret = stat(tempchroot, &sb);
358 if (ipchroot == 1 ||
359 (statret == 0 && (sb.st_mode & S_IFDIR)))
360 chroot_dir = tempchroot;
361 }
362 /* Must get this before chroot because /etc might go away */
363 if ((nobody = getpwnam(chuser)) == NULL) {
288 syslog(LOG_ERR, "%s: no such user", chuser);
364 tftp_log(LOG_ERR, "%s: no such user", chuser);
289 exit(1);
290 }
291 if (chroot(chroot_dir)) {
365 exit(1);
366 }
367 if (chroot(chroot_dir)) {
292 syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
368 tftp_log(LOG_ERR, "chroot: %s: %s",
369 chroot_dir, strerror(errno));
293 exit(1);
294 }
295 chdir("/");
296 setgroups(1, &nobody->pw_gid);
297 setuid(nobody->pw_uid);
298 }
299
370 exit(1);
371 }
372 chdir("/");
373 setgroups(1, &nobody->pw_gid);
374 setuid(nobody->pw_uid);
375 }
376
300 len = sizeof(me);
301 if (getsockname(0, (struct sockaddr *)&me, &len) == 0) {
302 switch (me.ss_family) {
377 len = sizeof(me_sock);
378 if (getsockname(0, (struct sockaddr *)&me_sock, &len) == 0) {
379 switch (me_sock.ss_family) {
303 case AF_INET:
380 case AF_INET:
304 ((struct sockaddr_in *)&me)->sin_port = 0;
381 ((struct sockaddr_in *)&me_sock)->sin_port = 0;
305 break;
306 case AF_INET6:
382 break;
383 case AF_INET6:
307 ((struct sockaddr_in6 *)&me)->sin6_port = 0;
384 ((struct sockaddr_in6 *)&me_sock)->sin6_port = 0;
308 break;
309 default:
310 /* unsupported */
311 break;
312 }
313 } else {
385 break;
386 default:
387 /* unsupported */
388 break;
389 }
390 } else {
314 memset(&me, 0, sizeof(me));
315 me.ss_family = from.ss_family;
316 me.ss_len = from.ss_len;
391 memset(&me_sock, 0, sizeof(me_sock));
392 me_sock.ss_family = peer_sock.ss_family;
393 me_sock.ss_len = peer_sock.ss_len;
317 }
394 }
318 alarm(0);
319 close(0);
320 close(1);
395 close(0);
396 close(1);
321 peer = socket(from.ss_family, SOCK_DGRAM, 0);
397 peer = socket(peer_sock.ss_family, SOCK_DGRAM, 0);
322 if (peer < 0) {
398 if (peer < 0) {
323 syslog(LOG_ERR, "socket: %m");
399 tftp_log(LOG_ERR, "socket: %s", strerror(errno));
324 exit(1);
325 }
400 exit(1);
401 }
326 if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
327 syslog(LOG_ERR, "bind: %m");
402 if (bind(peer, (struct sockaddr *)&me_sock, me_sock.ss_len) < 0) {
403 tftp_log(LOG_ERR, "bind: %s", strerror(errno));
328 exit(1);
329 }
404 exit(1);
405 }
330 if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
331 syslog(LOG_ERR, "connect: %m");
332 exit(1);
333 }
334 tp = (struct tftphdr *)buf;
406
407 tp = (struct tftphdr *)recvbuffer;
335 tp->th_opcode = ntohs(tp->th_opcode);
408 tp->th_opcode = ntohs(tp->th_opcode);
336 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
337 tftp(tp, n);
409 if (tp->th_opcode == RRQ) {
410 if (allow_ro)
411 tftp_rrq(peer, tp->th_stuff, n - 1);
412 else {
413 tftp_log(LOG_WARNING,
414 "%s read access denied", peername);
415 exit(1);
416 }
417 }
418 if (tp->th_opcode == WRQ) {
419 if (allow_wo)
420 tftp_wrq(peer, tp->th_stuff, n - 1);
421 else {
422 tftp_log(LOG_WARNING,
423 "%s write access denied", peername);
424 exit(1);
425 }
426 }
338 exit(1);
339}
340
341static void
342reduce_path(char *fn)
343{
344 char *slash, *ptr;
345

--- 18 unchanged lines hidden (view full) ---

364 if (ptr < fn)
365 break;
366 slash += 3;
367 while (*slash)
368 *++ptr = *++slash;
369 }
370}
371
427 exit(1);
428}
429
430static void
431reduce_path(char *fn)
432{
433 char *slash, *ptr;
434

--- 18 unchanged lines hidden (view full) ---

453 if (ptr < fn)
454 break;
455 slash += 3;
456 while (*slash)
457 *++ptr = *++slash;
458 }
459}
460
372struct formats;
373int validate_access(char **, int);
374void xmitfile(struct formats *);
375void recvfile(struct formats *);
461static char *
462parse_header(int peer, char *recvbuffer, ssize_t size,
463 char **filename, char **mode)
464{
465 char *cp;
466 int i;
467 struct formats *pf;
376
468
377struct formats {
378 const char *f_mode;
379 int (*f_validate)(char **, int);
380 void (*f_send)(struct formats *);
381 void (*f_recv)(struct formats *);
382 int f_convert;
383} formats[] = {
384 { "netascii", validate_access, xmitfile, recvfile, 1 },
385 { "octet", validate_access, xmitfile, recvfile, 0 },
386#ifdef notdef
387 { "mail", validate_user, sendmail, recvmail, 1 },
388#endif
389 { 0, NULL, NULL, NULL, 0 }
390};
469 *mode = NULL;
470 cp = recvbuffer;
391
471
392struct options {
393 const char *o_type;
394 char *o_request;
395 int o_reply; /* turn into union if need be */
396} options[] = {
397 { "tsize", NULL, 0 }, /* OPT_TSIZE */
398 { "timeout", NULL, 0 }, /* OPT_TIMEOUT */
399 { NULL, NULL, 0 }
400};
472 i = get_field(peer, recvbuffer, size);
473 if (i >= PATH_MAX) {
474 tftp_log(LOG_ERR, "Bad option - filename too long");
475 send_error(peer, EBADOP);
476 exit(1);
477 }
478 *filename = recvbuffer;
479 tftp_log(LOG_INFO, "Filename: '%s'", *filename);
480 cp += i;
401
481
402enum opt_enum {
403 OPT_TSIZE = 0,
404 OPT_TIMEOUT,
405};
482 i = get_field(peer, cp, size);
483 *mode = cp;
484 cp += i;
406
485
486 /* Find the file transfer mode */
487 for (cp = *mode; *cp; cp++)
488 if (isupper(*cp))
489 *cp = tolower(*cp);
490 for (pf = formats; pf->f_mode; pf++)
491 if (strcmp(pf->f_mode, *mode) == 0)
492 break;
493 if (pf->f_mode == NULL) {
494 tftp_log(LOG_ERR,
495 "Bad option - Unknown transfer mode (%s)", *mode);
496 send_error(peer, EBADOP);
497 exit(1);
498 }
499 tftp_log(LOG_INFO, "Mode: '%s'", *mode);
500
501 return (cp + 1);
502}
503
407/*
504/*
408 * Handle initial connection protocol.
505 * WRQ - receive a file from the client
409 */
410void
506 */
507void
411tftp(struct tftphdr *tp, int size)
508tftp_wrq(int peer, char *recvbuffer, ssize_t size)
412{
413 char *cp;
509{
510 char *cp;
414 int i, first = 1, has_options = 0, ecode;
415 struct formats *pf;
416 char *filename, *mode, *option, *ccp;
511 int has_options = 0, ecode;
512 char *filename, *mode;
417 char fnbuf[PATH_MAX];
418
513 char fnbuf[PATH_MAX];
514
419 cp = tp->th_stuff;
420again:
421 while (cp < buf + size) {
422 if (*cp == '\0')
423 break;
424 cp++;
425 }
426 if (*cp != '\0') {
427 nak(EBADOP);
428 exit(1);
429 }
430 i = cp - tp->th_stuff;
431 if (i >= sizeof(fnbuf)) {
432 nak(EBADOP);
433 exit(1);
434 }
435 memcpy(fnbuf, tp->th_stuff, i);
436 fnbuf[i] = '\0';
515 cp = parse_header(peer, recvbuffer, size, &filename, &mode);
516 size -= (cp - recvbuffer) + 1;
517
518 strcpy(fnbuf, filename);
437 reduce_path(fnbuf);
438 filename = fnbuf;
519 reduce_path(fnbuf);
520 filename = fnbuf;
439 if (first) {
440 mode = ++cp;
441 first = 0;
442 goto again;
521
522 if (size > 0) {
523 if (options_rfc_enabled)
524 has_options = !parse_options(peer, cp, size);
525 else
526 tftp_log(LOG_INFO, "Options found but not enabled");
443 }
527 }
444 for (cp = mode; *cp; cp++)
445 if (isupper(*cp))
446 *cp = tolower(*cp);
447 for (pf = formats; pf->f_mode; pf++)
448 if (strcmp(pf->f_mode, mode) == 0)
449 break;
450 if (pf->f_mode == 0) {
451 nak(EBADOP);
452 exit(1);
528
529 ecode = validate_access(peer, &filename, WRQ);
530 if (ecode == 0) {
531 if (has_options)
532 send_oack(peer);
533 else
534 send_ack(peer, 0);
453 }
535 }
454 while (++cp < buf + size) {
455 for (i = 2, ccp = cp; i > 0; ccp++) {
456 if (ccp >= buf + size) {
457 /*
458 * Don't reject the request, just stop trying
459 * to parse the option and get on with it.
460 * Some Apple Open Firmware versions have
461 * trailing garbage on the end of otherwise
462 * valid requests.
463 */
464 goto option_fail;
465 } else if (*ccp == '\0')
466 i--;
467 }
468 for (option = cp; *cp; cp++)
469 if (isupper(*cp))
470 *cp = tolower(*cp);
471 for (i = 0; options[i].o_type != NULL; i++)
472 if (strcmp(option, options[i].o_type) == 0) {
473 options[i].o_request = ++cp;
474 has_options = 1;
475 }
476 cp = ccp-1;
536 if (logging) {
537 tftp_log(LOG_INFO, "%s: write request for %s: %s", peername,
538 filename, errtomsg(ecode));
477 }
478
539 }
540
479option_fail:
480 if (options[OPT_TIMEOUT].o_request) {
481 int to = atoi(options[OPT_TIMEOUT].o_request);
482 if (to < 1 || to > 255) {
483 nak(EBADOP);
484 exit(1);
485 }
486 else if (to <= max_rexmtval)
487 options[OPT_TIMEOUT].o_reply = rexmtval = to;
541 tftp_recvfile(peer, mode);
542 exit(0);
543}
544
545/*
546 * RRQ - send a file to the client
547 */
548void
549tftp_rrq(int peer, char *recvbuffer, ssize_t size)
550{
551 char *cp;
552 int has_options = 0, ecode;
553 char *filename, *mode;
554 char fnbuf[PATH_MAX];
555
556 cp = parse_header(peer, recvbuffer, size, &filename, &mode);
557 size -= (cp - recvbuffer) + 1;
558
559 strcpy(fnbuf, filename);
560 reduce_path(fnbuf);
561 filename = fnbuf;
562
563 if (size > 0) {
564 if (options_rfc_enabled)
565 has_options = !parse_options(peer, cp, size);
488 else
566 else
489 options[OPT_TIMEOUT].o_request = NULL;
567 tftp_log(LOG_INFO, "Options found but not enabled");
490 }
491
568 }
569
492 ecode = (*pf->f_validate)(&filename, tp->th_opcode);
493 if (has_options && ecode == 0)
494 oack();
495 if (logging) {
496 char hbuf[NI_MAXHOST];
570 ecode = validate_access(peer, &filename, RRQ);
571 if (ecode == 0) {
572 if (has_options) {
573 int n;
574 char lrecvbuffer[MAXPKTSIZE];
575 struct tftphdr *rp = (struct tftphdr *)lrecvbuffer;
497
576
498 getnameinfo((struct sockaddr *)&from, from.ss_len,
499 hbuf, sizeof(hbuf), NULL, 0, 0);
500 syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf,
501 tp->th_opcode == WRQ ? "write" : "read",
502 filename, errtomsg(ecode));
577 send_oack(peer);
578 n = receive_packet(peer, lrecvbuffer, MAXPKTSIZE,
579 NULL, timeoutpacket);
580 if (n < 0) {
581 if (debug&DEBUG_SIMPLE)
582 tftp_log(LOG_DEBUG, "Aborting: %s",
583 rp_strerror(n));
584 return;
585 }
586 if (rp->th_opcode != ACK) {
587 if (debug&DEBUG_SIMPLE)
588 tftp_log(LOG_DEBUG,
589 "Expected ACK, got %s on OACK",
590 packettype(rp->th_opcode));
591 return;
592 }
593 }
503 }
594 }
595
596 if (logging)
597 tftp_log(LOG_INFO, "%s: read request for %s: %s", peername,
598 filename, errtomsg(ecode));
599
504 if (ecode) {
505 /*
506 * Avoid storms of naks to a RRQ broadcast for a relative
507 * bootfile pathname from a diskless Sun.
508 */
509 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
510 exit(0);
600 if (ecode) {
601 /*
602 * Avoid storms of naks to a RRQ broadcast for a relative
603 * bootfile pathname from a diskless Sun.
604 */
605 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
606 exit(0);
511 nak(ecode);
607 tftp_log(LOG_ERR, "Prevent NAK storm");
608 send_error(peer, ecode);
512 exit(1);
513 }
609 exit(1);
610 }
514 if (tp->th_opcode == WRQ)
515 (*pf->f_recv)(pf);
516 else
517 (*pf->f_send)(pf);
518 exit(0);
611 tftp_xmitfile(peer, mode);
519}
520
612}
613
521
522FILE *file;
523
524/*
525 * Find the next value for YYYYMMDD.nn when the file to be written should
526 * be unique. Due to the limitations of nn, we will fail if nn reaches 100.
527 * Besides, that is four updates per hour on a file, which is kind of
528 * execessive anyway.
529 */
530static int
531find_next_name(char *filename, int *fd)
532{
533 int i;
534 time_t tval;
535 size_t len;
536 struct tm lt;
537 char yyyymmdd[MAXPATHLEN];
538 char newname[MAXPATHLEN];
614/*
615 * Find the next value for YYYYMMDD.nn when the file to be written should
616 * be unique. Due to the limitations of nn, we will fail if nn reaches 100.
617 * Besides, that is four updates per hour on a file, which is kind of
618 * execessive anyway.
619 */
620static int
621find_next_name(char *filename, int *fd)
622{
623 int i;
624 time_t tval;
625 size_t len;
626 struct tm lt;
627 char yyyymmdd[MAXPATHLEN];
628 char newname[MAXPATHLEN];
539 struct stat sb;
540 int ret;
541
542 /* Create the YYYYMMDD part of the filename */
543 time(&tval);
544 lt = *localtime(&tval);
545 len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, &lt);
546 if (len == 0) {
547 syslog(LOG_WARNING,
548 "Filename suffix too long (%d characters maximum)",
549 MAXPATHLEN);
550 return (EACCESS);
551 }
552
553 /* Make sure the new filename is not too long */
554 if (strlen(filename) > MAXPATHLEN - len - 5) {
555 syslog(LOG_WARNING,
629
630 /* Create the YYYYMMDD part of the filename */
631 time(&tval);
632 lt = *localtime(&tval);
633 len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, &lt);
634 if (len == 0) {
635 syslog(LOG_WARNING,
636 "Filename suffix too long (%d characters maximum)",
637 MAXPATHLEN);
638 return (EACCESS);
639 }
640
641 /* Make sure the new filename is not too long */
642 if (strlen(filename) > MAXPATHLEN - len - 5) {
643 syslog(LOG_WARNING,
556 "Filename too long (%d characters, %d maximum)",
644 "Filename too long (%zd characters, %zd maximum)",
557 strlen(filename), MAXPATHLEN - len - 5);
558 return (EACCESS);
559 }
560
561 /* Find the first file which doesn't exist */
562 for (i = 0; i < 100; i++) {
563 sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i);
564 *fd = open(newname,

--- 14 unchanged lines hidden (view full) ---

579 * readable/writable.
580 * If we were invoked with arguments
581 * from inetd then the file must also be
582 * in one of the given directory prefixes.
583 * Note also, full path name must be
584 * given as we have no login directory.
585 */
586int
645 strlen(filename), MAXPATHLEN - len - 5);
646 return (EACCESS);
647 }
648
649 /* Find the first file which doesn't exist */
650 for (i = 0; i < 100; i++) {
651 sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i);
652 *fd = open(newname,

--- 14 unchanged lines hidden (view full) ---

667 * readable/writable.
668 * If we were invoked with arguments
669 * from inetd then the file must also be
670 * in one of the given directory prefixes.
671 * Note also, full path name must be
672 * given as we have no login directory.
673 */
674int
587validate_access(char **filep, int mode)
675validate_access(int peer, char **filep, int mode)
588{
589 struct stat stbuf;
590 int fd;
591 int error;
592 struct dirlist *dirp;
593 static char pathname[MAXPATHLEN];
594 char *filename = *filep;
595

--- 59 unchanged lines hidden (view full) ---

655 err = EACCESS;
656 }
657 }
658 if (dirp->name != NULL)
659 *filep = filename = pathname;
660 else if (mode == RRQ)
661 return (err);
662 }
676{
677 struct stat stbuf;
678 int fd;
679 int error;
680 struct dirlist *dirp;
681 static char pathname[MAXPATHLEN];
682 char *filename = *filep;
683

--- 59 unchanged lines hidden (view full) ---

743 err = EACCESS;
744 }
745 }
746 if (dirp->name != NULL)
747 *filep = filename = pathname;
748 else if (mode == RRQ)
749 return (err);
750 }
663 if (options[OPT_TSIZE].o_request) {
664 if (mode == RRQ)
665 options[OPT_TSIZE].o_reply = stbuf.st_size;
666 else
667 /* XXX Allows writes of all sizes. */
668 options[OPT_TSIZE].o_reply =
669 atoi(options[OPT_TSIZE].o_request);
670 }
751
752 /*
753 * This option is handled here because it (might) require(s) the
754 * size of the file.
755 */
756 option_tsize(peer, NULL, mode, &stbuf);
757
671 if (mode == RRQ)
672 fd = open(filename, O_RDONLY);
673 else {
674 if (create_new) {
675 if (increase_name) {
676 error = find_next_name(filename, &fd);
677 if (error > 0)
678 return (error + 100);

--- 10 unchanged lines hidden (view full) ---

689 file = fdopen(fd, (mode == RRQ)? "r":"w");
690 if (file == NULL) {
691 close(fd);
692 return (errno + 100);
693 }
694 return (0);
695}
696
758 if (mode == RRQ)
759 fd = open(filename, O_RDONLY);
760 else {
761 if (create_new) {
762 if (increase_name) {
763 error = find_next_name(filename, &fd);
764 if (error > 0)
765 return (error + 100);

--- 10 unchanged lines hidden (view full) ---

776 file = fdopen(fd, (mode == RRQ)? "r":"w");
777 if (file == NULL) {
778 close(fd);
779 return (errno + 100);
780 }
781 return (0);
782}
783
697int timeouts;
698jmp_buf timeoutbuf;
699
700void
701timer(int sig __unused)
784static void
785tftp_xmitfile(int peer, const char *mode)
702{
786{
703 if (++timeouts > MAX_TIMEOUTS)
704 exit(1);
705 longjmp(timeoutbuf, 1);
706}
787 uint16_t block;
788 uint32_t amount;
789 time_t now;
790 struct tftp_stats ts;
707
791
708/*
709 * Send the requested file.
710 */
711void
712xmitfile(struct formats *pf)
713{
714 struct tftphdr *dp;
715 struct tftphdr *ap; /* ack packet */
716 int size, n;
717 volatile unsigned short block;
792 now = time(NULL);
793 if (debug&DEBUG_SIMPLE)
794 tftp_log(LOG_DEBUG, "Transmitting file");
718
795
719 signal(SIGALRM, timer);
720 dp = r_init();
721 ap = (struct tftphdr *)ackbuf;
796 read_init(0, file, mode);
722 block = 1;
797 block = 1;
723 do {
724 size = readit(file, &dp, pf->f_convert);
725 if (size < 0) {
726 nak(errno + 100);
727 goto abort;
728 }
729 dp->th_opcode = htons((u_short)DATA);
730 dp->th_block = htons((u_short)block);
731 timeouts = 0;
732 (void)setjmp(timeoutbuf);
733
734send_data:
735 {
736 int i, t = 1;
737 for (i = 0; ; i++){
738 if (send(peer, dp, size + 4, 0) != size + 4) {
739 sleep(t);
740 t = (t < 32) ? t<< 1 : t;
741 if (i >= 12) {
742 syslog(LOG_ERR, "write: %m");
743 goto abort;
744 }
745 }
746 break;
747 }
748 }
749 read_ahead(file, pf->f_convert);
750 for ( ; ; ) {
751 alarm(rexmtval); /* read the ack */
752 n = recv(peer, ackbuf, sizeof (ackbuf), 0);
753 alarm(0);
754 if (n < 0) {
755 syslog(LOG_ERR, "read: %m");
756 goto abort;
757 }
758 ap->th_opcode = ntohs((u_short)ap->th_opcode);
759 ap->th_block = ntohs((u_short)ap->th_block);
760
761 if (ap->th_opcode == ERROR)
762 goto abort;
763
764 if (ap->th_opcode == ACK) {
765 if (ap->th_block == block)
766 break;
767 /* Re-synchronize with the other side */
768 (void) synchnet(peer);
769 if (ap->th_block == (block -1))
770 goto send_data;
771 }
772
773 }
774 block++;
775 } while (size == SEGSIZE);
776abort:
777 (void) fclose(file);
798 tftp_send(peer, &block, &ts);
799 read_close();
800 if (debug&DEBUG_SIMPLE)
801 tftp_log(LOG_INFO, "Sent %d bytes in %d seconds",
802 amount, time(NULL) - now);
778}
779
803}
804
780void
781justquit(int sig __unused)
805static void
806tftp_recvfile(int peer, const char *mode)
782{
807{
783 exit(0);
784}
808 uint32_t filesize;
809 uint16_t block;
810 struct timeval now1, now2;
811 struct tftp_stats ts;
785
812
813 gettimeofday(&now1, NULL);
814 if (debug&DEBUG_SIMPLE)
815 tftp_log(LOG_DEBUG, "Receiving file");
786
816
787/*
788 * Receive a file.
789 */
790void
791recvfile(struct formats *pf)
792{
793 struct tftphdr *dp;
794 struct tftphdr *ap; /* ack buffer */
795 int n, size;
796 volatile unsigned short block;
817 write_init(0, file, mode);
797
818
798 signal(SIGALRM, timer);
799 dp = w_init();
800 ap = (struct tftphdr *)ackbuf;
801 block = 0;
819 block = 0;
802 do {
803 timeouts = 0;
804 ap->th_opcode = htons((u_short)ACK);
805 ap->th_block = htons((u_short)block);
806 block++;
807 (void) setjmp(timeoutbuf);
808send_ack:
809 if (send(peer, ackbuf, 4, 0) != 4) {
810 syslog(LOG_ERR, "write: %m");
811 goto abort;
812 }
813 write_behind(file, pf->f_convert);
814 for ( ; ; ) {
815 alarm(rexmtval);
816 n = recv(peer, dp, PKTSIZE, 0);
817 alarm(0);
818 if (n < 0) { /* really? */
819 syslog(LOG_ERR, "read: %m");
820 goto abort;
821 }
822 dp->th_opcode = ntohs((u_short)dp->th_opcode);
823 dp->th_block = ntohs((u_short)dp->th_block);
824 if (dp->th_opcode == ERROR)
825 goto abort;
826 if (dp->th_opcode == DATA) {
827 if (dp->th_block == block) {
828 break; /* normal */
829 }
830 /* Re-synchronize with the other side */
831 (void) synchnet(peer);
832 if (dp->th_block == (block-1))
833 goto send_ack; /* rexmit */
834 }
835 }
836 /* size = write(file, dp->th_data, n - 4); */
837 size = writeit(file, &dp, n - 4, pf->f_convert);
838 if (size != (n-4)) { /* ahem */
839 if (size < 0) nak(errno + 100);
840 else nak(ENOSPACE);
841 goto abort;
842 }
843 } while (size == SEGSIZE);
844 write_behind(file, pf->f_convert);
845 (void) fclose(file); /* close data file */
820 tftp_receive(peer, &block, &ts, NULL, 0);
846
821
847 ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
848 ap->th_block = htons((u_short)(block));
849 (void) send(peer, ackbuf, 4, 0);
822 write_close();
850
823
851 signal(SIGALRM, justquit); /* just quit on timeout */
852 alarm(rexmtval);
853 n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
854 alarm(0);
855 if (n >= 4 && /* if read some data */
856 dp->th_opcode == DATA && /* and got a data block */
857 block == dp->th_block) { /* then my last ack was lost */
858 (void) send(peer, ackbuf, 4, 0); /* resend final ack */
859 }
860abort:
861 return;
862}
863
864struct errmsg {
865 int e_code;
866 const char *e_msg;
867} errmsgs[] = {
868 { EUNDEF, "Undefined error code" },
869 { ENOTFOUND, "File not found" },
870 { EACCESS, "Access violation" },
871 { ENOSPACE, "Disk full or allocation exceeded" },
872 { EBADOP, "Illegal TFTP operation" },
873 { EBADID, "Unknown transfer ID" },
874 { EEXISTS, "File already exists" },
875 { ENOUSER, "No such user" },
876 { EOPTNEG, "Option negotiation" },
877 { -1, 0 }
878};
879
880static const char *
881errtomsg(int error)
882{
883 static char ebuf[20];
884 struct errmsg *pe;
885 if (error == 0)
886 return "success";
887 for (pe = errmsgs; pe->e_code >= 0; pe++)
888 if (pe->e_code == error)
889 return pe->e_msg;
890 snprintf(ebuf, sizeof(buf), "error %d", error);
891 return ebuf;
892}
893
894/*
895 * Send a nak packet (error message).
896 * Error code passed in is one of the
897 * standard TFTP codes, or a UNIX errno
898 * offset by 100.
899 */
900static void
901nak(int error)
902{
903 struct tftphdr *tp;
904 int length;
905 struct errmsg *pe;
906
907 tp = (struct tftphdr *)buf;
908 tp->th_opcode = htons((u_short)ERROR);
909 tp->th_code = htons((u_short)error);
910 for (pe = errmsgs; pe->e_code >= 0; pe++)
911 if (pe->e_code == error)
912 break;
913 if (pe->e_code < 0) {
914 pe->e_msg = strerror(error - 100);
915 tp->th_code = EUNDEF; /* set 'undef' errorcode */
916 }
917 strcpy(tp->th_msg, pe->e_msg);
918 length = strlen(pe->e_msg);
919 tp->th_msg[length] = '\0';
920 length += 5;
921 if (send(peer, buf, length, 0) != length)
922 syslog(LOG_ERR, "nak: %m");
923}
924
925/* translate IPv4 mapped IPv6 address to IPv4 address */
926static void
927unmappedaddr(struct sockaddr_in6 *sin6)
928{
929 struct sockaddr_in *sin4;
930 u_int32_t addr;
931 int port;
932
933 if (sin6->sin6_family != AF_INET6 ||
934 !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
935 return;
936 sin4 = (struct sockaddr_in *)sin6;
937 addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
938 port = sin6->sin6_port;
939 memset(sin4, 0, sizeof(struct sockaddr_in));
940 sin4->sin_addr.s_addr = addr;
941 sin4->sin_port = port;
942 sin4->sin_family = AF_INET;
943 sin4->sin_len = sizeof(struct sockaddr_in);
944}
945
946/*
947 * Send an oack packet (option acknowledgement).
948 */
949static void
950oack(void)
951{
952 struct tftphdr *tp, *ap;
953 int size, i, n;
954 char *bp;
955
956 tp = (struct tftphdr *)buf;
957 bp = buf + 2;
958 size = sizeof(buf) - 2;
959 tp->th_opcode = htons((u_short)OACK);
960 for (i = 0; options[i].o_type != NULL; i++) {
961 if (options[i].o_request) {
962 n = snprintf(bp, size, "%s%c%d", options[i].o_type,
963 0, options[i].o_reply);
964 bp += n+1;
965 size -= n+1;
966 if (size < 0) {
967 syslog(LOG_ERR, "oack: buffer overflow");
968 exit(1);
969 }
824 if (debug&DEBUG_SIMPLE) {
825 double f;
826 if (now1.tv_usec > now2.tv_usec) {
827 now2.tv_usec += 1000000;
828 now2.tv_sec--;
970 }
829 }
971 }
972 size = bp - buf;
973 ap = (struct tftphdr *)ackbuf;
974 signal(SIGALRM, timer);
975 timeouts = 0;
976
830
977 (void)setjmp(timeoutbuf);
978 if (send(peer, buf, size, 0) != size) {
979 syslog(LOG_INFO, "oack: %m");
980 exit(1);
831 f = now2.tv_sec - now1.tv_sec +
832 (now2.tv_usec - now1.tv_usec) / 100000.0;
833 tftp_log(LOG_INFO,
834 "Download of %d bytes in %d blocks completed after %0.1f seconds\n",
835 filesize, block, f);
981 }
982
836 }
837
983 for (;;) {
984 alarm(rexmtval);
985 n = recv(peer, ackbuf, sizeof (ackbuf), 0);
986 alarm(0);
987 if (n < 0) {
988 syslog(LOG_ERR, "recv: %m");
989 exit(1);
990 }
991 ap->th_opcode = ntohs((u_short)ap->th_opcode);
992 ap->th_block = ntohs((u_short)ap->th_block);
993 if (ap->th_opcode == ERROR)
994 exit(1);
995 if (ap->th_opcode == ACK && ap->th_block == 0)
996 break;
997 }
838 return;
998}
839}
840