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