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.105 (Berkeley) 06/20/95 (with daemon mode)"; 15 #else 16 static char sccsid[] = "@(#)daemon.c 8.105 (Berkeley) 06/20/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 #if 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 #if 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 sleep(15); 180 continue; 181 } 182 183 /* arrange to (re)open the socket if necessary */ 184 if (refusingconnections) 185 { 186 (void) opendaemonsocket(FALSE); 187 refusingconnections = FALSE; 188 } 189 190 #if XDEBUG 191 /* check for disaster */ 192 { 193 char jbuf[MAXHOSTNAMELEN]; 194 195 expand("\201j", jbuf, sizeof jbuf, CurEnv); 196 if (!wordinclass(jbuf, 'w')) 197 { 198 dumpstate("daemon lost $j"); 199 syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 200 abort(); 201 } 202 else if (j_has_dot && strchr(jbuf, '.') == NULL) 203 { 204 dumpstate("daemon $j lost dot"); 205 syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 206 abort(); 207 } 208 } 209 #endif 210 211 /* wait for a connection */ 212 setproctitle("accepting connections"); 213 do 214 { 215 errno = 0; 216 lotherend = socksize; 217 t = accept(DaemonSocket, 218 (struct sockaddr *)&RealHostAddr, &lotherend); 219 } while (t < 0 && errno == EINTR); 220 if (t < 0) 221 { 222 syserr("getrequests: accept"); 223 224 /* arrange to re-open the socket next time around */ 225 (void) close(DaemonSocket); 226 DaemonSocket = -1; 227 sleep(5); 228 continue; 229 } 230 231 /* 232 ** Create a subprocess to process the mail. 233 */ 234 235 if (tTd(15, 2)) 236 printf("getrequests: forking (fd = %d)\n", t); 237 238 pid = fork(); 239 if (pid < 0) 240 { 241 syserr("daemon: cannot fork"); 242 sleep(10); 243 (void) close(t); 244 continue; 245 } 246 247 if (pid == 0) 248 { 249 char *p; 250 extern char *hostnamebyanyaddr(); 251 extern void intsig(); 252 253 /* 254 ** CHILD -- return to caller. 255 ** Collect verified idea of sending host. 256 ** Verify calling user id if possible here. 257 */ 258 259 (void) setsignal(SIGCHLD, SIG_DFL); 260 (void) setsignal(SIGHUP, intsig); 261 (void) close(DaemonSocket); 262 DisConnected = FALSE; 263 264 setproctitle("startup with %s", 265 anynet_ntoa(&RealHostAddr)); 266 267 /* determine host name */ 268 p = hostnamebyanyaddr(&RealHostAddr); 269 if (strlen(p) > MAXNAME) 270 p[MAXNAME] = '\0'; 271 RealHostName = newstr(p); 272 setproctitle("startup with %s", p); 273 274 if ((InChannel = fdopen(t, "r")) == NULL || 275 (t = dup(t)) < 0 || 276 (OutChannel = fdopen(t, "w")) == NULL) 277 { 278 syserr("cannot open SMTP server channel, fd=%d", t); 279 exit(0); 280 } 281 282 /* should we check for illegal connection here? XXX */ 283 #ifdef XLA 284 if (!xla_host_ok(RealHostName)) 285 { 286 message("421 Too many SMTP sessions for this host"); 287 exit(0); 288 } 289 #endif 290 291 if (tTd(15, 2)) 292 printf("getreq: returning\n"); 293 return; 294 } 295 296 CurChildren++; 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 # if NETINET 380 case AF_INET: 381 socksize = sizeof DaemonAddr.sin; 382 break; 383 # endif 384 385 # if 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 #if NETINET 480 else if (strcasecmp(v, "inet") == 0) 481 DaemonAddr.sa.sa_family = AF_INET; 482 #endif 483 #if NETISO 484 else if (strcasecmp(v, "iso") == 0) 485 DaemonAddr.sa.sa_family = AF_ISO; 486 #endif 487 #if NETNS 488 else if (strcasecmp(v, "ns") == 0) 489 DaemonAddr.sa.sa_family = AF_NS; 490 #endif 491 #if 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 #if 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 #if 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 #if 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 627 /* 628 ** Set up the address for the mailer. 629 ** Accept "[a.b.c.d]" syntax for host name. 630 */ 631 632 #if NAMED_BIND 633 h_errno = 0; 634 #endif 635 errno = 0; 636 bzero(&CurHostAddr, sizeof CurHostAddr); 637 SmtpPhase = mci->mci_phase = "initial connection"; 638 CurHostName = host; 639 640 if (host[0] == '[') 641 { 642 long hid; 643 register char *p = strchr(host, ']'); 644 645 if (p != NULL) 646 { 647 *p = '\0'; 648 #if NETINET 649 hid = inet_addr(&host[1]); 650 if (hid == -1) 651 #endif 652 { 653 /* try it as a host name (avoid MX lookup) */ 654 hp = sm_gethostbyname(&host[1]); 655 if (hp == NULL && p[-1] == '.') 656 { 657 #if NAMED_BIND 658 int oldopts = _res.options; 659 660 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 661 #endif 662 p[-1] = '\0'; 663 hp = sm_gethostbyname(&host[1]); 664 p[-1] = '.'; 665 #if NAMED_BIND 666 _res.options = oldopts; 667 #endif 668 } 669 *p = ']'; 670 goto gothostent; 671 } 672 *p = ']'; 673 } 674 if (p == NULL) 675 { 676 usrerr("553 Invalid numeric domain spec \"%s\"", host); 677 mci->mci_status = "5.1.2"; 678 return (EX_NOHOST); 679 } 680 #if NETINET 681 addr.sin.sin_family = AF_INET; /*XXX*/ 682 addr.sin.sin_addr.s_addr = hid; 683 #endif 684 } 685 else 686 { 687 register char *p = &host[strlen(host) - 1]; 688 689 hp = sm_gethostbyname(host); 690 if (hp == NULL && *p == '.') 691 { 692 #if NAMED_BIND 693 int oldopts = _res.options; 694 695 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 696 #endif 697 *p = '\0'; 698 hp = sm_gethostbyname(host); 699 *p = '.'; 700 #if NAMED_BIND 701 _res.options = oldopts; 702 #endif 703 } 704 gothostent: 705 if (hp == NULL) 706 { 707 #if NAMED_BIND 708 /* check for name server timeouts */ 709 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 710 (errno == ECONNREFUSED && UseNameServer)) 711 { 712 mci->mci_status = "4.4.3"; 713 return (EX_TEMPFAIL); 714 } 715 #endif 716 return (EX_NOHOST); 717 } 718 addr.sa.sa_family = hp->h_addrtype; 719 switch (hp->h_addrtype) 720 { 721 #if NETINET 722 case AF_INET: 723 bcopy(hp->h_addr, 724 &addr.sin.sin_addr, 725 INADDRSZ); 726 break; 727 #endif 728 729 default: 730 bcopy(hp->h_addr, 731 addr.sa.sa_data, 732 hp->h_length); 733 break; 734 } 735 i = 1; 736 } 737 738 /* 739 ** Determine the port number. 740 */ 741 742 if (port == 0) 743 { 744 register struct servent *sp = getservbyname("smtp", "tcp"); 745 746 if (sp == NULL) 747 { 748 #ifdef LOG 749 if (LogLevel > 2) 750 syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown"); 751 #endif 752 port = htons(25); 753 } 754 else 755 port = sp->s_port; 756 } 757 758 switch (addr.sa.sa_family) 759 { 760 #if NETINET 761 case AF_INET: 762 addr.sin.sin_port = port; 763 addrlen = sizeof (struct sockaddr_in); 764 break; 765 #endif 766 767 #if NETISO 768 case AF_ISO: 769 /* assume two byte transport selector */ 770 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 771 addrlen = sizeof (struct sockaddr_iso); 772 break; 773 #endif 774 775 default: 776 syserr("Can't connect to address family %d", addr.sa.sa_family); 777 return (EX_NOHOST); 778 } 779 780 /* 781 ** Try to actually open the connection. 782 */ 783 784 #ifdef XLA 785 /* if too many connections, don't bother trying */ 786 if (!xla_noqueue_ok(host)) 787 return EX_TEMPFAIL; 788 #endif 789 790 firstconnect = TRUE; 791 for (;;) 792 { 793 if (tTd(16, 1)) 794 printf("makeconnection (%s [%s])\n", 795 host, anynet_ntoa(&addr)); 796 797 /* save for logging */ 798 CurHostAddr = addr; 799 800 if (usesecureport) 801 { 802 int rport = IPPORT_RESERVED - 1; 803 804 s = rresvport(&rport); 805 } 806 else 807 { 808 s = socket(AF_INET, SOCK_STREAM, 0); 809 } 810 if (s < 0) 811 { 812 sav_errno = errno; 813 syserr("makeconnection: cannot create socket"); 814 goto failure; 815 } 816 817 #ifdef SO_SNDBUF 818 if (TcpSndBufferSize > 0) 819 { 820 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 821 (char *) &TcpSndBufferSize, 822 sizeof(TcpSndBufferSize)) < 0) 823 syserr("makeconnection: setsockopt(SO_SNDBUF)"); 824 } 825 #endif 826 827 if (tTd(16, 1)) 828 printf("makeconnection: fd=%d\n", s); 829 830 /* turn on network debugging? */ 831 if (tTd(16, 101)) 832 { 833 int on = 1; 834 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 835 (char *)&on, sizeof on); 836 } 837 if (CurEnv->e_xfp != NULL) 838 (void) fflush(CurEnv->e_xfp); /* for debugging */ 839 errno = 0; /* for debugging */ 840 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 841 break; 842 843 /* if running demand-dialed connection, try again */ 844 if (DialDelay > 0 && firstconnect) 845 { 846 if (tTd(16, 1)) 847 printf("Connect failed (%s); trying again...\n", 848 errstring(sav_errno)); 849 firstconnect = FALSE; 850 sleep(DialDelay); 851 continue; 852 } 853 854 /* couldn't connect.... figure out why */ 855 sav_errno = errno; 856 (void) close(s); 857 if (hp != NULL && hp->h_addr_list[i]) 858 { 859 if (tTd(16, 1)) 860 printf("Connect failed (%s); trying new address....\n", 861 errstring(sav_errno)); 862 switch (addr.sa.sa_family) 863 { 864 #if NETINET 865 case AF_INET: 866 bcopy(hp->h_addr_list[i++], 867 &addr.sin.sin_addr, 868 INADDRSZ); 869 break; 870 #endif 871 872 default: 873 bcopy(hp->h_addr_list[i++], 874 addr.sa.sa_data, 875 hp->h_length); 876 break; 877 } 878 continue; 879 } 880 881 /* failure, decide if temporary or not */ 882 failure: 883 #ifdef XLA 884 xla_host_end(host); 885 #endif 886 if (transienterror(sav_errno)) 887 return EX_TEMPFAIL; 888 else 889 { 890 message("%s", errstring(sav_errno)); 891 return (EX_UNAVAILABLE); 892 } 893 } 894 895 /* connection ok, put it into canonical form */ 896 if ((mci->mci_out = fdopen(s, "w")) == NULL || 897 (s = dup(s)) < 0 || 898 (mci->mci_in = fdopen(s, "r")) == NULL) 899 { 900 syserr("cannot open SMTP client channel, fd=%d", s); 901 return EX_TEMPFAIL; 902 } 903 904 return (EX_OK); 905 } 906 /* 907 ** MYHOSTNAME -- return the name of this host. 908 ** 909 ** Parameters: 910 ** hostbuf -- a place to return the name of this host. 911 ** size -- the size of hostbuf. 912 ** 913 ** Returns: 914 ** A list of aliases for this host. 915 ** 916 ** Side Effects: 917 ** Adds numeric codes to $=w. 918 */ 919 920 struct hostent * 921 myhostname(hostbuf, size) 922 char hostbuf[]; 923 int size; 924 { 925 register struct hostent *hp; 926 extern bool getcanonname(); 927 928 if (gethostname(hostbuf, size) < 0) 929 { 930 (void) strcpy(hostbuf, "localhost"); 931 } 932 hp = sm_gethostbyname(hostbuf); 933 if (hp == NULL) 934 return NULL; 935 if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 936 { 937 (void) strncpy(hostbuf, hp->h_name, size - 1); 938 hostbuf[size - 1] = '\0'; 939 } 940 941 /* 942 ** If there is still no dot in the name, try looking for a 943 ** dotted alias. 944 */ 945 946 if (strchr(hostbuf, '.') == NULL) 947 { 948 char **ha; 949 950 for (ha = hp->h_aliases; *ha != NULL; ha++) 951 { 952 if (strchr(*ha, '.') != NULL) 953 { 954 (void) strncpy(hostbuf, *ha, size - 1); 955 hostbuf[size - 1] = '\0'; 956 break; 957 } 958 } 959 } 960 961 /* 962 ** If _still_ no dot, wait for a while and try again -- it is 963 ** possible that some service is starting up. This can result 964 ** in excessive delays if the system is badly configured, but 965 ** there really isn't a way around that, particularly given that 966 ** the config file hasn't been read at this point. 967 ** All in all, a bit of a mess. 968 */ 969 970 if (strchr(hostbuf, '.') == NULL && 971 !getcanonname(hostbuf, size, TRUE)) 972 { 973 message("My unqualifed host name (%s) unknown; sleeping for retry", 974 hostbuf); 975 sleep(60); 976 (void) getcanonname(hostbuf, size, TRUE); 977 } 978 return (hp); 979 } 980 /* 981 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 982 ** 983 ** Uses RFC1413 protocol to try to get info from the other end. 984 ** 985 ** Parameters: 986 ** fd -- the descriptor 987 ** 988 ** Returns: 989 ** The user@host information associated with this descriptor. 990 */ 991 992 static jmp_buf CtxAuthTimeout; 993 994 static void 995 authtimeout() 996 { 997 longjmp(CtxAuthTimeout, 1); 998 } 999 1000 char * 1001 getauthinfo(fd) 1002 int fd; 1003 { 1004 int falen; 1005 register char *p; 1006 SOCKADDR la; 1007 int lalen; 1008 register struct servent *sp; 1009 int s; 1010 int i; 1011 EVENT *ev; 1012 int nleft; 1013 char ibuf[MAXNAME + 1]; 1014 static char hbuf[MAXNAME * 2 + 2]; 1015 extern char *hostnamebyanyaddr(); 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 1297 /* 1298 ** See if we have already looked up this name. If so, just 1299 ** return it. 1300 */ 1301 1302 s = stab(name, ST_NAMECANON, ST_ENTER); 1303 if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1304 { 1305 if (tTd(9, 1)) 1306 printf("host_map_lookup(%s) => CACHE %s\n", 1307 name, 1308 s->s_namecanon.nc_cname == NULL 1309 ? "NULL" 1310 : s->s_namecanon.nc_cname); 1311 errno = s->s_namecanon.nc_errno; 1312 #if NAMED_BIND 1313 h_errno = s->s_namecanon.nc_herrno; 1314 #endif 1315 *statp = s->s_namecanon.nc_stat; 1316 if (*statp == EX_TEMPFAIL) 1317 { 1318 CurEnv->e_status = "4.4.3"; 1319 usrerr("451 %s: Name server timeout", 1320 shortenstring(name, 33)); 1321 } 1322 return s->s_namecanon.nc_cname; 1323 } 1324 1325 /* 1326 ** If first character is a bracket, then it is an address 1327 ** lookup. Address is copied into a temporary buffer to 1328 ** strip the brackets and to preserve name if address is 1329 ** unknown. 1330 */ 1331 1332 if (*name != '[') 1333 { 1334 extern bool getcanonname(); 1335 1336 if (tTd(9, 1)) 1337 printf("host_map_lookup(%s) => ", name); 1338 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1339 if (strlen(name) < sizeof hbuf) 1340 (void) strcpy(hbuf, name); 1341 else 1342 { 1343 bcopy(name, hbuf, sizeof hbuf - 1); 1344 hbuf[sizeof hbuf - 1] = '\0'; 1345 } 1346 if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX)) 1347 { 1348 if (tTd(9, 1)) 1349 printf("%s\n", hbuf); 1350 cp = map_rewrite(map, hbuf, strlen(hbuf), av); 1351 s->s_namecanon.nc_cname = newstr(cp); 1352 return cp; 1353 } 1354 else 1355 { 1356 register struct hostent *hp; 1357 1358 s->s_namecanon.nc_errno = errno; 1359 #if NAMED_BIND 1360 s->s_namecanon.nc_herrno = h_errno; 1361 if (tTd(9, 1)) 1362 printf("FAIL (%d)\n", h_errno); 1363 switch (h_errno) 1364 { 1365 case TRY_AGAIN: 1366 if (UseNameServer) 1367 { 1368 CurEnv->e_status = "4.4.3"; 1369 usrerr("451 %s: Name server timeout", 1370 shortenstring(name, 33)); 1371 } 1372 *statp = EX_TEMPFAIL; 1373 break; 1374 1375 case HOST_NOT_FOUND: 1376 case NO_DATA: 1377 *statp = EX_NOHOST; 1378 break; 1379 1380 case NO_RECOVERY: 1381 *statp = EX_SOFTWARE; 1382 break; 1383 1384 default: 1385 *statp = EX_UNAVAILABLE; 1386 break; 1387 } 1388 #else 1389 if (tTd(9, 1)) 1390 printf("FAIL\n"); 1391 *statp = EX_NOHOST; 1392 #endif 1393 s->s_namecanon.nc_stat = *statp; 1394 if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 1395 UseNameServer) 1396 return NULL; 1397 1398 /* 1399 ** Try to look it up in /etc/hosts 1400 */ 1401 1402 hp = sm_gethostbyname(name); 1403 if (hp == NULL) 1404 { 1405 /* no dice there either */ 1406 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1407 return NULL; 1408 } 1409 1410 s->s_namecanon.nc_stat = *statp = EX_OK; 1411 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1412 s->s_namecanon.nc_cname = newstr(cp); 1413 return cp; 1414 } 1415 } 1416 if ((cp = strchr(name, ']')) == NULL) 1417 return (NULL); 1418 *cp = '\0'; 1419 in_addr.s_addr = inet_addr(&name[1]); 1420 1421 /* nope -- ask the name server */ 1422 hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 1423 s->s_namecanon.nc_errno = errno; 1424 #if NAMED_BIND 1425 s->s_namecanon.nc_herrno = h_errno; 1426 #endif 1427 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1428 if (hp == NULL) 1429 { 1430 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1431 return (NULL); 1432 } 1433 1434 /* found a match -- copy out */ 1435 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1436 s->s_namecanon.nc_stat = *statp = EX_OK; 1437 s->s_namecanon.nc_cname = newstr(cp); 1438 return cp; 1439 } 1440 /* 1441 ** ANYNET_NTOA -- convert a network address to printable form. 1442 ** 1443 ** Parameters: 1444 ** sap -- a pointer to a sockaddr structure. 1445 ** 1446 ** Returns: 1447 ** A printable version of that sockaddr. 1448 */ 1449 1450 #if NETLINK 1451 # include <net/if_dl.h> 1452 #endif 1453 1454 char * 1455 anynet_ntoa(sap) 1456 register SOCKADDR *sap; 1457 { 1458 register char *bp; 1459 register char *ap; 1460 int l; 1461 static char buf[100]; 1462 1463 /* check for null/zero family */ 1464 if (sap == NULL) 1465 return "NULLADDR"; 1466 if (sap->sa.sa_family == 0) 1467 return "0"; 1468 1469 switch (sap->sa.sa_family) 1470 { 1471 #if NETUNIX 1472 case AF_UNIX: 1473 if (sap->sunix.sun_path[0] != '\0') 1474 sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1475 else 1476 sprintf(buf, "[UNIX: localhost]"); 1477 return buf; 1478 #endif 1479 1480 #if NETINET 1481 case AF_INET: 1482 return inet_ntoa(sap->sin.sin_addr); 1483 #endif 1484 1485 #if NETLINK 1486 case AF_LINK: 1487 sprintf(buf, "[LINK: %s]", 1488 link_ntoa((struct sockaddr_dl *) &sap->sa)); 1489 return buf; 1490 #endif 1491 default: 1492 /* this case is needed when nothing is #defined */ 1493 /* in order to keep the switch syntactically correct */ 1494 break; 1495 } 1496 1497 /* unknown family -- just dump bytes */ 1498 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1499 bp = &buf[strlen(buf)]; 1500 ap = sap->sa.sa_data; 1501 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1502 { 1503 (void) sprintf(bp, "%02x:", *ap++ & 0377); 1504 bp += 3; 1505 } 1506 *--bp = '\0'; 1507 return buf; 1508 } 1509 /* 1510 ** HOSTNAMEBYANYADDR -- return name of host based on address 1511 ** 1512 ** Parameters: 1513 ** sap -- SOCKADDR pointer 1514 ** 1515 ** Returns: 1516 ** text representation of host name. 1517 ** 1518 ** Side Effects: 1519 ** none. 1520 */ 1521 1522 char * 1523 hostnamebyanyaddr(sap) 1524 register SOCKADDR *sap; 1525 { 1526 register struct hostent *hp; 1527 int saveretry; 1528 1529 #if NAMED_BIND 1530 /* shorten name server timeout to avoid higher level timeouts */ 1531 saveretry = _res.retry; 1532 _res.retry = 3; 1533 #endif /* NAMED_BIND */ 1534 1535 switch (sap->sa.sa_family) 1536 { 1537 #if NETINET 1538 case AF_INET: 1539 hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 1540 INADDRSZ, 1541 AF_INET); 1542 break; 1543 #endif 1544 1545 #if NETISO 1546 case AF_ISO: 1547 hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 1548 sizeof sap->siso.siso_addr, 1549 AF_ISO); 1550 break; 1551 #endif 1552 1553 case AF_UNIX: 1554 hp = NULL; 1555 break; 1556 1557 default: 1558 hp = sm_gethostbyaddr(sap->sa.sa_data, 1559 sizeof sap->sa.sa_data, 1560 sap->sa.sa_family); 1561 break; 1562 } 1563 1564 #if NAMED_BIND 1565 _res.retry = saveretry; 1566 #endif /* NAMED_BIND */ 1567 1568 if (hp != NULL) 1569 return hp->h_name; 1570 else 1571 { 1572 /* produce a dotted quad */ 1573 static char buf[512]; 1574 1575 (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 1576 return buf; 1577 } 1578 } 1579 1580 # else /* DAEMON */ 1581 /* code for systems without sophisticated networking */ 1582 1583 /* 1584 ** MYHOSTNAME -- stub version for case of no daemon code. 1585 ** 1586 ** Can't convert to upper case here because might be a UUCP name. 1587 ** 1588 ** Mark, you can change this to be anything you want...... 1589 */ 1590 1591 char ** 1592 myhostname(hostbuf, size) 1593 char hostbuf[]; 1594 int size; 1595 { 1596 register FILE *f; 1597 1598 hostbuf[0] = '\0'; 1599 f = fopen("/usr/include/whoami", "r"); 1600 if (f != NULL) 1601 { 1602 (void) fgets(hostbuf, size, f); 1603 fixcrlf(hostbuf, TRUE); 1604 (void) fclose(f); 1605 } 1606 return (NULL); 1607 } 1608 /* 1609 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1610 ** 1611 ** Parameters: 1612 ** fd -- the descriptor 1613 ** 1614 ** Returns: 1615 ** The host name associated with this descriptor, if it can 1616 ** be determined. 1617 ** NULL otherwise. 1618 ** 1619 ** Side Effects: 1620 ** none 1621 */ 1622 1623 char * 1624 getauthinfo(fd) 1625 int fd; 1626 { 1627 return NULL; 1628 } 1629 /* 1630 ** MAPHOSTNAME -- turn a hostname into canonical form 1631 ** 1632 ** Parameters: 1633 ** map -- a pointer to the database map. 1634 ** name -- a buffer containing a hostname. 1635 ** avp -- a pointer to a (cf file defined) argument vector. 1636 ** statp -- an exit status (out parameter). 1637 ** 1638 ** Returns: 1639 ** mapped host name 1640 ** FALSE otherwise. 1641 ** 1642 ** Side Effects: 1643 ** Looks up the host specified in name. If it is not 1644 ** the canonical name for that host, replace it with 1645 ** the canonical name. If the name is unknown, or it 1646 ** is already the canonical name, leave it unchanged. 1647 */ 1648 1649 /*ARGSUSED*/ 1650 char * 1651 host_map_lookup(map, name, avp, statp) 1652 MAP *map; 1653 char *name; 1654 char **avp; 1655 char *statp; 1656 { 1657 register struct hostent *hp; 1658 1659 hp = sm_gethostbyname(name); 1660 if (hp != NULL) 1661 return hp->h_name; 1662 *statp = EX_NOHOST; 1663 return NULL; 1664 } 1665 1666 #endif /* DAEMON */ 1667