1 /* 2 * Copyright (c) 1983, 1995 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #include <errno.h> 10 #include "sendmail.h" 11 12 #ifndef lint 13 #ifdef DAEMON 14 static char sccsid[] = "@(#)daemon.c 8.96 (Berkeley) 05/31/95 (with daemon mode)"; 15 #else 16 static char sccsid[] = "@(#)daemon.c 8.96 (Berkeley) 05/31/95 (without daemon mode)"; 17 #endif 18 #endif /* not lint */ 19 20 #ifdef DAEMON 21 22 # include <arpa/inet.h> 23 24 #if NAMED_BIND 25 # include <resolv.h> 26 #endif 27 28 #if IP_SRCROUTE 29 # include <netinet/in_systm.h> 30 # include <netinet/ip.h> 31 # include <netinet/ip_var.h> 32 #endif 33 34 /* 35 ** DAEMON.C -- routines to use when running as a daemon. 36 ** 37 ** This entire file is highly dependent on the 4.2 BSD 38 ** interprocess communication primitives. No attempt has 39 ** been made to make this file portable to Version 7, 40 ** Version 6, MPX files, etc. If you should try such a 41 ** thing yourself, I recommend chucking the entire file 42 ** and starting from scratch. Basic semantics are: 43 ** 44 ** getrequests() 45 ** Opens a port and initiates a connection. 46 ** Returns in a child. Must set InChannel and 47 ** OutChannel appropriately. 48 ** clrdaemon() 49 ** Close any open files associated with getting 50 ** the connection; this is used when running the queue, 51 ** etc., to avoid having extra file descriptors during 52 ** the queue run and to avoid confusing the network 53 ** code (if it cares). 54 ** makeconnection(host, port, outfile, infile, usesecureport) 55 ** Make a connection to the named host on the given 56 ** port. Set *outfile and *infile to the files 57 ** appropriate for communication. Returns zero on 58 ** success, else an exit status describing the 59 ** error. 60 ** host_map_lookup(map, hbuf, avp, pstat) 61 ** Convert the entry in hbuf into a canonical form. 62 */ 63 /* 64 ** GETREQUESTS -- open mail IPC port and get requests. 65 ** 66 ** Parameters: 67 ** none. 68 ** 69 ** Returns: 70 ** none. 71 ** 72 ** Side Effects: 73 ** Waits until some interesting activity occurs. When 74 ** it does, a child is created to process it, and the 75 ** parent waits for completion. Return from this 76 ** routine is always in the child. The file pointers 77 ** "InChannel" and "OutChannel" should be set to point 78 ** to the communication channel. 79 */ 80 81 int DaemonSocket = -1; /* fd describing socket */ 82 SOCKADDR DaemonAddr; /* socket for incoming */ 83 int ListenQueueSize = 10; /* size of listen queue */ 84 int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 85 int TcpSndBufferSize = 0; /* size of TCP send buffer */ 86 87 void 88 getrequests() 89 { 90 int t; 91 bool refusingconnections = TRUE; 92 FILE *pidf; 93 int socksize; 94 #ifdef XDEBUG 95 bool j_has_dot; 96 #endif 97 extern void reapchild(); 98 99 /* 100 ** Set up the address for the mailer. 101 */ 102 103 if (DaemonAddr.sin.sin_family == 0) 104 DaemonAddr.sin.sin_family = AF_INET; 105 if (DaemonAddr.sin.sin_addr.s_addr == 0) 106 DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 107 if (DaemonAddr.sin.sin_port == 0) 108 { 109 register struct servent *sp; 110 111 sp = getservbyname("smtp", "tcp"); 112 if (sp == NULL) 113 { 114 syserr("554 service \"smtp\" unknown"); 115 DaemonAddr.sin.sin_port = htons(25); 116 } 117 else 118 DaemonAddr.sin.sin_port = sp->s_port; 119 } 120 121 /* 122 ** Try to actually open the connection. 123 */ 124 125 if (tTd(15, 1)) 126 printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 127 128 /* get a socket for the SMTP connection */ 129 socksize = opendaemonsocket(TRUE); 130 131 (void) setsignal(SIGCHLD, reapchild); 132 133 /* write the pid to the log file for posterity */ 134 pidf = fopen(PidFile, "w"); 135 if (pidf != NULL) 136 { 137 extern char *CommandLineArgs; 138 139 /* write the process id on line 1 */ 140 fprintf(pidf, "%d\n", getpid()); 141 142 /* line 2 contains all command line flags */ 143 fprintf(pidf, "%s\n", CommandLineArgs); 144 145 /* flush and close */ 146 fclose(pidf); 147 } 148 149 #ifdef XDEBUG 150 { 151 char jbuf[MAXHOSTNAMELEN]; 152 153 expand("\201j", jbuf, sizeof jbuf, CurEnv); 154 j_has_dot = strchr(jbuf, '.') != NULL; 155 } 156 #endif 157 158 if (tTd(15, 1)) 159 printf("getrequests: %d\n", DaemonSocket); 160 161 for (;;) 162 { 163 register int pid; 164 auto int lotherend; 165 extern bool refuseconnections(); 166 extern int getla(); 167 168 /* see if we are rejecting connections */ 169 CurrentLA = getla(); 170 if (refuseconnections()) 171 { 172 if (DaemonSocket >= 0) 173 { 174 /* close socket so peer will fail quickly */ 175 (void) close(DaemonSocket); 176 DaemonSocket = -1; 177 } 178 refusingconnections = TRUE; 179 setproctitle("rejecting connections: load average: %d", 180 CurrentLA); 181 sleep(15); 182 continue; 183 } 184 185 /* arrange to (re)open the socket if necessary */ 186 if (refusingconnections) 187 { 188 (void) opendaemonsocket(FALSE); 189 refusingconnections = FALSE; 190 } 191 192 #ifdef XDEBUG 193 /* check for disaster */ 194 { 195 char jbuf[MAXHOSTNAMELEN]; 196 197 expand("\201j", jbuf, sizeof jbuf, CurEnv); 198 if (!wordinclass(jbuf, 'w')) 199 { 200 dumpstate("daemon lost $j"); 201 syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 202 abort(); 203 } 204 else if (j_has_dot && strchr(jbuf, '.') == NULL) 205 { 206 dumpstate("daemon $j lost dot"); 207 syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 208 abort(); 209 } 210 } 211 #endif 212 213 /* wait for a connection */ 214 setproctitle("accepting connections"); 215 do 216 { 217 errno = 0; 218 lotherend = socksize; 219 t = accept(DaemonSocket, 220 (struct sockaddr *)&RealHostAddr, &lotherend); 221 } while (t < 0 && errno == EINTR); 222 if (t < 0) 223 { 224 syserr("getrequests: accept"); 225 226 /* arrange to re-open the socket next time around */ 227 (void) close(DaemonSocket); 228 DaemonSocket = -1; 229 sleep(5); 230 continue; 231 } 232 233 /* 234 ** Create a subprocess to process the mail. 235 */ 236 237 if (tTd(15, 2)) 238 printf("getrequests: forking (fd = %d)\n", t); 239 240 pid = fork(); 241 if (pid < 0) 242 { 243 syserr("daemon: cannot fork"); 244 sleep(10); 245 (void) close(t); 246 continue; 247 } 248 249 if (pid == 0) 250 { 251 char *p; 252 extern char *hostnamebyanyaddr(); 253 extern void intsig(); 254 255 /* 256 ** CHILD -- return to caller. 257 ** Collect verified idea of sending host. 258 ** Verify calling user id if possible here. 259 */ 260 261 (void) setsignal(SIGCHLD, SIG_DFL); 262 (void) setsignal(SIGHUP, intsig); 263 (void) close(DaemonSocket); 264 DisConnected = FALSE; 265 266 setproctitle("startup with %s", 267 anynet_ntoa(&RealHostAddr)); 268 269 /* determine host name */ 270 p = hostnamebyanyaddr(&RealHostAddr); 271 if (strlen(p) > MAXNAME) 272 p[MAXNAME] = '\0'; 273 RealHostName = newstr(p); 274 setproctitle("startup with %s", p); 275 276 if ((InChannel = fdopen(t, "r")) == NULL || 277 (t = dup(t)) < 0 || 278 (OutChannel = fdopen(t, "w")) == NULL) 279 { 280 syserr("cannot open SMTP server channel, fd=%d", t); 281 exit(0); 282 } 283 284 /* should we check for illegal connection here? XXX */ 285 #ifdef XLA 286 if (!xla_host_ok(RealHostName)) 287 { 288 message("421 Too many SMTP sessions for this host"); 289 exit(0); 290 } 291 #endif 292 293 if (tTd(15, 2)) 294 printf("getreq: returning\n"); 295 return; 296 } 297 298 /* close the port so that others will hang (for a while) */ 299 (void) close(t); 300 } 301 /*NOTREACHED*/ 302 } 303 /* 304 ** OPENDAEMONSOCKET -- open the SMTP socket 305 ** 306 ** Deals with setting all appropriate options. DaemonAddr must 307 ** be set up in advance. 308 ** 309 ** Parameters: 310 ** firsttime -- set if this is the initial open. 311 ** 312 ** Returns: 313 ** Size in bytes of the daemon socket addr. 314 ** 315 ** Side Effects: 316 ** Leaves DaemonSocket set to the open socket. 317 ** Exits if the socket cannot be created. 318 */ 319 320 #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 321 322 int 323 opendaemonsocket(firsttime) 324 bool firsttime; 325 { 326 int on = 1; 327 int socksize = 0; 328 int ntries = 0; 329 int saveerrno; 330 331 if (tTd(15, 2)) 332 printf("opendaemonsocket()\n"); 333 334 do 335 { 336 if (ntries > 0) 337 sleep(5); 338 if (firsttime || DaemonSocket < 0) 339 { 340 DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 341 if (DaemonSocket < 0) 342 { 343 /* probably another daemon already */ 344 saveerrno = errno; 345 syserr("opendaemonsocket: can't create server SMTP socket"); 346 severe: 347 # ifdef LOG 348 if (LogLevel > 0) 349 syslog(LOG_ALERT, "problem creating SMTP socket"); 350 # endif /* LOG */ 351 DaemonSocket = -1; 352 continue; 353 } 354 355 /* turn on network debugging? */ 356 if (tTd(15, 101)) 357 (void) setsockopt(DaemonSocket, SOL_SOCKET, 358 SO_DEBUG, (char *)&on, 359 sizeof on); 360 361 (void) setsockopt(DaemonSocket, SOL_SOCKET, 362 SO_REUSEADDR, (char *)&on, sizeof on); 363 (void) setsockopt(DaemonSocket, SOL_SOCKET, 364 SO_KEEPALIVE, (char *)&on, sizeof on); 365 366 #ifdef SO_RCVBUF 367 if (TcpRcvBufferSize > 0) 368 { 369 if (setsockopt(DaemonSocket, SOL_SOCKET, 370 SO_RCVBUF, 371 (char *) &TcpRcvBufferSize, 372 sizeof(TcpRcvBufferSize)) < 0) 373 syserr("getrequests: setsockopt(SO_RCVBUF)"); 374 } 375 #endif 376 377 switch (DaemonAddr.sa.sa_family) 378 { 379 # ifdef NETINET 380 case AF_INET: 381 socksize = sizeof DaemonAddr.sin; 382 break; 383 # endif 384 385 # ifdef NETISO 386 case AF_ISO: 387 socksize = sizeof DaemonAddr.siso; 388 break; 389 # endif 390 391 default: 392 socksize = sizeof DaemonAddr; 393 break; 394 } 395 396 if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 397 { 398 saveerrno = errno; 399 syserr("getrequests: cannot bind"); 400 (void) close(DaemonSocket); 401 goto severe; 402 } 403 } 404 if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 405 { 406 saveerrno = errno; 407 syserr("getrequests: cannot listen"); 408 (void) close(DaemonSocket); 409 goto severe; 410 } 411 return socksize; 412 } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 413 syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 414 finis(); 415 } 416 /* 417 ** CLRDAEMON -- reset the daemon connection 418 ** 419 ** Parameters: 420 ** none. 421 ** 422 ** Returns: 423 ** none. 424 ** 425 ** Side Effects: 426 ** releases any resources used by the passive daemon. 427 */ 428 429 void 430 clrdaemon() 431 { 432 if (DaemonSocket >= 0) 433 (void) close(DaemonSocket); 434 DaemonSocket = -1; 435 } 436 /* 437 ** SETDAEMONOPTIONS -- set options for running the daemon 438 ** 439 ** Parameters: 440 ** p -- the options line. 441 ** 442 ** Returns: 443 ** none. 444 */ 445 446 void 447 setdaemonoptions(p) 448 register char *p; 449 { 450 if (DaemonAddr.sa.sa_family == AF_UNSPEC) 451 DaemonAddr.sa.sa_family = AF_INET; 452 453 while (p != NULL) 454 { 455 register char *f; 456 register char *v; 457 458 while (isascii(*p) && isspace(*p)) 459 p++; 460 if (*p == '\0') 461 break; 462 f = p; 463 p = strchr(p, ','); 464 if (p != NULL) 465 *p++ = '\0'; 466 v = strchr(f, '='); 467 if (v == NULL) 468 continue; 469 while (isascii(*++v) && isspace(*v)) 470 continue; 471 if (isascii(*f) && isupper(*f)) 472 *f = tolower(*f); 473 474 switch (*f) 475 { 476 case 'F': /* address family */ 477 if (isascii(*v) && isdigit(*v)) 478 DaemonAddr.sa.sa_family = atoi(v); 479 #ifdef NETINET 480 else if (strcasecmp(v, "inet") == 0) 481 DaemonAddr.sa.sa_family = AF_INET; 482 #endif 483 #ifdef NETISO 484 else if (strcasecmp(v, "iso") == 0) 485 DaemonAddr.sa.sa_family = AF_ISO; 486 #endif 487 #ifdef NETNS 488 else if (strcasecmp(v, "ns") == 0) 489 DaemonAddr.sa.sa_family = AF_NS; 490 #endif 491 #ifdef NETX25 492 else if (strcasecmp(v, "x.25") == 0) 493 DaemonAddr.sa.sa_family = AF_CCITT; 494 #endif 495 else 496 syserr("554 Unknown address family %s in Family=option", v); 497 break; 498 499 case 'A': /* address */ 500 switch (DaemonAddr.sa.sa_family) 501 { 502 #ifdef NETINET 503 case AF_INET: 504 if (isascii(*v) && isdigit(*v)) 505 DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); 506 else 507 { 508 register struct netent *np; 509 510 np = getnetbyname(v); 511 if (np == NULL) 512 syserr("554 network \"%s\" unknown", v); 513 else 514 DaemonAddr.sin.sin_addr.s_addr = np->n_net; 515 } 516 break; 517 #endif 518 519 default: 520 syserr("554 Address= option unsupported for family %d", 521 DaemonAddr.sa.sa_family); 522 break; 523 } 524 break; 525 526 case 'P': /* port */ 527 switch (DaemonAddr.sa.sa_family) 528 { 529 short port; 530 531 #ifdef NETINET 532 case AF_INET: 533 if (isascii(*v) && isdigit(*v)) 534 DaemonAddr.sin.sin_port = htons(atoi(v)); 535 else 536 { 537 register struct servent *sp; 538 539 sp = getservbyname(v, "tcp"); 540 if (sp == NULL) 541 syserr("554 service \"%s\" unknown", v); 542 else 543 DaemonAddr.sin.sin_port = sp->s_port; 544 } 545 break; 546 #endif 547 548 #ifdef NETISO 549 case AF_ISO: 550 /* assume two byte transport selector */ 551 if (isascii(*v) && isdigit(*v)) 552 port = htons(atoi(v)); 553 else 554 { 555 register struct servent *sp; 556 557 sp = getservbyname(v, "tcp"); 558 if (sp == NULL) 559 syserr("554 service \"%s\" unknown", v); 560 else 561 port = sp->s_port; 562 } 563 bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 564 break; 565 #endif 566 567 default: 568 syserr("554 Port= option unsupported for family %d", 569 DaemonAddr.sa.sa_family); 570 break; 571 } 572 break; 573 574 case 'L': /* listen queue size */ 575 ListenQueueSize = atoi(v); 576 break; 577 578 case 'S': /* send buffer size */ 579 TcpSndBufferSize = atoi(v); 580 break; 581 582 case 'R': /* receive buffer size */ 583 TcpRcvBufferSize = atoi(v); 584 break; 585 586 default: 587 syserr("554 DaemonPortOptions parameter \"%s\" unknown", f); 588 } 589 } 590 } 591 /* 592 ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 593 ** 594 ** Parameters: 595 ** host -- the name of the host. 596 ** port -- the port number to connect to. 597 ** mci -- a pointer to the mail connection information 598 ** structure to be filled in. 599 ** usesecureport -- if set, use a low numbered (reserved) 600 ** port to provide some rudimentary authentication. 601 ** 602 ** Returns: 603 ** An exit code telling whether the connection could be 604 ** made and if not why not. 605 ** 606 ** Side Effects: 607 ** none. 608 */ 609 610 SOCKADDR CurHostAddr; /* address of current host */ 611 612 int 613 makeconnection(host, port, mci, usesecureport) 614 char *host; 615 u_short port; 616 register MCI *mci; 617 bool usesecureport; 618 { 619 register int i = 0; 620 register int s; 621 register struct hostent *hp = (struct hostent *)NULL; 622 SOCKADDR addr; 623 int sav_errno; 624 int addrlen; 625 bool firstconnect; 626 #if NAMED_BIND 627 extern int h_errno; 628 #endif 629 630 /* 631 ** Set up the address for the mailer. 632 ** Accept "[a.b.c.d]" syntax for host name. 633 */ 634 635 #if NAMED_BIND 636 h_errno = 0; 637 #endif 638 errno = 0; 639 bzero(&CurHostAddr, sizeof CurHostAddr); 640 SmtpPhase = mci->mci_phase = "initial connection"; 641 CurHostName = host; 642 643 if (host[0] == '[') 644 { 645 long hid; 646 register char *p = strchr(host, ']'); 647 648 if (p != NULL) 649 { 650 *p = '\0'; 651 #ifdef NETINET 652 hid = inet_addr(&host[1]); 653 if (hid == -1) 654 #endif 655 { 656 /* try it as a host name (avoid MX lookup) */ 657 hp = sm_gethostbyname(&host[1]); 658 if (hp == NULL && p[-1] == '.') 659 { 660 #if NAMED_BIND 661 int oldopts = _res.options; 662 663 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 664 #endif 665 p[-1] = '\0'; 666 hp = sm_gethostbyname(&host[1]); 667 p[-1] = '.'; 668 #if NAMED_BIND 669 _res.options = oldopts; 670 #endif 671 } 672 *p = ']'; 673 goto gothostent; 674 } 675 *p = ']'; 676 } 677 if (p == NULL) 678 { 679 usrerr("553 Invalid numeric domain spec \"%s\"", host); 680 mci->mci_status = "5.1.2"; 681 return (EX_NOHOST); 682 } 683 #ifdef NETINET 684 addr.sin.sin_family = AF_INET; /*XXX*/ 685 addr.sin.sin_addr.s_addr = hid; 686 #endif 687 } 688 else 689 { 690 register char *p = &host[strlen(host) - 1]; 691 692 hp = sm_gethostbyname(host); 693 if (hp == NULL && *p == '.') 694 { 695 #if NAMED_BIND 696 int oldopts = _res.options; 697 698 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 699 #endif 700 *p = '\0'; 701 hp = sm_gethostbyname(host); 702 *p = '.'; 703 #if NAMED_BIND 704 _res.options = oldopts; 705 #endif 706 } 707 gothostent: 708 if (hp == NULL) 709 { 710 #if NAMED_BIND 711 /* check for name server timeouts */ 712 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 713 (errno == ECONNREFUSED && UseNameServer)) 714 { 715 mci->mci_status = "4.4.3"; 716 return (EX_TEMPFAIL); 717 } 718 #endif 719 return (EX_NOHOST); 720 } 721 addr.sa.sa_family = hp->h_addrtype; 722 switch (hp->h_addrtype) 723 { 724 #ifdef NETINET 725 case AF_INET: 726 bcopy(hp->h_addr, 727 &addr.sin.sin_addr, 728 INADDRSZ); 729 break; 730 #endif 731 732 default: 733 bcopy(hp->h_addr, 734 addr.sa.sa_data, 735 hp->h_length); 736 break; 737 } 738 i = 1; 739 } 740 741 /* 742 ** Determine the port number. 743 */ 744 745 if (port != 0) 746 port = htons(port); 747 else 748 { 749 register struct servent *sp = getservbyname("smtp", "tcp"); 750 751 if (sp == NULL) 752 { 753 #ifdef LOG 754 if (LogLevel > 2) 755 syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown"); 756 #endif 757 port = htons(25); 758 } 759 else 760 port = sp->s_port; 761 } 762 763 switch (addr.sa.sa_family) 764 { 765 #ifdef NETINET 766 case AF_INET: 767 addr.sin.sin_port = port; 768 addrlen = sizeof (struct sockaddr_in); 769 break; 770 #endif 771 772 #ifdef NETISO 773 case AF_ISO: 774 /* assume two byte transport selector */ 775 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 776 addrlen = sizeof (struct sockaddr_iso); 777 break; 778 #endif 779 780 default: 781 syserr("Can't connect to address family %d", addr.sa.sa_family); 782 return (EX_NOHOST); 783 } 784 785 /* 786 ** Try to actually open the connection. 787 */ 788 789 #ifdef XLA 790 /* if too many connections, don't bother trying */ 791 if (!xla_noqueue_ok(host)) 792 return EX_TEMPFAIL; 793 #endif 794 795 firstconnect = TRUE; 796 for (;;) 797 { 798 if (tTd(16, 1)) 799 printf("makeconnection (%s [%s])\n", 800 host, anynet_ntoa(&addr)); 801 802 /* save for logging */ 803 CurHostAddr = addr; 804 805 if (usesecureport) 806 { 807 int rport = IPPORT_RESERVED - 1; 808 809 s = rresvport(&rport); 810 } 811 else 812 { 813 s = socket(AF_INET, SOCK_STREAM, 0); 814 } 815 if (s < 0) 816 { 817 sav_errno = errno; 818 syserr("makeconnection: no socket"); 819 goto failure; 820 } 821 822 #ifdef SO_SNDBUF 823 if (TcpSndBufferSize > 0) 824 { 825 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 826 (char *) &TcpSndBufferSize, 827 sizeof(TcpSndBufferSize)) < 0) 828 syserr("makeconnection: setsockopt(SO_SNDBUF)"); 829 } 830 #endif 831 832 if (tTd(16, 1)) 833 printf("makeconnection: fd=%d\n", s); 834 835 /* turn on network debugging? */ 836 if (tTd(16, 101)) 837 { 838 int on = 1; 839 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 840 (char *)&on, sizeof on); 841 } 842 if (CurEnv->e_xfp != NULL) 843 (void) fflush(CurEnv->e_xfp); /* for debugging */ 844 errno = 0; /* for debugging */ 845 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 846 break; 847 848 /* if running demand-dialed connection, try again */ 849 if (DialDelay > 0 && firstconnect) 850 { 851 if (tTd(16, 1)) 852 printf("Connect failed (%s); trying again...\n", 853 errstring(sav_errno)); 854 firstconnect = FALSE; 855 sleep(DialDelay); 856 continue; 857 } 858 859 /* couldn't connect.... figure out why */ 860 sav_errno = errno; 861 (void) close(s); 862 if (hp != NULL && hp->h_addr_list[i]) 863 { 864 if (tTd(16, 1)) 865 printf("Connect failed (%s); trying new address....\n", 866 errstring(sav_errno)); 867 switch (addr.sa.sa_family) 868 { 869 #ifdef NETINET 870 case AF_INET: 871 bcopy(hp->h_addr_list[i++], 872 &addr.sin.sin_addr, 873 INADDRSZ); 874 break; 875 #endif 876 877 default: 878 bcopy(hp->h_addr_list[i++], 879 addr.sa.sa_data, 880 hp->h_length); 881 break; 882 } 883 continue; 884 } 885 886 /* failure, decide if temporary or not */ 887 failure: 888 #ifdef XLA 889 xla_host_end(host); 890 #endif 891 if (transienterror(sav_errno)) 892 return EX_TEMPFAIL; 893 else 894 { 895 message("%s", errstring(sav_errno)); 896 return (EX_UNAVAILABLE); 897 } 898 } 899 900 /* connection ok, put it into canonical form */ 901 if ((mci->mci_out = fdopen(s, "w")) == NULL || 902 (s = dup(s)) < 0 || 903 (mci->mci_in = fdopen(s, "r")) == NULL) 904 { 905 syserr("cannot open SMTP client channel, fd=%d", s); 906 return EX_TEMPFAIL; 907 } 908 909 return (EX_OK); 910 } 911 /* 912 ** MYHOSTNAME -- return the name of this host. 913 ** 914 ** Parameters: 915 ** hostbuf -- a place to return the name of this host. 916 ** size -- the size of hostbuf. 917 ** 918 ** Returns: 919 ** A list of aliases for this host. 920 ** 921 ** Side Effects: 922 ** Adds numeric codes to $=w. 923 */ 924 925 struct hostent * 926 myhostname(hostbuf, size) 927 char hostbuf[]; 928 int size; 929 { 930 register struct hostent *hp; 931 extern bool getcanonname(); 932 extern int h_errno; 933 934 if (gethostname(hostbuf, size) < 0) 935 { 936 (void) strcpy(hostbuf, "localhost"); 937 } 938 hp = sm_gethostbyname(hostbuf); 939 if (hp == NULL) 940 return NULL; 941 if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 942 { 943 (void) strncpy(hostbuf, hp->h_name, size - 1); 944 hostbuf[size - 1] = '\0'; 945 } 946 947 #if NAMED_BIND 948 /* 949 ** If still no dot, try DNS directly (i.e., avoid NIS problems). 950 ** This ought to be driven from the configuration file, but 951 ** we are called before the configuration is read. We could 952 ** check for an /etc/resolv.conf file, but that isn't required. 953 ** All in all, a bit of a mess. 954 */ 955 956 if (strchr(hostbuf, '.') == NULL && 957 !getcanonname(hostbuf, size, TRUE) && 958 h_errno == TRY_AGAIN) 959 { 960 /* try twice in case name server not yet started up */ 961 message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 962 hostbuf); 963 sleep(60); 964 if (!getcanonname(hostbuf, size, TRUE)) 965 errno = h_errno + E_DNSBASE; 966 } 967 #endif 968 return (hp); 969 } 970 /* 971 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 972 ** 973 ** Uses RFC1413 protocol to try to get info from the other end. 974 ** 975 ** Parameters: 976 ** fd -- the descriptor 977 ** 978 ** Returns: 979 ** The user@host information associated with this descriptor. 980 */ 981 982 static jmp_buf CtxAuthTimeout; 983 984 static void 985 authtimeout() 986 { 987 longjmp(CtxAuthTimeout, 1); 988 } 989 990 char * 991 getauthinfo(fd) 992 int fd; 993 { 994 int falen; 995 register char *p; 996 SOCKADDR la; 997 int lalen; 998 register struct servent *sp; 999 int s; 1000 int i; 1001 EVENT *ev; 1002 int nleft; 1003 char ibuf[MAXNAME + 1]; 1004 static char hbuf[MAXNAME * 2 + 2]; 1005 extern char *hostnamebyanyaddr(); 1006 1007 falen = sizeof RealHostAddr; 1008 if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 1009 falen <= 0 || RealHostAddr.sa.sa_family == 0) 1010 { 1011 (void) sprintf(hbuf, "%s@localhost", RealUserName); 1012 if (tTd(9, 1)) 1013 printf("getauthinfo: %s\n", hbuf); 1014 return hbuf; 1015 } 1016 1017 if (RealHostName == NULL) 1018 { 1019 /* translate that to a host name */ 1020 RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 1021 } 1022 1023 if (TimeOuts.to_ident == 0) 1024 goto noident; 1025 1026 lalen = sizeof la; 1027 if (RealHostAddr.sa.sa_family != AF_INET || 1028 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 1029 la.sa.sa_family != AF_INET) 1030 { 1031 /* no ident info */ 1032 goto noident; 1033 } 1034 1035 /* create ident query */ 1036 (void) sprintf(ibuf, "%d,%d\r\n", 1037 ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 1038 1039 /* create local address */ 1040 la.sin.sin_port = 0; 1041 1042 /* create foreign address */ 1043 sp = getservbyname("auth", "tcp"); 1044 if (sp != NULL) 1045 RealHostAddr.sin.sin_port = sp->s_port; 1046 else 1047 RealHostAddr.sin.sin_port = htons(113); 1048 1049 s = -1; 1050 if (setjmp(CtxAuthTimeout) != 0) 1051 { 1052 if (s >= 0) 1053 (void) close(s); 1054 goto noident; 1055 } 1056 1057 /* put a timeout around the whole thing */ 1058 ev = setevent(TimeOuts.to_ident, authtimeout, 0); 1059 1060 /* connect to foreign IDENT server using same address as SMTP socket */ 1061 s = socket(AF_INET, SOCK_STREAM, 0); 1062 if (s < 0) 1063 { 1064 clrevent(ev); 1065 goto noident; 1066 } 1067 if (bind(s, &la.sa, sizeof la.sin) < 0 || 1068 connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 1069 { 1070 goto closeident; 1071 } 1072 1073 if (tTd(9, 10)) 1074 printf("getauthinfo: sent %s", ibuf); 1075 1076 /* send query */ 1077 if (write(s, ibuf, strlen(ibuf)) < 0) 1078 goto closeident; 1079 1080 /* get result */ 1081 p = &ibuf[0]; 1082 nleft = sizeof ibuf - 1; 1083 while ((i = read(s, p, nleft)) > 0) 1084 { 1085 p += i; 1086 nleft -= i; 1087 } 1088 (void) close(s); 1089 clrevent(ev); 1090 if (i < 0 || p == &ibuf[0]) 1091 goto noident; 1092 1093 if (*--p == '\n' && *--p == '\r') 1094 p--; 1095 *++p = '\0'; 1096 1097 if (tTd(9, 3)) 1098 printf("getauthinfo: got %s\n", ibuf); 1099 1100 /* parse result */ 1101 p = strchr(ibuf, ':'); 1102 if (p == NULL) 1103 { 1104 /* malformed response */ 1105 goto noident; 1106 } 1107 while (isascii(*++p) && isspace(*p)) 1108 continue; 1109 if (strncasecmp(p, "userid", 6) != 0) 1110 { 1111 /* presumably an error string */ 1112 goto noident; 1113 } 1114 p += 6; 1115 while (isascii(*p) && isspace(*p)) 1116 p++; 1117 if (*p++ != ':') 1118 { 1119 /* either useridxx or malformed response */ 1120 goto noident; 1121 } 1122 1123 /* p now points to the OSTYPE field */ 1124 while (isascii(*p) && isspace(*p)) 1125 p++; 1126 if (strncasecmp(p, "other", 5) == 0 && 1127 (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) 1128 { 1129 /* not useful information */ 1130 goto noident; 1131 } 1132 p = strchr(p, ':'); 1133 if (p == NULL) 1134 { 1135 /* malformed response */ 1136 goto noident; 1137 } 1138 1139 /* 1413 says don't do this -- but it's broken otherwise */ 1140 while (isascii(*++p) && isspace(*p)) 1141 continue; 1142 1143 /* p now points to the authenticated name -- copy carefully */ 1144 cleanstrcpy(hbuf, p, MAXNAME); 1145 i = strlen(hbuf); 1146 hbuf[i++] = '@'; 1147 strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 1148 goto postident; 1149 1150 closeident: 1151 (void) close(s); 1152 clrevent(ev); 1153 1154 noident: 1155 if (RealHostName == NULL) 1156 { 1157 if (tTd(9, 1)) 1158 printf("getauthinfo: NULL\n"); 1159 return NULL; 1160 } 1161 (void) strcpy(hbuf, RealHostName); 1162 1163 postident: 1164 #if IP_SRCROUTE 1165 /* 1166 ** Extract IP source routing information. 1167 ** 1168 ** Format of output for a connection from site a through b 1169 ** through c to d: 1170 ** loose: @site-c@site-b:site-a 1171 ** strict: !@site-c@site-b:site-a 1172 ** 1173 ** o - pointer within ipopt_list structure. 1174 ** q - pointer within ls/ss rr route data 1175 ** p - pointer to hbuf 1176 */ 1177 1178 if (RealHostAddr.sa.sa_family == AF_INET) 1179 { 1180 int ipoptlen, j; 1181 u_char *q; 1182 u_char *o; 1183 struct in_addr addr; 1184 struct ipoption ipopt; 1185 1186 ipoptlen = sizeof ipopt; 1187 if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 1188 (char *) &ipopt, &ipoptlen) < 0) 1189 goto noipsr; 1190 if (ipoptlen == 0) 1191 goto noipsr; 1192 o = (u_char *) ipopt.ipopt_list; 1193 while (o != NULL && o < (u_char *) &ipopt + ipoptlen) 1194 { 1195 switch (*o) 1196 { 1197 case IPOPT_EOL: 1198 o = NULL; 1199 break; 1200 1201 case IPOPT_NOP: 1202 o++; 1203 break; 1204 1205 case IPOPT_SSRR: 1206 case IPOPT_LSRR: 1207 p = &hbuf[strlen(hbuf)]; 1208 sprintf(p, " [%s@%s", 1209 *o == IPOPT_SSRR ? "!" : "", 1210 inet_ntoa(ipopt.ipopt_dst)); 1211 p += strlen(p); 1212 1213 /* o[1] is option length */ 1214 j = *++o / sizeof(struct in_addr) - 1; 1215 1216 /* q skips length and router pointer to data */ 1217 q = o + 2; 1218 for ( ; j >= 0; j--) 1219 { 1220 memcpy(&addr, q, sizeof(addr)); 1221 sprintf(p, "%c%s", 1222 j ? '@' : ':', 1223 inet_ntoa(addr)); 1224 p += strlen(p); 1225 q += sizeof(struct in_addr); 1226 } 1227 o += *o; 1228 break; 1229 1230 default: 1231 /* Skip over option */ 1232 o += o[1]; 1233 break; 1234 } 1235 } 1236 strcat(hbuf,"]"); 1237 goto postipsr; 1238 } 1239 #endif 1240 1241 noipsr: 1242 if (RealHostName != NULL && RealHostName[0] != '[') 1243 { 1244 p = &hbuf[strlen(hbuf)]; 1245 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 1246 } 1247 1248 postipsr: 1249 if (tTd(9, 1)) 1250 printf("getauthinfo: %s\n", hbuf); 1251 return hbuf; 1252 } 1253 /* 1254 ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 1255 ** 1256 ** Parameters: 1257 ** map -- a pointer to this map (unused). 1258 ** name -- the (presumably unqualified) hostname. 1259 ** av -- unused -- for compatibility with other mapping 1260 ** functions. 1261 ** statp -- an exit status (out parameter) -- set to 1262 ** EX_TEMPFAIL if the name server is unavailable. 1263 ** 1264 ** Returns: 1265 ** The mapping, if found. 1266 ** NULL if no mapping found. 1267 ** 1268 ** Side Effects: 1269 ** Looks up the host specified in hbuf. If it is not 1270 ** the canonical name for that host, return the canonical 1271 ** name. 1272 */ 1273 1274 char * 1275 host_map_lookup(map, name, av, statp) 1276 MAP *map; 1277 char *name; 1278 char **av; 1279 int *statp; 1280 { 1281 register struct hostent *hp; 1282 struct in_addr in_addr; 1283 char *cp; 1284 register STAB *s; 1285 char hbuf[MAXNAME + 1]; 1286 #if NAMED_BIND 1287 extern int h_errno; 1288 #endif 1289 1290 /* 1291 ** See if we have already looked up this name. If so, just 1292 ** return it. 1293 */ 1294 1295 s = stab(name, ST_NAMECANON, ST_ENTER); 1296 if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1297 { 1298 if (tTd(9, 1)) 1299 printf("host_map_lookup(%s) => CACHE %s\n", 1300 name, 1301 s->s_namecanon.nc_cname == NULL 1302 ? "NULL" 1303 : s->s_namecanon.nc_cname); 1304 errno = s->s_namecanon.nc_errno; 1305 #if NAMED_BIND 1306 h_errno = s->s_namecanon.nc_herrno; 1307 #endif 1308 *statp = s->s_namecanon.nc_stat; 1309 if (*statp == EX_TEMPFAIL) 1310 { 1311 CurEnv->e_status = "4.4.3"; 1312 usrerr("451 %s: Name server timeout", 1313 shortenstring(name, 33)); 1314 } 1315 return s->s_namecanon.nc_cname; 1316 } 1317 1318 /* 1319 ** If first character is a bracket, then it is an address 1320 ** lookup. Address is copied into a temporary buffer to 1321 ** strip the brackets and to preserve name if address is 1322 ** unknown. 1323 */ 1324 1325 if (*name != '[') 1326 { 1327 extern bool getcanonname(); 1328 1329 if (tTd(9, 1)) 1330 printf("host_map_lookup(%s) => ", name); 1331 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1332 if (strlen(name) < sizeof hbuf) 1333 (void) strcpy(hbuf, name); 1334 else 1335 { 1336 bcopy(name, hbuf, sizeof hbuf - 1); 1337 hbuf[sizeof hbuf - 1] = '\0'; 1338 } 1339 if (getcanonname(hbuf, sizeof hbuf - 1, !NoMXforCanon)) 1340 { 1341 if (tTd(9, 1)) 1342 printf("%s\n", hbuf); 1343 cp = map_rewrite(map, hbuf, strlen(hbuf), av); 1344 s->s_namecanon.nc_cname = newstr(cp); 1345 return cp; 1346 } 1347 else 1348 { 1349 register struct hostent *hp; 1350 1351 s->s_namecanon.nc_errno = errno; 1352 #if NAMED_BIND 1353 s->s_namecanon.nc_herrno = h_errno; 1354 if (tTd(9, 1)) 1355 printf("FAIL (%d)\n", h_errno); 1356 switch (h_errno) 1357 { 1358 case TRY_AGAIN: 1359 if (UseNameServer) 1360 { 1361 CurEnv->e_status = "4.4.3"; 1362 usrerr("451 %s: Name server timeout", 1363 shortenstring(name, 33)); 1364 } 1365 *statp = EX_TEMPFAIL; 1366 break; 1367 1368 case HOST_NOT_FOUND: 1369 case NO_DATA: 1370 *statp = EX_NOHOST; 1371 break; 1372 1373 case NO_RECOVERY: 1374 *statp = EX_SOFTWARE; 1375 break; 1376 1377 default: 1378 *statp = EX_UNAVAILABLE; 1379 break; 1380 } 1381 #else 1382 if (tTd(9, 1)) 1383 printf("FAIL\n"); 1384 *statp = EX_NOHOST; 1385 #endif 1386 s->s_namecanon.nc_stat = *statp; 1387 if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 1388 UseNameServer) 1389 return NULL; 1390 1391 /* 1392 ** Try to look it up in /etc/hosts 1393 */ 1394 1395 hp = sm_gethostbyname(name); 1396 if (hp == NULL) 1397 { 1398 /* no dice there either */ 1399 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1400 return NULL; 1401 } 1402 1403 s->s_namecanon.nc_stat = *statp = EX_OK; 1404 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1405 s->s_namecanon.nc_cname = newstr(cp); 1406 return cp; 1407 } 1408 } 1409 if ((cp = strchr(name, ']')) == NULL) 1410 return (NULL); 1411 *cp = '\0'; 1412 in_addr.s_addr = inet_addr(&name[1]); 1413 1414 /* nope -- ask the name server */ 1415 hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 1416 s->s_namecanon.nc_errno = errno; 1417 #if NAMED_BIND 1418 s->s_namecanon.nc_herrno = h_errno; 1419 #endif 1420 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1421 if (hp == NULL) 1422 { 1423 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1424 return (NULL); 1425 } 1426 1427 /* found a match -- copy out */ 1428 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1429 s->s_namecanon.nc_stat = *statp = EX_OK; 1430 s->s_namecanon.nc_cname = newstr(cp); 1431 return cp; 1432 } 1433 /* 1434 ** ANYNET_NTOA -- convert a network address to printable form. 1435 ** 1436 ** Parameters: 1437 ** sap -- a pointer to a sockaddr structure. 1438 ** 1439 ** Returns: 1440 ** A printable version of that sockaddr. 1441 */ 1442 1443 #ifdef NETLINK 1444 # include <net/if_dl.h> 1445 #endif 1446 1447 char * 1448 anynet_ntoa(sap) 1449 register SOCKADDR *sap; 1450 { 1451 register char *bp; 1452 register char *ap; 1453 int l; 1454 static char buf[100]; 1455 1456 /* check for null/zero family */ 1457 if (sap == NULL) 1458 return "NULLADDR"; 1459 if (sap->sa.sa_family == 0) 1460 return "0"; 1461 1462 switch (sap->sa.sa_family) 1463 { 1464 #ifdef NETUNIX 1465 case AF_UNIX: 1466 if (sap->sunix.sun_path[0] != '\0') 1467 sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1468 else 1469 sprintf(buf, "[UNIX: localhost]"); 1470 return buf; 1471 #endif 1472 1473 #ifdef NETINET 1474 case AF_INET: 1475 return inet_ntoa(sap->sin.sin_addr); 1476 #endif 1477 1478 #ifdef NETLINK 1479 case AF_LINK: 1480 sprintf(buf, "[LINK: %s]", 1481 link_ntoa((struct sockaddr_dl *) &sap->sa)); 1482 return buf; 1483 #endif 1484 default: 1485 /* this case is needed when nothing is #defined */ 1486 /* in order to keep the switch syntactically correct */ 1487 break; 1488 } 1489 1490 /* unknown family -- just dump bytes */ 1491 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1492 bp = &buf[strlen(buf)]; 1493 ap = sap->sa.sa_data; 1494 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1495 { 1496 (void) sprintf(bp, "%02x:", *ap++ & 0377); 1497 bp += 3; 1498 } 1499 *--bp = '\0'; 1500 return buf; 1501 } 1502 /* 1503 ** HOSTNAMEBYANYADDR -- return name of host based on address 1504 ** 1505 ** Parameters: 1506 ** sap -- SOCKADDR pointer 1507 ** 1508 ** Returns: 1509 ** text representation of host name. 1510 ** 1511 ** Side Effects: 1512 ** none. 1513 */ 1514 1515 char * 1516 hostnamebyanyaddr(sap) 1517 register SOCKADDR *sap; 1518 { 1519 register struct hostent *hp; 1520 int saveretry; 1521 1522 #if NAMED_BIND 1523 /* shorten name server timeout to avoid higher level timeouts */ 1524 saveretry = _res.retry; 1525 _res.retry = 3; 1526 #endif /* NAMED_BIND */ 1527 1528 switch (sap->sa.sa_family) 1529 { 1530 #ifdef NETINET 1531 case AF_INET: 1532 hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 1533 INADDRSZ, 1534 AF_INET); 1535 break; 1536 #endif 1537 1538 #ifdef NETISO 1539 case AF_ISO: 1540 hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 1541 sizeof sap->siso.siso_addr, 1542 AF_ISO); 1543 break; 1544 #endif 1545 1546 case AF_UNIX: 1547 hp = NULL; 1548 break; 1549 1550 default: 1551 hp = sm_gethostbyaddr(sap->sa.sa_data, 1552 sizeof sap->sa.sa_data, 1553 sap->sa.sa_family); 1554 break; 1555 } 1556 1557 #if NAMED_BIND 1558 _res.retry = saveretry; 1559 #endif /* NAMED_BIND */ 1560 1561 if (hp != NULL) 1562 return hp->h_name; 1563 else 1564 { 1565 /* produce a dotted quad */ 1566 static char buf[512]; 1567 1568 (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 1569 return buf; 1570 } 1571 } 1572 1573 # else /* DAEMON */ 1574 /* code for systems without sophisticated networking */ 1575 1576 /* 1577 ** MYHOSTNAME -- stub version for case of no daemon code. 1578 ** 1579 ** Can't convert to upper case here because might be a UUCP name. 1580 ** 1581 ** Mark, you can change this to be anything you want...... 1582 */ 1583 1584 char ** 1585 myhostname(hostbuf, size) 1586 char hostbuf[]; 1587 int size; 1588 { 1589 register FILE *f; 1590 1591 hostbuf[0] = '\0'; 1592 f = fopen("/usr/include/whoami", "r"); 1593 if (f != NULL) 1594 { 1595 (void) fgets(hostbuf, size, f); 1596 fixcrlf(hostbuf, TRUE); 1597 (void) fclose(f); 1598 } 1599 return (NULL); 1600 } 1601 /* 1602 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1603 ** 1604 ** Parameters: 1605 ** fd -- the descriptor 1606 ** 1607 ** Returns: 1608 ** The host name associated with this descriptor, if it can 1609 ** be determined. 1610 ** NULL otherwise. 1611 ** 1612 ** Side Effects: 1613 ** none 1614 */ 1615 1616 char * 1617 getauthinfo(fd) 1618 int fd; 1619 { 1620 return NULL; 1621 } 1622 /* 1623 ** MAPHOSTNAME -- turn a hostname into canonical form 1624 ** 1625 ** Parameters: 1626 ** map -- a pointer to the database map. 1627 ** name -- a buffer containing a hostname. 1628 ** avp -- a pointer to a (cf file defined) argument vector. 1629 ** statp -- an exit status (out parameter). 1630 ** 1631 ** Returns: 1632 ** mapped host name 1633 ** FALSE otherwise. 1634 ** 1635 ** Side Effects: 1636 ** Looks up the host specified in name. If it is not 1637 ** the canonical name for that host, replace it with 1638 ** the canonical name. If the name is unknown, or it 1639 ** is already the canonical name, leave it unchanged. 1640 */ 1641 1642 /*ARGSUSED*/ 1643 char * 1644 host_map_lookup(map, name, avp, statp) 1645 MAP *map; 1646 char *name; 1647 char **avp; 1648 char *statp; 1649 { 1650 register struct hostent *hp; 1651 1652 hp = sm_gethostbyname(name); 1653 if (hp != NULL) 1654 return hp->h_name; 1655 *statp = EX_NOHOST; 1656 return NULL; 1657 } 1658 1659 #endif /* DAEMON */ 1660