1 /* $NetBSD: tftpd.c,v 1.16 1999/02/07 21:38:44 aidan Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #if 0 41 static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93"; 42 #else 43 __RCSID("$NetBSD: tftpd.c,v 1.16 1999/02/07 21:38:44 aidan Exp $"); 44 #endif 45 #endif /* not lint */ 46 47 /* 48 * Trivial file transfer protocol server. 49 * 50 * This version includes many modifications by Jim Guyton 51 * <guyton@rand-unix>. 52 */ 53 54 #include <sys/param.h> 55 #include <sys/ioctl.h> 56 #include <sys/stat.h> 57 #include <sys/socket.h> 58 59 #include <signal.h> 60 #include <fcntl.h> 61 62 #include <netinet/in.h> 63 #include <arpa/tftp.h> 64 #include <arpa/inet.h> 65 66 #include <ctype.h> 67 #include <errno.h> 68 #include <fcntl.h> 69 #include <grp.h> 70 #include <netdb.h> 71 #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> 78 #include <unistd.h> 79 80 #include "tftpsubs.h" 81 82 #define DEFAULTUSER "nobody" 83 84 #define TIMEOUT 5 85 86 extern char *__progname; 87 int peer; 88 int rexmtval = TIMEOUT; 89 int maxtimeout = 5*TIMEOUT; 90 91 #define PKTSIZE SEGSIZE+4 92 char buf[PKTSIZE]; 93 char ackbuf[PKTSIZE]; 94 struct sockaddr_in from; 95 int fromlen; 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 105 static struct dirlist { 106 char *name; 107 int len; 108 } dirs[MAXDIRS+1]; 109 static int suppress_naks; 110 static int logging; 111 static int secure; 112 static char *securedir; 113 114 struct formats; 115 116 static void tftp __P((struct tftphdr *, int)); 117 static const char *errtomsg __P((int)); 118 static void nak __P((int)); 119 static char *verifyhost __P((struct sockaddr_in *)); 120 static void usage __P((void)); 121 void timer __P((int)); 122 void sendfile __P((struct formats *)); 123 void recvfile __P((struct formats *)); 124 void justquit __P((int)); 125 int validate_access __P((char **, int)); 126 int main __P((int, char **)); 127 128 struct formats { 129 char *f_mode; 130 int (*f_validate) __P((char **, int)); 131 void (*f_send) __P((struct formats *)); 132 void (*f_recv) __P((struct formats *)); 133 int f_convert; 134 } formats[] = { 135 { "netascii", validate_access, sendfile, recvfile, 1 }, 136 { "octet", validate_access, sendfile, recvfile, 0 }, 137 { 0 } 138 }; 139 140 static void 141 usage() 142 { 143 syslog(LOG_ERR, 144 "Usage: %s [-ln] [-u user] [-g group] [-s directory] [directory ...]", 145 __progname); 146 exit(1); 147 } 148 149 int 150 main(argc, argv) 151 int argc; 152 char **argv; 153 { 154 struct passwd *pwent; 155 struct group *grent; 156 struct tftphdr *tp; 157 int n = 0; 158 int ch, on; 159 int fd = 0; 160 struct sockaddr_in sin; 161 int len; 162 char *tgtuser, *tgtgroup, *ep; 163 uid_t curuid, tgtuid; 164 gid_t curgid, tgtgid; 165 long nid; 166 167 openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 168 tgtuser = DEFAULTUSER; 169 tgtgroup = NULL; 170 curuid = getuid(); 171 curgid = getgid(); 172 173 while ((ch = getopt(argc, argv, "g:lns:u:")) != -1) 174 switch (ch) { 175 176 case 'g': 177 tgtgroup = optarg; 178 break; 179 180 case 'l': 181 logging = 1; 182 break; 183 184 case 'n': 185 suppress_naks = 1; 186 break; 187 188 case 's': 189 secure = 1; 190 securedir = optarg; 191 break; 192 193 case 'u': 194 tgtuser = optarg; 195 break; 196 197 default: 198 usage(); 199 break; 200 } 201 202 if (optind < argc) { 203 struct dirlist *dirp; 204 205 /* Get list of directory prefixes. Skip relative pathnames. */ 206 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS]; 207 optind++) { 208 if (argv[optind][0] == '/') { 209 dirp->name = argv[optind]; 210 dirp->len = strlen(dirp->name); 211 dirp++; 212 } 213 } 214 } 215 216 if (*tgtuser == '\0' || (tgtgroup != NULL && *tgtgroup == '\0')) 217 usage(); 218 219 nid = (strtol(tgtuser, &ep, 10)); 220 if (*ep == '\0') { 221 if (nid > UID_MAX) { 222 syslog(LOG_ERR, "uid %ld is too large", nid); 223 exit(1); 224 } 225 pwent = getpwuid((uid_t)nid); 226 } else 227 pwent = getpwnam(tgtuser); 228 if (pwent == NULL) { 229 syslog(LOG_ERR, "unknown user `%s'", tgtuser); 230 exit(1); 231 } 232 tgtuid = pwent->pw_uid; 233 tgtgid = pwent->pw_gid; 234 235 if (tgtgroup != NULL) { 236 nid = (strtol(tgtgroup, &ep, 10)); 237 if (*ep == '\0') { 238 if (nid > GID_MAX) { 239 syslog(LOG_ERR, "gid %ld is too large", nid); 240 exit(1); 241 } 242 grent = getgrgid((gid_t)nid); 243 } else 244 grent = getgrnam(tgtgroup); 245 if (grent != NULL) 246 tgtgid = grent->gr_gid; 247 else { 248 syslog(LOG_ERR, "unknown group `%s'", tgtgroup); 249 exit(1); 250 } 251 } 252 253 if (secure) { 254 if (chdir(securedir) < 0) { 255 syslog(LOG_ERR, "chdir %s: %m", securedir); 256 exit(1); 257 } 258 if (chroot(".")) { 259 syslog(LOG_ERR, "chroot: %m"); 260 exit(1); 261 } 262 } 263 264 syslog(LOG_DEBUG, "running as user `%s' (%d), group `%s' (%d)", 265 tgtuser, tgtuid, tgtgroup ? tgtgroup : "(unspecified)" , tgtgid); 266 if (curgid != tgtgid) { 267 if (setgid(tgtgid)) { 268 syslog(LOG_ERR, "setgid to %d: %m", (int)tgtgid); 269 exit(1); 270 } 271 if (setgroups(0, NULL)) { 272 syslog(LOG_ERR, "setgroups: %m"); 273 exit(1); 274 } 275 } 276 277 if (curuid != tgtuid) { 278 if (setuid(tgtuid)) { 279 syslog(LOG_ERR, "setuid to %d: %m", (int)tgtuid); 280 exit(1); 281 } 282 } 283 284 on = 1; 285 if (ioctl(fd, FIONBIO, &on) < 0) { 286 syslog(LOG_ERR, "ioctl(FIONBIO): %m"); 287 exit(1); 288 } 289 fromlen = sizeof (from); 290 n = recvfrom(fd, buf, sizeof (buf), 0, 291 (struct sockaddr *)&from, &fromlen); 292 if (n < 0) { 293 syslog(LOG_ERR, "recvfrom: %m"); 294 exit(1); 295 } 296 /* 297 * Now that we have read the message out of the UDP 298 * socket, we fork and exit. Thus, inetd will go back 299 * to listening to the tftp port, and the next request 300 * to come in will start up a new instance of tftpd. 301 * 302 * We do this so that inetd can run tftpd in "wait" mode. 303 * The problem with tftpd running in "nowait" mode is that 304 * inetd may get one or more successful "selects" on the 305 * tftp port before we do our receive, so more than one 306 * instance of tftpd may be started up. Worse, if tftpd 307 * break before doing the above "recvfrom", inetd would 308 * spawn endless instances, clogging the system. 309 */ 310 { 311 int pid; 312 int i, j; 313 314 for (i = 1; i < 20; i++) { 315 pid = fork(); 316 if (pid < 0) { 317 sleep(i); 318 /* 319 * flush out to most recently sent request. 320 * 321 * This may drop some request, but those 322 * will be resent by the clients when 323 * they timeout. The positive effect of 324 * this flush is to (try to) prevent more 325 * than one tftpd being started up to service 326 * a single request from a single client. 327 */ 328 j = sizeof from; 329 i = recvfrom(fd, buf, sizeof (buf), 0, 330 (struct sockaddr *)&from, &j); 331 if (i > 0) { 332 n = i; 333 fromlen = j; 334 } 335 } else { 336 break; 337 } 338 } 339 if (pid < 0) { 340 syslog(LOG_ERR, "fork: %m"); 341 exit(1); 342 } else if (pid != 0) { 343 exit(0); 344 } 345 } 346 347 from.sin_len = sizeof(struct sockaddr_in); 348 from.sin_family = AF_INET; 349 350 /* 351 * remember what address this was sent to, so we can respond on the 352 * same interface 353 */ 354 len = sizeof(sin); 355 if (getsockname(fd, (struct sockaddr *)&sin, &len) == 0) 356 sin.sin_port = 0; 357 else { 358 memset(&sin, 0, sizeof(sin)); 359 sin.sin_family = AF_INET; 360 } 361 362 alarm(0); 363 close(fd); 364 close(1); 365 peer = socket(AF_INET, SOCK_DGRAM, 0); 366 if (peer < 0) { 367 syslog(LOG_ERR, "socket: %m"); 368 exit(1); 369 } 370 if (bind(peer, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 371 syslog(LOG_ERR, "bind: %m"); 372 exit(1); 373 } 374 if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { 375 syslog(LOG_ERR, "connect: %m"); 376 exit(1); 377 } 378 tp = (struct tftphdr *)buf; 379 tp->th_opcode = ntohs(tp->th_opcode); 380 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) 381 tftp(tp, n); 382 exit(1); 383 } 384 385 /* 386 * Handle initial connection protocol. 387 */ 388 static void 389 tftp(tp, size) 390 struct tftphdr *tp; 391 int size; 392 { 393 char *cp; 394 int first = 1, ecode; 395 struct formats *pf; 396 char *filename, *mode = NULL; /* XXX gcc */ 397 398 filename = cp = tp->th_stuff; 399 again: 400 while (cp < buf + size) { 401 if (*cp == '\0') 402 break; 403 cp++; 404 } 405 if (*cp != '\0') { 406 nak(EBADOP); 407 exit(1); 408 } 409 if (first) { 410 mode = ++cp; 411 first = 0; 412 goto again; 413 } 414 for (cp = mode; *cp; cp++) 415 if (isupper(*cp)) 416 *cp = tolower(*cp); 417 for (pf = formats; pf->f_mode; pf++) 418 if (strcmp(pf->f_mode, mode) == 0) 419 break; 420 if (pf->f_mode == 0) { 421 nak(EBADOP); 422 exit(1); 423 } 424 ecode = (*pf->f_validate)(&filename, tp->th_opcode); 425 if (logging) { 426 syslog(LOG_INFO, "%s: %s request for %s: %s", 427 verifyhost(&from), 428 tp->th_opcode == WRQ ? "write" : "read", 429 filename, errtomsg(ecode)); 430 } 431 if (ecode) { 432 /* 433 * Avoid storms of naks to a RRQ broadcast for a relative 434 * bootfile pathname from a diskless Sun. 435 */ 436 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) 437 exit(0); 438 nak(ecode); 439 exit(1); 440 } 441 if (tp->th_opcode == WRQ) 442 (*pf->f_recv)(pf); 443 else 444 (*pf->f_send)(pf); 445 exit(0); 446 } 447 448 449 FILE *file; 450 451 /* 452 * Validate file access. Since we 453 * have no uid or gid, for now require 454 * file to exist and be publicly 455 * readable/writable. 456 * If we were invoked with arguments 457 * from inetd then the file must also be 458 * in one of the given directory prefixes. 459 */ 460 int 461 validate_access(filep, mode) 462 char **filep; 463 int mode; 464 { 465 struct stat stbuf; 466 int fd; 467 struct dirlist *dirp; 468 static char pathname[MAXPATHLEN]; 469 char *filename = *filep; 470 471 /* 472 * Prevent tricksters from getting around the directory restrictions 473 */ 474 if (strstr(filename, "/../")) 475 return (EACCESS); 476 477 if (*filename == '/') { 478 /* 479 * Allow the request if it's in one of the approved locations. 480 * Special case: check the null prefix ("/") by looking 481 * for length = 1 and relying on the arg. processing that 482 * it's a /. 483 */ 484 for (dirp = dirs; dirp->name != NULL; dirp++) { 485 if (dirp->len == 1 || 486 (!strncmp(filename, dirp->name, dirp->len) && 487 filename[dirp->len] == '/')) 488 break; 489 } 490 /* If directory list is empty, allow access to any file */ 491 if (dirp->name == NULL && dirp != dirs) 492 return (EACCESS); 493 if (stat(filename, &stbuf) < 0) 494 return (errno == ENOENT ? ENOTFOUND : EACCESS); 495 if (!S_ISREG(stbuf.st_mode)) 496 return (ENOTFOUND); 497 if (mode == RRQ) { 498 if ((stbuf.st_mode & S_IROTH) == 0) 499 return (EACCESS); 500 } else { 501 if ((stbuf.st_mode & S_IWOTH) == 0) 502 return (EACCESS); 503 } 504 } else { 505 /* 506 * Relative file name: search the approved locations for it. 507 */ 508 509 if (!strncmp(filename, "../", 3)) 510 return (EACCESS); 511 512 /* 513 * Find the first file that exists in any of the directories, 514 * check access on it. 515 */ 516 if (dirs[0].name != NULL) { 517 for (dirp = dirs; dirp->name != NULL; dirp++) { 518 snprintf(pathname, sizeof pathname, "%s/%s", 519 dirp->name, filename); 520 if (stat(pathname, &stbuf) == 0 && 521 (stbuf.st_mode & S_IFMT) == S_IFREG) { 522 break; 523 } 524 } 525 if (dirp->name == NULL) 526 return (ENOTFOUND); 527 if (mode == RRQ && !(stbuf.st_mode & S_IROTH)) 528 return (EACCESS); 529 if (mode == WRQ && !(stbuf.st_mode & S_IWOTH)) 530 return (EACCESS); 531 *filep = filename = pathname; 532 } else { 533 /* 534 * If there's no directory list, take our cue from the 535 * absolute file request check above (*filename == '/'), 536 * and allow access to anything. 537 */ 538 if (stat(filename, &stbuf) < 0) 539 return (errno == ENOENT ? ENOTFOUND : EACCESS); 540 if (!S_ISREG(stbuf.st_mode)) 541 return (ENOTFOUND); 542 if (mode == RRQ) { 543 if ((stbuf.st_mode & S_IROTH) == 0) 544 return (EACCESS); 545 } else { 546 if ((stbuf.st_mode & S_IWOTH) == 0) 547 return (EACCESS); 548 } 549 *filep = filename; 550 } 551 } 552 fd = open(filename, mode == RRQ ? 0 : 1); 553 if (fd < 0) 554 return (errno + 100); 555 file = fdopen(fd, (mode == RRQ)? "r":"w"); 556 if (file == NULL) { 557 close(fd); 558 return errno+100; 559 } 560 return (0); 561 } 562 563 int timeout; 564 jmp_buf timeoutbuf; 565 566 void 567 timer(dummy) 568 int dummy; 569 { 570 571 timeout += rexmtval; 572 if (timeout >= maxtimeout) 573 exit(1); 574 longjmp(timeoutbuf, 1); 575 } 576 577 /* 578 * Send the requested file. 579 */ 580 void 581 sendfile(pf) 582 struct formats *pf; 583 { 584 struct tftphdr *dp; 585 struct tftphdr *ap; /* ack packet */ 586 int size, n; 587 volatile int block; 588 589 signal(SIGALRM, timer); 590 dp = r_init(); 591 ap = (struct tftphdr *)ackbuf; 592 block = 1; 593 do { 594 size = readit(file, &dp, pf->f_convert); 595 if (size < 0) { 596 nak(errno + 100); 597 goto abort; 598 } 599 dp->th_opcode = htons((u_short)DATA); 600 dp->th_block = htons((u_short)block); 601 timeout = 0; 602 (void)setjmp(timeoutbuf); 603 604 send_data: 605 if (send(peer, dp, size + 4, 0) != size + 4) { 606 syslog(LOG_ERR, "tftpd: write: %m"); 607 goto abort; 608 } 609 read_ahead(file, pf->f_convert); 610 for ( ; ; ) { 611 alarm(rexmtval); /* read the ack */ 612 n = recv(peer, ackbuf, sizeof (ackbuf), 0); 613 alarm(0); 614 if (n < 0) { 615 syslog(LOG_ERR, "tftpd: read: %m"); 616 goto abort; 617 } 618 ap->th_opcode = ntohs((u_short)ap->th_opcode); 619 ap->th_block = ntohs((u_short)ap->th_block); 620 621 if (ap->th_opcode == ERROR) 622 goto abort; 623 624 if (ap->th_opcode == ACK) { 625 if (ap->th_block == block) 626 break; 627 /* Re-synchronize with the other side */ 628 (void) synchnet(peer); 629 if (ap->th_block == (block -1)) 630 goto send_data; 631 } 632 633 } 634 block++; 635 } while (size == SEGSIZE); 636 abort: 637 (void) fclose(file); 638 } 639 640 void 641 justquit(dummy) 642 int dummy; 643 { 644 exit(0); 645 } 646 647 /* 648 * Receive a file. 649 */ 650 void 651 recvfile(pf) 652 struct formats *pf; 653 { 654 struct tftphdr *dp; 655 struct tftphdr *ap; /* ack buffer */ 656 int n, size; 657 volatile int block; 658 659 signal(SIGALRM, timer); 660 dp = w_init(); 661 ap = (struct tftphdr *)ackbuf; 662 block = 0; 663 do { 664 timeout = 0; 665 ap->th_opcode = htons((u_short)ACK); 666 ap->th_block = htons((u_short)block); 667 block++; 668 (void) setjmp(timeoutbuf); 669 send_ack: 670 if (send(peer, ackbuf, 4, 0) != 4) { 671 syslog(LOG_ERR, "tftpd: write: %m"); 672 goto abort; 673 } 674 write_behind(file, pf->f_convert); 675 for ( ; ; ) { 676 alarm(rexmtval); 677 n = recv(peer, dp, PKTSIZE, 0); 678 alarm(0); 679 if (n < 0) { /* really? */ 680 syslog(LOG_ERR, "tftpd: read: %m"); 681 goto abort; 682 } 683 dp->th_opcode = ntohs((u_short)dp->th_opcode); 684 dp->th_block = ntohs((u_short)dp->th_block); 685 if (dp->th_opcode == ERROR) 686 goto abort; 687 if (dp->th_opcode == DATA) { 688 if (dp->th_block == block) { 689 break; /* normal */ 690 } 691 /* Re-synchronize with the other side */ 692 (void) synchnet(peer); 693 if (dp->th_block == (block-1)) 694 goto send_ack; /* rexmit */ 695 } 696 } 697 /* size = write(file, dp->th_data, n - 4); */ 698 size = writeit(file, &dp, n - 4, pf->f_convert); 699 if (size != (n-4)) { /* ahem */ 700 if (size < 0) nak(errno + 100); 701 else nak(ENOSPACE); 702 goto abort; 703 } 704 } while (size == SEGSIZE); 705 write_behind(file, pf->f_convert); 706 (void) fclose(file); /* close data file */ 707 708 ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ 709 ap->th_block = htons((u_short)(block)); 710 (void) send(peer, ackbuf, 4, 0); 711 712 signal(SIGALRM, justquit); /* just quit on timeout */ 713 alarm(rexmtval); 714 n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ 715 alarm(0); 716 if (n >= 4 && /* if read some data */ 717 dp->th_opcode == DATA && /* and got a data block */ 718 block == dp->th_block) { /* then my last ack was lost */ 719 (void) send(peer, ackbuf, 4, 0); /* resend final ack */ 720 } 721 abort: 722 return; 723 } 724 725 const struct errmsg { 726 int e_code; 727 const char *e_msg; 728 } errmsgs[] = { 729 { EUNDEF, "Undefined error code" }, 730 { ENOTFOUND, "File not found" }, 731 { EACCESS, "Access violation" }, 732 { ENOSPACE, "Disk full or allocation exceeded" }, 733 { EBADOP, "Illegal TFTP operation" }, 734 { EBADID, "Unknown transfer ID" }, 735 { EEXISTS, "File already exists" }, 736 { ENOUSER, "No such user" }, 737 { -1, 0 } 738 }; 739 740 static const char * 741 errtomsg(error) 742 int error; 743 { 744 static char buf[20]; 745 const struct errmsg *pe; 746 747 if (error == 0) 748 return "success"; 749 for (pe = errmsgs; pe->e_code >= 0; pe++) 750 if (pe->e_code == error) 751 return pe->e_msg; 752 sprintf(buf, "error %d", error); 753 return buf; 754 } 755 756 /* 757 * Send a nak packet (error message). 758 * Error code passed in is one of the 759 * standard TFTP codes, or a UNIX errno 760 * offset by 100. 761 */ 762 static void 763 nak(error) 764 int error; 765 { 766 struct tftphdr *tp; 767 int length; 768 const struct errmsg *pe; 769 770 tp = (struct tftphdr *)buf; 771 tp->th_opcode = htons((u_short)ERROR); 772 for (pe = errmsgs; pe->e_code >= 0; pe++) 773 if (pe->e_code == error) 774 break; 775 if (pe->e_code < 0) { 776 tp->th_code = EUNDEF; /* set 'undef' errorcode */ 777 strcpy(tp->th_msg, strerror(error - 100)); 778 } else { 779 tp->th_code = htons((u_short)error); 780 strcpy(tp->th_msg, pe->e_msg); 781 } 782 length = strlen(pe->e_msg); 783 tp->th_msg[length] = '\0'; 784 length += 5; 785 if (send(peer, buf, length, 0) != length) 786 syslog(LOG_ERR, "nak: %m"); 787 } 788 789 static char * 790 verifyhost(fromp) 791 struct sockaddr_in *fromp; 792 { 793 struct hostent *hp; 794 795 hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (fromp->sin_addr), 796 fromp->sin_family); 797 if (hp) 798 return hp->h_name; 799 else 800 return inet_ntoa(fromp->sin_addr); 801 } 802