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