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.92 (Berkeley) 05/23/95 (with daemon mode)"; 15 #else 16 static char sccsid[] = "@(#)daemon.c 8.92 (Berkeley) 05/23/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 setproctitle("accepting connections"); 190 refusingconnections = FALSE; 191 } 192 193 #ifdef XDEBUG 194 /* check for disaster */ 195 { 196 char jbuf[MAXHOSTNAMELEN]; 197 198 expand("\201j", jbuf, sizeof jbuf, CurEnv); 199 if (!wordinclass(jbuf, 'w')) 200 { 201 dumpstate("daemon lost $j"); 202 syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 203 abort(); 204 } 205 else if (j_has_dot && strchr(jbuf, '.') == NULL) 206 { 207 dumpstate("daemon $j lost dot"); 208 syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 209 abort(); 210 } 211 } 212 #endif 213 214 /* wait for a connection */ 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 extern char RealUserName[]; /* main.c */ 1016 1017 falen = sizeof RealHostAddr; 1018 if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 1019 falen <= 0 || RealHostAddr.sa.sa_family == 0) 1020 { 1021 (void) sprintf(hbuf, "%s@localhost", RealUserName); 1022 if (tTd(9, 1)) 1023 printf("getauthinfo: %s\n", hbuf); 1024 return hbuf; 1025 } 1026 1027 if (RealHostName == NULL) 1028 { 1029 /* translate that to a host name */ 1030 RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 1031 } 1032 1033 if (TimeOuts.to_ident == 0) 1034 goto noident; 1035 1036 lalen = sizeof la; 1037 if (RealHostAddr.sa.sa_family != AF_INET || 1038 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 1039 la.sa.sa_family != AF_INET) 1040 { 1041 /* no ident info */ 1042 goto noident; 1043 } 1044 1045 /* create ident query */ 1046 (void) sprintf(ibuf, "%d,%d\r\n", 1047 ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 1048 1049 /* create local address */ 1050 la.sin.sin_port = 0; 1051 1052 /* create foreign address */ 1053 sp = getservbyname("auth", "tcp"); 1054 if (sp != NULL) 1055 RealHostAddr.sin.sin_port = sp->s_port; 1056 else 1057 RealHostAddr.sin.sin_port = htons(113); 1058 1059 s = -1; 1060 if (setjmp(CtxAuthTimeout) != 0) 1061 { 1062 if (s >= 0) 1063 (void) close(s); 1064 goto noident; 1065 } 1066 1067 /* put a timeout around the whole thing */ 1068 ev = setevent(TimeOuts.to_ident, authtimeout, 0); 1069 1070 /* connect to foreign IDENT server using same address as SMTP socket */ 1071 s = socket(AF_INET, SOCK_STREAM, 0); 1072 if (s < 0) 1073 { 1074 clrevent(ev); 1075 goto noident; 1076 } 1077 if (bind(s, &la.sa, sizeof la.sin) < 0 || 1078 connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 1079 { 1080 goto closeident; 1081 } 1082 1083 if (tTd(9, 10)) 1084 printf("getauthinfo: sent %s", ibuf); 1085 1086 /* send query */ 1087 if (write(s, ibuf, strlen(ibuf)) < 0) 1088 goto closeident; 1089 1090 /* get result */ 1091 p = &ibuf[0]; 1092 nleft = sizeof ibuf - 1; 1093 while ((i = read(s, p, nleft)) > 0) 1094 { 1095 p += i; 1096 nleft -= i; 1097 } 1098 (void) close(s); 1099 clrevent(ev); 1100 if (i < 0 || p == &ibuf[0]) 1101 goto noident; 1102 1103 if (*--p == '\n' && *--p == '\r') 1104 p--; 1105 *++p = '\0'; 1106 1107 if (tTd(9, 3)) 1108 printf("getauthinfo: got %s\n", ibuf); 1109 1110 /* parse result */ 1111 p = strchr(ibuf, ':'); 1112 if (p == NULL) 1113 { 1114 /* malformed response */ 1115 goto noident; 1116 } 1117 while (isascii(*++p) && isspace(*p)) 1118 continue; 1119 if (strncasecmp(p, "userid", 6) != 0) 1120 { 1121 /* presumably an error string */ 1122 goto noident; 1123 } 1124 p += 6; 1125 while (isascii(*p) && isspace(*p)) 1126 p++; 1127 if (*p++ != ':') 1128 { 1129 /* either useridxx or malformed response */ 1130 goto noident; 1131 } 1132 1133 /* p now points to the OSTYPE field */ 1134 while (isascii(*p) && isspace(*p)) 1135 p++; 1136 if (strncasecmp(p, "other", 5) == 0 && 1137 (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) 1138 { 1139 /* not useful information */ 1140 goto noident; 1141 } 1142 p = strchr(p, ':'); 1143 if (p == NULL) 1144 { 1145 /* malformed response */ 1146 goto noident; 1147 } 1148 1149 /* 1413 says don't do this -- but it's broken otherwise */ 1150 while (isascii(*++p) && isspace(*p)) 1151 continue; 1152 1153 /* p now points to the authenticated name -- copy carefully */ 1154 cleanstrcpy(hbuf, p, MAXNAME); 1155 i = strlen(hbuf); 1156 hbuf[i++] = '@'; 1157 strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 1158 goto postident; 1159 1160 closeident: 1161 (void) close(s); 1162 clrevent(ev); 1163 1164 noident: 1165 if (RealHostName == NULL) 1166 { 1167 if (tTd(9, 1)) 1168 printf("getauthinfo: NULL\n"); 1169 return NULL; 1170 } 1171 (void) strcpy(hbuf, RealHostName); 1172 1173 postident: 1174 #if IP_SRCROUTE 1175 /* 1176 ** Extract IP source routing information. 1177 ** 1178 ** Format of output for a connection from site a through b 1179 ** through c to d: 1180 ** loose: @site-c@site-b:site-a 1181 ** strict: !@site-c@site-b:site-a 1182 ** 1183 ** o - pointer within ipopt_list structure. 1184 ** q - pointer within ls/ss rr route data 1185 ** p - pointer to hbuf 1186 */ 1187 1188 if (RealHostAddr.sa.sa_family == AF_INET) 1189 { 1190 int ipoptlen, j; 1191 u_char *q; 1192 u_char *o; 1193 struct in_addr addr; 1194 struct ipoption ipopt; 1195 1196 ipoptlen = sizeof ipopt; 1197 if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 1198 (char *) &ipopt, &ipoptlen) < 0) 1199 goto noipsr; 1200 if (ipoptlen == 0) 1201 goto noipsr; 1202 o = (u_char *) ipopt.ipopt_list; 1203 while (o != NULL && o < (u_char *) (&ipopt + ipoptlen)) 1204 { 1205 switch (*o) 1206 { 1207 case IPOPT_EOL: 1208 o = NULL; 1209 break; 1210 1211 case IPOPT_NOP: 1212 o++; 1213 break; 1214 1215 case IPOPT_SSRR: 1216 case IPOPT_LSRR: 1217 p = &hbuf[strlen(hbuf)]; 1218 sprintf(p, " [%s@%s", 1219 *o == IPOPT_SSRR ? "!" : "", 1220 inet_ntoa(ipopt.ipopt_dst)); 1221 p += strlen(p); 1222 1223 /* o[1] is option length */ 1224 j = *++o / sizeof(struct in_addr) - 1; 1225 1226 /* q skips length and router pointer to data */ 1227 q = o + 2; 1228 for ( ; j >= 0; j--) 1229 { 1230 memcpy(&addr, q, sizeof(addr)); 1231 sprintf(p, "%c%s", 1232 j ? '@' : ':', 1233 inet_ntoa(addr)); 1234 p += strlen(p); 1235 q += sizeof(struct in_addr); 1236 } 1237 o += *o; 1238 break; 1239 1240 default: 1241 /* Skip over option */ 1242 o += o[1]; 1243 break; 1244 } 1245 } 1246 strcat(hbuf,"]"); 1247 goto postipsr; 1248 } 1249 #endif 1250 1251 noipsr: 1252 if (RealHostName != NULL && RealHostName[0] != '[') 1253 { 1254 p = &hbuf[strlen(hbuf)]; 1255 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 1256 } 1257 1258 postipsr: 1259 if (tTd(9, 1)) 1260 printf("getauthinfo: %s\n", hbuf); 1261 return hbuf; 1262 } 1263 /* 1264 ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 1265 ** 1266 ** Parameters: 1267 ** map -- a pointer to this map (unused). 1268 ** name -- the (presumably unqualified) hostname. 1269 ** av -- unused -- for compatibility with other mapping 1270 ** functions. 1271 ** statp -- an exit status (out parameter) -- set to 1272 ** EX_TEMPFAIL if the name server is unavailable. 1273 ** 1274 ** Returns: 1275 ** The mapping, if found. 1276 ** NULL if no mapping found. 1277 ** 1278 ** Side Effects: 1279 ** Looks up the host specified in hbuf. If it is not 1280 ** the canonical name for that host, return the canonical 1281 ** name. 1282 */ 1283 1284 char * 1285 host_map_lookup(map, name, av, statp) 1286 MAP *map; 1287 char *name; 1288 char **av; 1289 int *statp; 1290 { 1291 register struct hostent *hp; 1292 struct in_addr in_addr; 1293 char *cp; 1294 register STAB *s; 1295 char hbuf[MAXNAME + 1]; 1296 #if NAMED_BIND 1297 extern int h_errno; 1298 #endif 1299 1300 /* 1301 ** See if we have already looked up this name. If so, just 1302 ** return it. 1303 */ 1304 1305 s = stab(name, ST_NAMECANON, ST_ENTER); 1306 if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1307 { 1308 if (tTd(9, 1)) 1309 printf("host_map_lookup(%s) => CACHE %s\n", 1310 name, 1311 s->s_namecanon.nc_cname == NULL 1312 ? "NULL" 1313 : s->s_namecanon.nc_cname); 1314 errno = s->s_namecanon.nc_errno; 1315 #if NAMED_BIND 1316 h_errno = s->s_namecanon.nc_herrno; 1317 #endif 1318 *statp = s->s_namecanon.nc_stat; 1319 if (*statp == EX_TEMPFAIL) 1320 { 1321 CurEnv->e_status = "4.4.3"; 1322 usrerr("451 %s: Name server timeout", 1323 shortenstring(name, 33)); 1324 } 1325 return s->s_namecanon.nc_cname; 1326 } 1327 1328 /* 1329 ** If first character is a bracket, then it is an address 1330 ** lookup. Address is copied into a temporary buffer to 1331 ** strip the brackets and to preserve name if address is 1332 ** unknown. 1333 */ 1334 1335 if (*name != '[') 1336 { 1337 extern bool getcanonname(); 1338 1339 if (tTd(9, 1)) 1340 printf("host_map_lookup(%s) => ", name); 1341 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1342 if (strlen(name) < sizeof hbuf) 1343 (void) strcpy(hbuf, name); 1344 else 1345 { 1346 bcopy(name, hbuf, sizeof hbuf - 1); 1347 hbuf[sizeof hbuf - 1] = '\0'; 1348 } 1349 if (getcanonname(hbuf, sizeof hbuf - 1, !NoMXforCanon)) 1350 { 1351 if (tTd(9, 1)) 1352 printf("%s\n", hbuf); 1353 cp = map_rewrite(map, hbuf, strlen(hbuf), av); 1354 s->s_namecanon.nc_cname = newstr(cp); 1355 return cp; 1356 } 1357 else 1358 { 1359 register struct hostent *hp; 1360 1361 s->s_namecanon.nc_errno = errno; 1362 #if NAMED_BIND 1363 s->s_namecanon.nc_herrno = h_errno; 1364 if (tTd(9, 1)) 1365 printf("FAIL (%d)\n", h_errno); 1366 switch (h_errno) 1367 { 1368 case TRY_AGAIN: 1369 if (UseNameServer) 1370 { 1371 CurEnv->e_status = "4.4.3"; 1372 usrerr("451 %s: Name server timeout", 1373 shortenstring(name, 33)); 1374 } 1375 *statp = EX_TEMPFAIL; 1376 break; 1377 1378 case HOST_NOT_FOUND: 1379 case NO_DATA: 1380 *statp = EX_NOHOST; 1381 break; 1382 1383 case NO_RECOVERY: 1384 *statp = EX_SOFTWARE; 1385 break; 1386 1387 default: 1388 *statp = EX_UNAVAILABLE; 1389 break; 1390 } 1391 #else 1392 if (tTd(9, 1)) 1393 printf("FAIL\n"); 1394 *statp = EX_NOHOST; 1395 #endif 1396 s->s_namecanon.nc_stat = *statp; 1397 if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 1398 UseNameServer) 1399 return NULL; 1400 1401 /* 1402 ** Try to look it up in /etc/hosts 1403 */ 1404 1405 hp = sm_gethostbyname(name); 1406 if (hp == NULL) 1407 { 1408 /* no dice there either */ 1409 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1410 return NULL; 1411 } 1412 1413 s->s_namecanon.nc_stat = *statp = EX_OK; 1414 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1415 s->s_namecanon.nc_cname = newstr(cp); 1416 return cp; 1417 } 1418 } 1419 if ((cp = strchr(name, ']')) == NULL) 1420 return (NULL); 1421 *cp = '\0'; 1422 in_addr.s_addr = inet_addr(&name[1]); 1423 1424 /* nope -- ask the name server */ 1425 hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 1426 s->s_namecanon.nc_errno = errno; 1427 #if NAMED_BIND 1428 s->s_namecanon.nc_herrno = h_errno; 1429 #endif 1430 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1431 if (hp == NULL) 1432 { 1433 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1434 return (NULL); 1435 } 1436 1437 /* found a match -- copy out */ 1438 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1439 s->s_namecanon.nc_stat = *statp = EX_OK; 1440 s->s_namecanon.nc_cname = newstr(cp); 1441 return cp; 1442 } 1443 /* 1444 ** ANYNET_NTOA -- convert a network address to printable form. 1445 ** 1446 ** Parameters: 1447 ** sap -- a pointer to a sockaddr structure. 1448 ** 1449 ** Returns: 1450 ** A printable version of that sockaddr. 1451 */ 1452 1453 #ifdef NETLINK 1454 # include <net/if_dl.h> 1455 #endif 1456 1457 char * 1458 anynet_ntoa(sap) 1459 register SOCKADDR *sap; 1460 { 1461 register char *bp; 1462 register char *ap; 1463 int l; 1464 static char buf[100]; 1465 1466 /* check for null/zero family */ 1467 if (sap == NULL) 1468 return "NULLADDR"; 1469 if (sap->sa.sa_family == 0) 1470 return "0"; 1471 1472 switch (sap->sa.sa_family) 1473 { 1474 #ifdef NETUNIX 1475 case AF_UNIX: 1476 if (sap->sunix.sun_path[0] != '\0') 1477 sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1478 else 1479 sprintf(buf, "[UNIX: localhost]"); 1480 return buf; 1481 #endif 1482 1483 #ifdef NETINET 1484 case AF_INET: 1485 return inet_ntoa(sap->sin.sin_addr); 1486 #endif 1487 1488 #ifdef NETLINK 1489 case AF_LINK: 1490 sprintf(buf, "[LINK: %s]", 1491 link_ntoa((struct sockaddr_dl *) &sap->sa)); 1492 return buf; 1493 #endif 1494 default: 1495 /* this case is needed when nothing is #defined */ 1496 /* in order to keep the switch syntactically correct */ 1497 break; 1498 } 1499 1500 /* unknown family -- just dump bytes */ 1501 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1502 bp = &buf[strlen(buf)]; 1503 ap = sap->sa.sa_data; 1504 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1505 { 1506 (void) sprintf(bp, "%02x:", *ap++ & 0377); 1507 bp += 3; 1508 } 1509 *--bp = '\0'; 1510 return buf; 1511 } 1512 /* 1513 ** HOSTNAMEBYANYADDR -- return name of host based on address 1514 ** 1515 ** Parameters: 1516 ** sap -- SOCKADDR pointer 1517 ** 1518 ** Returns: 1519 ** text representation of host name. 1520 ** 1521 ** Side Effects: 1522 ** none. 1523 */ 1524 1525 char * 1526 hostnamebyanyaddr(sap) 1527 register SOCKADDR *sap; 1528 { 1529 register struct hostent *hp; 1530 int saveretry; 1531 1532 #if NAMED_BIND 1533 /* shorten name server timeout to avoid higher level timeouts */ 1534 saveretry = _res.retry; 1535 _res.retry = 3; 1536 #endif /* NAMED_BIND */ 1537 1538 switch (sap->sa.sa_family) 1539 { 1540 #ifdef NETINET 1541 case AF_INET: 1542 hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 1543 INADDRSZ, 1544 AF_INET); 1545 break; 1546 #endif 1547 1548 #ifdef NETISO 1549 case AF_ISO: 1550 hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 1551 sizeof sap->siso.siso_addr, 1552 AF_ISO); 1553 break; 1554 #endif 1555 1556 case AF_UNIX: 1557 hp = NULL; 1558 break; 1559 1560 default: 1561 hp = sm_gethostbyaddr(sap->sa.sa_data, 1562 sizeof sap->sa.sa_data, 1563 sap->sa.sa_family); 1564 break; 1565 } 1566 1567 #if NAMED_BIND 1568 _res.retry = saveretry; 1569 #endif /* NAMED_BIND */ 1570 1571 if (hp != NULL) 1572 return hp->h_name; 1573 else 1574 { 1575 /* produce a dotted quad */ 1576 static char buf[512]; 1577 1578 (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 1579 return buf; 1580 } 1581 } 1582 1583 # else /* DAEMON */ 1584 /* code for systems without sophisticated networking */ 1585 1586 /* 1587 ** MYHOSTNAME -- stub version for case of no daemon code. 1588 ** 1589 ** Can't convert to upper case here because might be a UUCP name. 1590 ** 1591 ** Mark, you can change this to be anything you want...... 1592 */ 1593 1594 char ** 1595 myhostname(hostbuf, size) 1596 char hostbuf[]; 1597 int size; 1598 { 1599 register FILE *f; 1600 1601 hostbuf[0] = '\0'; 1602 f = fopen("/usr/include/whoami", "r"); 1603 if (f != NULL) 1604 { 1605 (void) fgets(hostbuf, size, f); 1606 fixcrlf(hostbuf, TRUE); 1607 (void) fclose(f); 1608 } 1609 return (NULL); 1610 } 1611 /* 1612 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1613 ** 1614 ** Parameters: 1615 ** fd -- the descriptor 1616 ** 1617 ** Returns: 1618 ** The host name associated with this descriptor, if it can 1619 ** be determined. 1620 ** NULL otherwise. 1621 ** 1622 ** Side Effects: 1623 ** none 1624 */ 1625 1626 char * 1627 getauthinfo(fd) 1628 int fd; 1629 { 1630 return NULL; 1631 } 1632 /* 1633 ** MAPHOSTNAME -- turn a hostname into canonical form 1634 ** 1635 ** Parameters: 1636 ** map -- a pointer to the database map. 1637 ** name -- a buffer containing a hostname. 1638 ** avp -- a pointer to a (cf file defined) argument vector. 1639 ** statp -- an exit status (out parameter). 1640 ** 1641 ** Returns: 1642 ** mapped host name 1643 ** FALSE otherwise. 1644 ** 1645 ** Side Effects: 1646 ** Looks up the host specified in name. If it is not 1647 ** the canonical name for that host, replace it with 1648 ** the canonical name. If the name is unknown, or it 1649 ** is already the canonical name, leave it unchanged. 1650 */ 1651 1652 /*ARGSUSED*/ 1653 char * 1654 host_map_lookup(map, name, avp, statp) 1655 MAP *map; 1656 char *name; 1657 char **avp; 1658 char *statp; 1659 { 1660 register struct hostent *hp; 1661 1662 hp = sm_gethostbyname(name); 1663 if (hp != NULL) 1664 return hp->h_name; 1665 *statp = EX_NOHOST; 1666 return NULL; 1667 } 1668 1669 #endif /* DAEMON */ 1670