1 /* $NetBSD: tftpd.c,v 1.22 2001/01/09 23:29:22 lukem 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.22 2001/01/09 23:29:22 lukem 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 <netinet/in.h> 60 #include <arpa/tftp.h> 61 #include <arpa/inet.h> 62 63 #include <ctype.h> 64 #include <errno.h> 65 #include <fcntl.h> 66 #include <fcntl.h> 67 #include <grp.h> 68 #include <netdb.h> 69 #include <pwd.h> 70 #include <setjmp.h> 71 #include <signal.h> 72 #include <signal.h> 73 #include <stdio.h> 74 #include <stdlib.h> 75 #include <string.h> 76 #include <syslog.h> 77 #include <unistd.h> 78 79 #include "tftpsubs.h" 80 81 #define DEFAULTUSER "nobody" 82 83 #define TIMEOUT 5 84 85 extern char *__progname; 86 int peer; 87 int rexmtval = TIMEOUT; 88 int maxtimeout = 5*TIMEOUT; 89 90 #define PKTSIZE SEGSIZE+4 91 char buf[PKTSIZE]; 92 char ackbuf[PKTSIZE]; 93 struct sockaddr_storage from; 94 int fromlen; 95 96 /* 97 * Null-terminated directory prefix list for absolute pathname requests and 98 * search list for relative pathname requests. 99 * 100 * MAXDIRS should be at least as large as the number of arguments that 101 * inetd allows (currently 20). 102 */ 103 #define MAXDIRS 20 104 static struct dirlist { 105 char *name; 106 int len; 107 } dirs[MAXDIRS+1]; 108 static int suppress_naks; 109 static int logging; 110 static int secure; 111 static char *securedir; 112 113 struct formats; 114 115 static const char *errtomsg(int); 116 static void nak(int); 117 static void tftp(struct tftphdr *, int); 118 static void usage(void); 119 static char *verifyhost(struct sockaddr *); 120 void justquit(int); 121 int main(int, char **); 122 void recvfile(struct formats *); 123 void sendfile(struct formats *); 124 void timer(int); 125 int validate_access(char **, int); 126 127 struct formats { 128 const char *f_mode; 129 int (*f_validate)(char **, int); 130 void (*f_send)(struct formats *); 131 void (*f_recv)(struct formats *); 132 int f_convert; 133 } formats[] = { 134 { "netascii", validate_access, sendfile, recvfile, 1 }, 135 { "octet", validate_access, sendfile, recvfile, 0 }, 136 { 0 } 137 }; 138 139 static void 140 usage(void) 141 { 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(int argc, char *argv[]) 151 { 152 struct sockaddr_storage me; 153 struct passwd *pwent; 154 struct group *grent; 155 struct tftphdr *tp; 156 char *tgtuser, *tgtgroup, *ep; 157 int n, ch, on, fd; 158 int len; 159 uid_t curuid, tgtuid; 160 gid_t curgid, tgtgid; 161 long nid; 162 163 n = 0; 164 fd = 0; 165 openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 166 tgtuser = DEFAULTUSER; 167 tgtgroup = NULL; 168 curuid = getuid(); 169 curgid = getgid(); 170 171 while ((ch = getopt(argc, argv, "g:lns:u:")) != -1) 172 switch (ch) { 173 174 case 'g': 175 tgtgroup = optarg; 176 break; 177 178 case 'l': 179 logging = 1; 180 break; 181 182 case 'n': 183 suppress_naks = 1; 184 break; 185 186 case 's': 187 secure = 1; 188 securedir = optarg; 189 break; 190 191 case 'u': 192 tgtuser = optarg; 193 break; 194 195 default: 196 usage(); 197 break; 198 } 199 200 if (optind < argc) { 201 struct dirlist *dirp; 202 203 /* Get list of directory prefixes. Skip relative pathnames. */ 204 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS]; 205 optind++) { 206 if (argv[optind][0] == '/') { 207 dirp->name = argv[optind]; 208 dirp->len = strlen(dirp->name); 209 dirp++; 210 } 211 } 212 } 213 214 if (*tgtuser == '\0' || (tgtgroup != NULL && *tgtgroup == '\0')) 215 usage(); 216 217 nid = (strtol(tgtuser, &ep, 10)); 218 if (*ep == '\0') { 219 if (nid > UID_MAX) { 220 syslog(LOG_ERR, "uid %ld is too large", nid); 221 exit(1); 222 } 223 pwent = getpwuid((uid_t)nid); 224 } else 225 pwent = getpwnam(tgtuser); 226 if (pwent == NULL) { 227 syslog(LOG_ERR, "unknown user `%s'", tgtuser); 228 exit(1); 229 } 230 tgtuid = pwent->pw_uid; 231 tgtgid = pwent->pw_gid; 232 233 if (tgtgroup != NULL) { 234 nid = (strtol(tgtgroup, &ep, 10)); 235 if (*ep == '\0') { 236 if (nid > GID_MAX) { 237 syslog(LOG_ERR, "gid %ld is too large", nid); 238 exit(1); 239 } 240 grent = getgrgid((gid_t)nid); 241 } else 242 grent = getgrnam(tgtgroup); 243 if (grent != NULL) 244 tgtgid = grent->gr_gid; 245 else { 246 syslog(LOG_ERR, "unknown group `%s'", tgtgroup); 247 exit(1); 248 } 249 } 250 251 if (secure) { 252 if (chdir(securedir) < 0) { 253 syslog(LOG_ERR, "chdir %s: %m", securedir); 254 exit(1); 255 } 256 if (chroot(".")) { 257 syslog(LOG_ERR, "chroot: %m"); 258 exit(1); 259 } 260 } 261 262 if (logging) 263 syslog(LOG_DEBUG, "running as user `%s' (%d), group `%s' (%d)", 264 tgtuser, tgtuid, tgtgroup ? tgtgroup : "(unspecified)", 265 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 /* 348 * remember what address this was sent to, so we can respond on the 349 * same interface 350 */ 351 len = sizeof(me); 352 if (getsockname(fd, (struct sockaddr *)&me, &len) == 0) { 353 switch (me.ss_family) { 354 case AF_INET: 355 ((struct sockaddr_in *)&me)->sin_port = 0; 356 break; 357 case AF_INET6: 358 ((struct sockaddr_in6 *)&me)->sin6_port = 0; 359 break; 360 default: 361 /* unsupported */ 362 break; 363 } 364 } else { 365 memset(&me, 0, sizeof(me)); 366 me.ss_family = from.ss_family; 367 me.ss_len = from.ss_len; 368 } 369 370 alarm(0); 371 close(fd); 372 close(1); 373 peer = socket(from.ss_family, SOCK_DGRAM, 0); 374 if (peer < 0) { 375 syslog(LOG_ERR, "socket: %m"); 376 exit(1); 377 } 378 if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) { 379 syslog(LOG_ERR, "bind: %m"); 380 exit(1); 381 } 382 if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) { 383 syslog(LOG_ERR, "connect: %m"); 384 exit(1); 385 } 386 tp = (struct tftphdr *)buf; 387 tp->th_opcode = ntohs(tp->th_opcode); 388 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) 389 tftp(tp, n); 390 exit(1); 391 } 392 393 /* 394 * Handle initial connection protocol. 395 */ 396 static void 397 tftp(struct tftphdr *tp, int size) 398 { 399 struct formats *pf; 400 char *cp; 401 char *filename, *mode; 402 int first, ecode; 403 404 first = 1; 405 mode = NULL; 406 407 filename = cp = tp->th_stuff; 408 again: 409 while (cp < buf + size) { 410 if (*cp == '\0') 411 break; 412 cp++; 413 } 414 if (*cp != '\0') { 415 nak(EBADOP); 416 exit(1); 417 } 418 if (first) { 419 mode = ++cp; 420 first = 0; 421 goto again; 422 } 423 for (cp = mode; *cp; cp++) 424 if (isupper(*cp)) 425 *cp = tolower(*cp); 426 for (pf = formats; pf->f_mode; pf++) 427 if (strcmp(pf->f_mode, mode) == 0) 428 break; 429 if (pf->f_mode == 0) { 430 nak(EBADOP); 431 exit(1); 432 } 433 ecode = (*pf->f_validate)(&filename, tp->th_opcode); 434 if (logging) { 435 syslog(LOG_INFO, "%s: %s request for %s: %s", 436 verifyhost((struct sockaddr *)&from), 437 tp->th_opcode == WRQ ? "write" : "read", 438 filename, errtomsg(ecode)); 439 } 440 if (ecode) { 441 /* 442 * Avoid storms of naks to a RRQ broadcast for a relative 443 * bootfile pathname from a diskless Sun. 444 */ 445 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) 446 exit(0); 447 nak(ecode); 448 exit(1); 449 } 450 if (tp->th_opcode == WRQ) 451 (*pf->f_recv)(pf); 452 else 453 (*pf->f_send)(pf); 454 exit(0); 455 } 456 457 458 FILE *file; 459 460 /* 461 * Validate file access. Since we 462 * have no uid or gid, for now require 463 * file to exist and be publicly 464 * readable/writable. 465 * If we were invoked with arguments 466 * from inetd then the file must also be 467 * in one of the given directory prefixes. 468 */ 469 int 470 validate_access(char **filep, int mode) 471 { 472 struct stat stbuf; 473 struct dirlist *dirp; 474 static char pathname[MAXPATHLEN]; 475 char *filename; 476 int fd; 477 478 filename = *filep; 479 480 /* 481 * Prevent tricksters from getting around the directory restrictions 482 */ 483 if (strstr(filename, "/../")) 484 return (EACCESS); 485 486 if (*filename == '/') { 487 /* 488 * Allow the request if it's in one of the approved locations. 489 * Special case: check the null prefix ("/") by looking 490 * for length = 1 and relying on the arg. processing that 491 * it's a /. 492 */ 493 for (dirp = dirs; dirp->name != NULL; dirp++) { 494 if (dirp->len == 1 || 495 (!strncmp(filename, dirp->name, dirp->len) && 496 filename[dirp->len] == '/')) 497 break; 498 } 499 /* If directory list is empty, allow access to any file */ 500 if (dirp->name == NULL && dirp != dirs) 501 return (EACCESS); 502 if (stat(filename, &stbuf) < 0) 503 return (errno == ENOENT ? ENOTFOUND : EACCESS); 504 if (!S_ISREG(stbuf.st_mode)) 505 return (ENOTFOUND); 506 if (mode == RRQ) { 507 if ((stbuf.st_mode & S_IROTH) == 0) 508 return (EACCESS); 509 } else { 510 if ((stbuf.st_mode & S_IWOTH) == 0) 511 return (EACCESS); 512 } 513 } else { 514 /* 515 * Relative file name: search the approved locations for it. 516 */ 517 518 if (!strncmp(filename, "../", 3)) 519 return (EACCESS); 520 521 /* 522 * Find the first file that exists in any of the directories, 523 * check access on it. 524 */ 525 if (dirs[0].name != NULL) { 526 for (dirp = dirs; dirp->name != NULL; dirp++) { 527 snprintf(pathname, sizeof pathname, "%s/%s", 528 dirp->name, filename); 529 if (stat(pathname, &stbuf) == 0 && 530 (stbuf.st_mode & S_IFMT) == S_IFREG) { 531 break; 532 } 533 } 534 if (dirp->name == NULL) 535 return (ENOTFOUND); 536 if (mode == RRQ && !(stbuf.st_mode & S_IROTH)) 537 return (EACCESS); 538 if (mode == WRQ && !(stbuf.st_mode & S_IWOTH)) 539 return (EACCESS); 540 *filep = filename = pathname; 541 } else { 542 /* 543 * If there's no directory list, take our cue from the 544 * absolute file request check above (*filename == '/'), 545 * and allow access to anything. 546 */ 547 if (stat(filename, &stbuf) < 0) 548 return (errno == ENOENT ? ENOTFOUND : EACCESS); 549 if (!S_ISREG(stbuf.st_mode)) 550 return (ENOTFOUND); 551 if (mode == RRQ) { 552 if ((stbuf.st_mode & S_IROTH) == 0) 553 return (EACCESS); 554 } else { 555 if ((stbuf.st_mode & S_IWOTH) == 0) 556 return (EACCESS); 557 } 558 *filep = filename; 559 } 560 } 561 fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY | O_TRUNC); 562 if (fd < 0) 563 return (errno + 100); 564 file = fdopen(fd, (mode == RRQ)? "r":"w"); 565 if (file == NULL) { 566 close(fd); 567 return (errno + 100); 568 } 569 return (0); 570 } 571 572 int timeout; 573 jmp_buf timeoutbuf; 574 575 void 576 timer(int dummy) 577 { 578 579 timeout += rexmtval; 580 if (timeout >= maxtimeout) 581 exit(1); 582 longjmp(timeoutbuf, 1); 583 } 584 585 /* 586 * Send the requested file. 587 */ 588 void 589 sendfile(struct formats *pf) 590 { 591 volatile unsigned int block; 592 struct tftphdr *dp; 593 struct tftphdr *ap; /* ack packet */ 594 int size, n; 595 596 signal(SIGALRM, timer); 597 dp = r_init(); 598 ap = (struct tftphdr *)ackbuf; 599 block = 1; 600 do { 601 size = readit(file, &dp, pf->f_convert); 602 if (size < 0) { 603 nak(errno + 100); 604 goto abort; 605 } 606 dp->th_opcode = htons((u_short)DATA); 607 dp->th_block = htons((u_short)block); 608 timeout = 0; 609 (void)setjmp(timeoutbuf); 610 611 send_data: 612 if (send(peer, dp, size + 4, 0) != size + 4) { 613 syslog(LOG_ERR, "tftpd: write: %m"); 614 goto abort; 615 } 616 read_ahead(file, pf->f_convert); 617 for ( ; ; ) { 618 alarm(rexmtval); /* read the ack */ 619 n = recv(peer, ackbuf, sizeof (ackbuf), 0); 620 alarm(0); 621 if (n < 0) { 622 syslog(LOG_ERR, "tftpd: read: %m"); 623 goto abort; 624 } 625 ap->th_opcode = ntohs((u_short)ap->th_opcode); 626 ap->th_block = ntohs((u_short)ap->th_block); 627 628 if (ap->th_opcode == ERROR) 629 goto abort; 630 631 if (ap->th_opcode == ACK) { 632 if (ap->th_block == block) 633 break; 634 /* Re-synchronize with the other side */ 635 (void) synchnet(peer); 636 if (ap->th_block == (block -1)) 637 goto send_data; 638 } 639 640 } 641 block++; 642 } while (size == SEGSIZE); 643 abort: 644 (void) fclose(file); 645 } 646 647 void 648 justquit(int dummy) 649 { 650 651 exit(0); 652 } 653 654 /* 655 * Receive a file. 656 */ 657 void 658 recvfile(struct formats *pf) 659 { 660 volatile unsigned int block; 661 struct tftphdr *dp; 662 struct tftphdr *ap; /* ack buffer */ 663 int n, size; 664 665 signal(SIGALRM, timer); 666 dp = w_init(); 667 ap = (struct tftphdr *)ackbuf; 668 block = 0; 669 do { 670 timeout = 0; 671 ap->th_opcode = htons((u_short)ACK); 672 ap->th_block = htons((u_short)block); 673 block++; 674 (void) setjmp(timeoutbuf); 675 send_ack: 676 if (send(peer, ackbuf, 4, 0) != 4) { 677 syslog(LOG_ERR, "tftpd: write: %m"); 678 goto abort; 679 } 680 write_behind(file, pf->f_convert); 681 for ( ; ; ) { 682 alarm(rexmtval); 683 n = recv(peer, dp, PKTSIZE, 0); 684 alarm(0); 685 if (n < 0) { /* really? */ 686 syslog(LOG_ERR, "tftpd: read: %m"); 687 goto abort; 688 } 689 dp->th_opcode = ntohs((u_short)dp->th_opcode); 690 dp->th_block = ntohs((u_short)dp->th_block); 691 if (dp->th_opcode == ERROR) 692 goto abort; 693 if (dp->th_opcode == DATA) { 694 if (dp->th_block == block) { 695 break; /* normal */ 696 } 697 /* Re-synchronize with the other side */ 698 (void) synchnet(peer); 699 if (dp->th_block == (block-1)) 700 goto send_ack; /* rexmit */ 701 } 702 } 703 /* size = write(file, dp->th_data, n - 4); */ 704 size = writeit(file, &dp, n - 4, pf->f_convert); 705 if (size != (n-4)) { /* ahem */ 706 if (size < 0) nak(errno + 100); 707 else nak(ENOSPACE); 708 goto abort; 709 } 710 } while (size == SEGSIZE); 711 write_behind(file, pf->f_convert); 712 (void) fclose(file); /* close data file */ 713 714 ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ 715 ap->th_block = htons((u_short)(block)); 716 (void) send(peer, ackbuf, 4, 0); 717 718 signal(SIGALRM, justquit); /* just quit on timeout */ 719 alarm(rexmtval); 720 n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ 721 alarm(0); 722 if (n >= 4 && /* if read some data */ 723 dp->th_opcode == DATA && /* and got a data block */ 724 block == dp->th_block) { /* then my last ack was lost */ 725 (void) send(peer, ackbuf, 4, 0); /* resend final ack */ 726 } 727 abort: 728 return; 729 } 730 731 const struct errmsg { 732 int e_code; 733 const char *e_msg; 734 } errmsgs[] = { 735 { EUNDEF, "Undefined error code" }, 736 { ENOTFOUND, "File not found" }, 737 { EACCESS, "Access violation" }, 738 { ENOSPACE, "Disk full or allocation exceeded" }, 739 { EBADOP, "Illegal TFTP operation" }, 740 { EBADID, "Unknown transfer ID" }, 741 { EEXISTS, "File already exists" }, 742 { ENOUSER, "No such user" }, 743 { -1, 0 } 744 }; 745 746 static const char * 747 errtomsg(int error) 748 { 749 static char ebuf[20]; 750 const struct errmsg *pe; 751 752 if (error == 0) 753 return ("success"); 754 for (pe = errmsgs; pe->e_code >= 0; pe++) 755 if (pe->e_code == error) 756 return (pe->e_msg); 757 snprintf(ebuf, sizeof(ebuf), "error %d", error); 758 return (ebuf); 759 } 760 761 /* 762 * Send a nak packet (error message). 763 * Error code passed in is one of the 764 * standard TFTP codes, or a UNIX errno 765 * offset by 100. 766 */ 767 static void 768 nak(int error) 769 { 770 const struct errmsg *pe; 771 struct tftphdr *tp; 772 int length; 773 size_t msglen; 774 775 tp = (struct tftphdr *)buf; 776 tp->th_opcode = htons((u_short)ERROR); 777 msglen = sizeof(buf) - (&tp->th_msg[0] - buf); 778 for (pe = errmsgs; pe->e_code >= 0; pe++) 779 if (pe->e_code == error) 780 break; 781 if (pe->e_code < 0) { 782 tp->th_code = EUNDEF; /* set 'undef' errorcode */ 783 strlcpy(tp->th_msg, strerror(error - 100), msglen); 784 } else { 785 tp->th_code = htons((u_short)error); 786 strlcpy(tp->th_msg, pe->e_msg, msglen); 787 } 788 length = strlen(tp->th_msg); 789 msglen = &tp->th_msg[length + 1] - buf; 790 if (send(peer, buf, msglen, 0) != msglen) 791 syslog(LOG_ERR, "nak: %m"); 792 } 793 794 static char * 795 verifyhost(struct sockaddr *fromp) 796 { 797 static char hbuf[MAXHOSTNAMELEN]; 798 799 if (getnameinfo(fromp, fromp->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0)) 800 strlcpy(hbuf, "?", sizeof(hbuf)); 801 return (hbuf); 802 } 803