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