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