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