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.62 (Berkeley) 12/05/94 (with daemon mode)"; 15 #else 16 static char sccsid[] = "@(#)daemon.c 8.62 (Berkeley) 12/05/94 (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 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, &jbuf[sizeof jbuf - 1], 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 161 /* see if we are rejecting connections */ 162 CurrentLA = getla(); 163 if (refuseconnections()) 164 { 165 if (DaemonSocket >= 0) 166 { 167 /* close socket so peer will fail quickly */ 168 (void) close(DaemonSocket); 169 DaemonSocket = -1; 170 } 171 refusingconnections = TRUE; 172 setproctitle("rejecting connections: load average: %d", 173 CurrentLA); 174 sleep(15); 175 continue; 176 } 177 178 /* arrange to (re)open the socket if necessary */ 179 if (refusingconnections) 180 { 181 (void) opendaemonsocket(FALSE); 182 setproctitle("accepting connections"); 183 refusingconnections = FALSE; 184 } 185 186 #ifdef XDEBUG 187 /* check for disaster */ 188 { 189 register STAB *s; 190 char jbuf[MAXHOSTNAMELEN]; 191 192 expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 193 if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL || 194 !bitnset('w', s->s_class)) 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 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) close(DaemonSocket); 257 DisConnected = FALSE; 258 259 setproctitle("startup with %s", 260 anynet_ntoa(&RealHostAddr)); 261 262 /* determine host name */ 263 p = hostnamebyanyaddr(&RealHostAddr); 264 RealHostName = newstr(p); 265 setproctitle("startup with %s", p); 266 267 #ifdef LOG 268 if (LogLevel > 11) 269 { 270 /* log connection information */ 271 syslog(LOG_INFO, "connect from %s (%s)", 272 RealHostName, anynet_ntoa(&RealHostAddr)); 273 } 274 #endif 275 276 if ((InChannel = fdopen(t, "r")) == NULL || 277 (t = dup(t)) < 0 || 278 (OutChannel = fdopen(t, "w")) == NULL) 279 { 280 syserr("cannot open SMTP server channel, fd=%d", t); 281 exit(0); 282 } 283 284 /* should we check for illegal connection here? XXX */ 285 #ifdef XLA 286 if (!xla_host_ok(RealHostName)) 287 { 288 message("421 Too many SMTP sessions for this host"); 289 exit(0); 290 } 291 #endif 292 293 if (tTd(15, 2)) 294 printf("getreq: returning\n"); 295 return; 296 } 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; 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 # ifdef NETINET 380 case AF_INET: 381 socksize = sizeof DaemonAddr.sin; 382 break; 383 # endif 384 385 # ifdef 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 clrdaemon() 430 { 431 if (DaemonSocket >= 0) 432 (void) close(DaemonSocket); 433 DaemonSocket = -1; 434 } 435 /* 436 ** SETDAEMONOPTIONS -- set options for running the daemon 437 ** 438 ** Parameters: 439 ** p -- the options line. 440 ** 441 ** Returns: 442 ** none. 443 */ 444 445 setdaemonoptions(p) 446 register char *p; 447 { 448 if (DaemonAddr.sa.sa_family == AF_UNSPEC) 449 DaemonAddr.sa.sa_family = AF_INET; 450 451 while (p != NULL) 452 { 453 register char *f; 454 register char *v; 455 456 while (isascii(*p) && isspace(*p)) 457 p++; 458 if (*p == '\0') 459 break; 460 f = p; 461 p = strchr(p, ','); 462 if (p != NULL) 463 *p++ = '\0'; 464 v = strchr(f, '='); 465 if (v == NULL) 466 continue; 467 while (isascii(*++v) && isspace(*v)) 468 continue; 469 470 switch (*f) 471 { 472 case 'F': /* address family */ 473 if (isascii(*v) && isdigit(*v)) 474 DaemonAddr.sa.sa_family = atoi(v); 475 #ifdef NETINET 476 else if (strcasecmp(v, "inet") == 0) 477 DaemonAddr.sa.sa_family = AF_INET; 478 #endif 479 #ifdef NETISO 480 else if (strcasecmp(v, "iso") == 0) 481 DaemonAddr.sa.sa_family = AF_ISO; 482 #endif 483 #ifdef NETNS 484 else if (strcasecmp(v, "ns") == 0) 485 DaemonAddr.sa.sa_family = AF_NS; 486 #endif 487 #ifdef NETX25 488 else if (strcasecmp(v, "x.25") == 0) 489 DaemonAddr.sa.sa_family = AF_CCITT; 490 #endif 491 else 492 syserr("554 Unknown address family %s in Family=option", v); 493 break; 494 495 case 'A': /* address */ 496 switch (DaemonAddr.sa.sa_family) 497 { 498 #ifdef NETINET 499 case AF_INET: 500 if (isascii(*v) && isdigit(*v)) 501 DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 502 else 503 { 504 register struct netent *np; 505 506 np = getnetbyname(v); 507 if (np == NULL) 508 syserr("554 network \"%s\" unknown", v); 509 else 510 DaemonAddr.sin.sin_addr.s_addr = np->n_net; 511 } 512 break; 513 #endif 514 515 default: 516 syserr("554 Address= option unsupported for family %d", 517 DaemonAddr.sa.sa_family); 518 break; 519 } 520 break; 521 522 case 'P': /* port */ 523 switch (DaemonAddr.sa.sa_family) 524 { 525 short port; 526 527 #ifdef NETINET 528 case AF_INET: 529 if (isascii(*v) && isdigit(*v)) 530 DaemonAddr.sin.sin_port = htons(atoi(v)); 531 else 532 { 533 register struct servent *sp; 534 535 sp = getservbyname(v, "tcp"); 536 if (sp == NULL) 537 syserr("554 service \"%s\" unknown", v); 538 else 539 DaemonAddr.sin.sin_port = sp->s_port; 540 } 541 break; 542 #endif 543 544 #ifdef NETISO 545 case AF_ISO: 546 /* assume two byte transport selector */ 547 if (isascii(*v) && isdigit(*v)) 548 port = htons(atoi(v)); 549 else 550 { 551 register struct servent *sp; 552 553 sp = getservbyname(v, "tcp"); 554 if (sp == NULL) 555 syserr("554 service \"%s\" unknown", v); 556 else 557 port = sp->s_port; 558 } 559 bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 560 break; 561 #endif 562 563 default: 564 syserr("554 Port= option unsupported for family %d", 565 DaemonAddr.sa.sa_family); 566 break; 567 } 568 break; 569 570 case 'L': /* listen queue size */ 571 ListenQueueSize = atoi(v); 572 break; 573 574 case 'S': /* send buffer size */ 575 TcpSndBufferSize = atoi(v); 576 break; 577 578 case 'R': /* receive buffer size */ 579 TcpRcvBufferSize = atoi(v); 580 break; 581 } 582 } 583 } 584 /* 585 ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 586 ** 587 ** Parameters: 588 ** host -- the name of the host. 589 ** port -- the port number to connect to. 590 ** mci -- a pointer to the mail connection information 591 ** structure to be filled in. 592 ** usesecureport -- if set, use a low numbered (reserved) 593 ** port to provide some rudimentary authentication. 594 ** 595 ** Returns: 596 ** An exit code telling whether the connection could be 597 ** made and if not why not. 598 ** 599 ** Side Effects: 600 ** none. 601 */ 602 603 SOCKADDR CurHostAddr; /* address of current host */ 604 605 int 606 makeconnection(host, port, mci, usesecureport) 607 char *host; 608 u_short port; 609 register MCI *mci; 610 bool usesecureport; 611 { 612 register int i, s; 613 register struct hostent *hp = (struct hostent *)NULL; 614 SOCKADDR addr; 615 int sav_errno; 616 int addrlen; 617 bool firstconnect; 618 #if NAMED_BIND 619 extern int h_errno; 620 #endif 621 622 /* 623 ** Set up the address for the mailer. 624 ** Accept "[a.b.c.d]" syntax for host name. 625 */ 626 627 #if NAMED_BIND 628 h_errno = 0; 629 #endif 630 errno = 0; 631 bzero(&CurHostAddr, sizeof CurHostAddr); 632 SmtpPhase = mci->mci_phase = "initial connection"; 633 CurHostName = host; 634 635 if (host[0] == '[') 636 { 637 long hid; 638 register char *p = strchr(host, ']'); 639 640 if (p != NULL) 641 { 642 *p = '\0'; 643 #ifdef NETINET 644 hid = inet_addr(&host[1]); 645 if (hid == -1) 646 #endif 647 { 648 /* try it as a host name (avoid MX lookup) */ 649 hp = gethostbyname(&host[1]); 650 if (hp == NULL && p[-1] == '.') 651 { 652 #ifdef NAMED_BIND 653 int oldopts = _res.options; 654 655 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 656 #endif 657 p[-1] = '\0'; 658 hp = gethostbyname(&host[1]); 659 p[-1] = '.'; 660 #ifdef NAMED_BIND 661 _res.options = oldopts; 662 #endif 663 } 664 *p = ']'; 665 goto gothostent; 666 } 667 *p = ']'; 668 } 669 if (p == NULL) 670 { 671 usrerr("553 Invalid numeric domain spec \"%s\"", host); 672 return (EX_NOHOST); 673 } 674 #ifdef NETINET 675 addr.sin.sin_family = AF_INET; /*XXX*/ 676 addr.sin.sin_addr.s_addr = hid; 677 #endif 678 } 679 else 680 { 681 register char *p = &host[strlen(host) - 1]; 682 683 hp = gethostbyname(host); 684 if (hp == NULL && *p == '.') 685 { 686 #ifdef NAMED_BIND 687 int oldopts = _res.options; 688 689 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 690 #endif 691 *p = '\0'; 692 hp = gethostbyname(host); 693 *p = '.'; 694 #ifdef NAMED_BIND 695 _res.options = oldopts; 696 #endif 697 } 698 gothostent: 699 if (hp == NULL) 700 { 701 #if NAMED_BIND 702 /* check for name server timeouts */ 703 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 704 (errno == ECONNREFUSED && UseNameServer)) 705 { 706 mci->mci_status = "466"; 707 return (EX_TEMPFAIL); 708 } 709 #endif 710 return (EX_NOHOST); 711 } 712 addr.sa.sa_family = hp->h_addrtype; 713 switch (hp->h_addrtype) 714 { 715 #ifdef NETINET 716 case AF_INET: 717 bcopy(hp->h_addr, 718 &addr.sin.sin_addr, 719 INADDRSZ); 720 break; 721 #endif 722 723 default: 724 bcopy(hp->h_addr, 725 addr.sa.sa_data, 726 hp->h_length); 727 break; 728 } 729 i = 1; 730 } 731 732 /* 733 ** Determine the port number. 734 */ 735 736 if (port != 0) 737 port = htons(port); 738 else 739 { 740 register struct servent *sp = getservbyname("smtp", "tcp"); 741 742 if (sp == NULL) 743 { 744 syserr("554 makeconnection: service \"smtp\" unknown"); 745 port = htons(25); 746 } 747 else 748 port = sp->s_port; 749 } 750 751 switch (addr.sa.sa_family) 752 { 753 #ifdef NETINET 754 case AF_INET: 755 addr.sin.sin_port = port; 756 addrlen = sizeof (struct sockaddr_in); 757 break; 758 #endif 759 760 #ifdef NETISO 761 case AF_ISO: 762 /* assume two byte transport selector */ 763 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 764 addrlen = sizeof (struct sockaddr_iso); 765 break; 766 #endif 767 768 default: 769 syserr("Can't connect to address family %d", addr.sa.sa_family); 770 return (EX_NOHOST); 771 } 772 773 /* 774 ** Try to actually open the connection. 775 */ 776 777 #ifdef XLA 778 /* if too many connections, don't bother trying */ 779 if (!xla_noqueue_ok(host)) 780 return EX_TEMPFAIL; 781 #endif 782 783 firstconnect = TRUE; 784 for (;;) 785 { 786 if (tTd(16, 1)) 787 printf("makeconnection (%s [%s])\n", 788 host, anynet_ntoa(&addr)); 789 790 /* save for logging */ 791 CurHostAddr = addr; 792 793 if (usesecureport) 794 { 795 int rport = IPPORT_RESERVED - 1; 796 797 s = rresvport(&rport); 798 } 799 else 800 { 801 s = socket(AF_INET, SOCK_STREAM, 0); 802 } 803 if (s < 0) 804 { 805 sav_errno = errno; 806 syserr("makeconnection: no socket"); 807 goto failure; 808 } 809 810 #ifdef SO_SNDBUF 811 if (TcpSndBufferSize > 0) 812 { 813 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 814 (char *) &TcpSndBufferSize, 815 sizeof(TcpSndBufferSize)) < 0) 816 syserr("makeconnection: setsockopt(SO_SNDBUF)"); 817 } 818 #endif 819 820 if (tTd(16, 1)) 821 printf("makeconnection: fd=%d\n", s); 822 823 /* turn on network debugging? */ 824 if (tTd(16, 101)) 825 { 826 int on = 1; 827 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 828 (char *)&on, sizeof on); 829 } 830 if (CurEnv->e_xfp != NULL) 831 (void) fflush(CurEnv->e_xfp); /* for debugging */ 832 errno = 0; /* for debugging */ 833 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 834 break; 835 836 /* if running demand-dialed connection, try again */ 837 if (DialDelay > 0 && firstconnect) 838 { 839 if (tTd(16, 1)) 840 printf("Connect failed (%s); trying again...\n", 841 errstring(sav_errno)); 842 firstconnect = FALSE; 843 sleep(DialDelay); 844 continue; 845 } 846 847 /* couldn't connect.... figure out why */ 848 sav_errno = errno; 849 (void) close(s); 850 if (hp && hp->h_addr_list[i]) 851 { 852 if (tTd(16, 1)) 853 printf("Connect failed (%s); trying new address....\n", 854 errstring(sav_errno)); 855 switch (addr.sa.sa_family) 856 { 857 #ifdef NETINET 858 case AF_INET: 859 bcopy(hp->h_addr_list[i++], 860 &addr.sin.sin_addr, 861 INADDRSZ); 862 break; 863 #endif 864 865 default: 866 bcopy(hp->h_addr_list[i++], 867 addr.sa.sa_data, 868 hp->h_length); 869 break; 870 } 871 continue; 872 } 873 874 /* failure, decide if temporary or not */ 875 failure: 876 #ifdef XLA 877 xla_host_end(host); 878 #endif 879 if (transienterror(sav_errno)) 880 return EX_TEMPFAIL; 881 else 882 { 883 message("%s", errstring(sav_errno)); 884 return (EX_UNAVAILABLE); 885 } 886 } 887 888 /* connection ok, put it into canonical form */ 889 if ((mci->mci_out = fdopen(s, "w")) == NULL || 890 (s = dup(s)) < 0 || 891 (mci->mci_in = fdopen(s, "r")) == NULL) 892 { 893 syserr("cannot open SMTP client channel, fd=%d", s); 894 return EX_TEMPFAIL; 895 } 896 897 return (EX_OK); 898 } 899 /* 900 ** MYHOSTNAME -- return the name of this host. 901 ** 902 ** Parameters: 903 ** hostbuf -- a place to return the name of this host. 904 ** size -- the size of hostbuf. 905 ** 906 ** Returns: 907 ** A list of aliases for this host. 908 ** 909 ** Side Effects: 910 ** Adds numeric codes to $=w. 911 */ 912 913 struct hostent * 914 myhostname(hostbuf, size) 915 char hostbuf[]; 916 int size; 917 { 918 register struct hostent *hp; 919 extern struct hostent *gethostbyname(); 920 extern bool getcanonname(); 921 extern int h_errno; 922 923 if (gethostname(hostbuf, size) < 0) 924 { 925 (void) strcpy(hostbuf, "localhost"); 926 } 927 hp = gethostbyname(hostbuf); 928 if (hp == NULL) 929 { 930 syserr("!My host name (%s) does not seem to exist!", hostbuf); 931 } 932 if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 933 { 934 (void) strncpy(hostbuf, hp->h_name, size - 1); 935 hostbuf[size - 1] = '\0'; 936 } 937 938 #if NAMED_BIND 939 /* 940 ** If still no dot, try DNS directly (i.e., avoid NIS problems). 941 ** This ought to be driven from the configuration file, but 942 ** we are called before the configuration is read. We could 943 ** check for an /etc/resolv.conf file, but that isn't required. 944 ** All in all, a bit of a mess. 945 */ 946 947 if (strchr(hostbuf, '.') == NULL && 948 !getcanonname(hostbuf, size, TRUE) && 949 h_errno == TRY_AGAIN) 950 { 951 struct stat stbuf; 952 953 /* try twice in case name server not yet started up */ 954 message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 955 hostbuf); 956 sleep(60); 957 if (!getcanonname(hostbuf, size, TRUE)) 958 errno = h_errno + E_DNSBASE; 959 } 960 #endif 961 return (hp); 962 } 963 /* 964 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 965 ** 966 ** Uses RFC1413 protocol to try to get info from the other end. 967 ** 968 ** Parameters: 969 ** fd -- the descriptor 970 ** 971 ** Returns: 972 ** The user@host information associated with this descriptor. 973 */ 974 975 #if IDENTPROTO 976 977 static jmp_buf CtxAuthTimeout; 978 979 static 980 authtimeout() 981 { 982 longjmp(CtxAuthTimeout, 1); 983 } 984 985 #endif 986 987 char * 988 getauthinfo(fd) 989 int fd; 990 { 991 int falen; 992 register char *p; 993 #if IDENTPROTO 994 SOCKADDR la; 995 int lalen; 996 register struct servent *sp; 997 int s; 998 int i; 999 EVENT *ev; 1000 #endif 1001 static char hbuf[MAXNAME * 2 + 2]; 1002 extern char *hostnamebyanyaddr(); 1003 extern char RealUserName[]; /* main.c */ 1004 1005 falen = sizeof RealHostAddr; 1006 if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 1007 falen <= 0 || RealHostAddr.sa.sa_family == 0) 1008 { 1009 (void) sprintf(hbuf, "%s@localhost", RealUserName); 1010 if (tTd(9, 1)) 1011 printf("getauthinfo: %s\n", hbuf); 1012 return hbuf; 1013 } 1014 1015 if (RealHostName == NULL) 1016 { 1017 /* translate that to a host name */ 1018 RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 1019 } 1020 1021 #if IDENTPROTO 1022 if (TimeOuts.to_ident == 0) 1023 goto noident; 1024 1025 lalen = sizeof la; 1026 if (RealHostAddr.sa.sa_family != AF_INET || 1027 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 1028 la.sa.sa_family != AF_INET) 1029 { 1030 /* no ident info */ 1031 goto noident; 1032 } 1033 1034 /* create ident query */ 1035 (void) sprintf(hbuf, "%d,%d\r\n", 1036 ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 1037 1038 /* create local address */ 1039 la.sin.sin_port = 0; 1040 1041 /* create foreign address */ 1042 sp = getservbyname("auth", "tcp"); 1043 if (sp != NULL) 1044 RealHostAddr.sin.sin_port = sp->s_port; 1045 else 1046 RealHostAddr.sin.sin_port = htons(113); 1047 1048 s = -1; 1049 if (setjmp(CtxAuthTimeout) != 0) 1050 { 1051 if (s >= 0) 1052 (void) close(s); 1053 goto noident; 1054 } 1055 1056 /* put a timeout around the whole thing */ 1057 ev = setevent(TimeOuts.to_ident, authtimeout, 0); 1058 1059 /* connect to foreign IDENT server using same address as SMTP socket */ 1060 s = socket(AF_INET, SOCK_STREAM, 0); 1061 if (s < 0) 1062 { 1063 clrevent(ev); 1064 goto noident; 1065 } 1066 if (bind(s, &la.sa, sizeof la.sin) < 0 || 1067 connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 1068 { 1069 goto closeident; 1070 } 1071 1072 if (tTd(9, 10)) 1073 printf("getauthinfo: sent %s", hbuf); 1074 1075 /* send query */ 1076 if (write(s, hbuf, strlen(hbuf)) < 0) 1077 goto closeident; 1078 1079 /* get result */ 1080 i = read(s, hbuf, sizeof hbuf); 1081 (void) close(s); 1082 clrevent(ev); 1083 if (i <= 0) 1084 goto noident; 1085 if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 1086 i--; 1087 hbuf[++i] = '\0'; 1088 1089 if (tTd(9, 3)) 1090 printf("getauthinfo: got %s\n", hbuf); 1091 1092 /* parse result */ 1093 p = strchr(hbuf, ':'); 1094 if (p == NULL) 1095 { 1096 /* malformed response */ 1097 goto noident; 1098 } 1099 while (isascii(*++p) && isspace(*p)) 1100 continue; 1101 if (strncasecmp(p, "userid", 6) != 0) 1102 { 1103 /* presumably an error string */ 1104 goto noident; 1105 } 1106 p += 6; 1107 while (isascii(*p) && isspace(*p)) 1108 p++; 1109 if (*p++ != ':') 1110 { 1111 /* either useridxx or malformed response */ 1112 goto noident; 1113 } 1114 1115 /* p now points to the OSTYPE field */ 1116 p = strchr(p, ':'); 1117 if (p == NULL) 1118 { 1119 /* malformed response */ 1120 goto noident; 1121 } 1122 1123 /* 1413 says don't do this -- but it's broken otherwise */ 1124 while (isascii(*++p) && isspace(*p)) 1125 continue; 1126 1127 /* p now points to the authenticated name -- copy carefully */ 1128 for (i = 0; i < MAXNAME && *p != '\0'; p++) 1129 { 1130 if (isascii(*p) && 1131 (isalnum(*p) || strchr("!#$%&'*+-./^_`{|}~", *p) != NULL)) 1132 hbuf[i++] = *p; 1133 } 1134 hbuf[i++] = '@'; 1135 strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 1136 goto finish; 1137 1138 closeident: 1139 (void) close(s); 1140 clrevent(ev); 1141 1142 #endif /* IDENTPROTO */ 1143 1144 noident: 1145 if (RealHostName == NULL) 1146 { 1147 if (tTd(9, 1)) 1148 printf("getauthinfo: NULL\n"); 1149 return NULL; 1150 } 1151 (void) strcpy(hbuf, RealHostName); 1152 1153 finish: 1154 if (RealHostName != NULL && RealHostName[0] != '[') 1155 { 1156 p = &hbuf[strlen(hbuf)]; 1157 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 1158 } 1159 if (tTd(9, 1)) 1160 printf("getauthinfo: %s\n", hbuf); 1161 return hbuf; 1162 } 1163 /* 1164 ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 1165 ** 1166 ** Parameters: 1167 ** map -- a pointer to this map (unused). 1168 ** name -- the (presumably unqualified) hostname. 1169 ** av -- unused -- for compatibility with other mapping 1170 ** functions. 1171 ** statp -- an exit status (out parameter) -- set to 1172 ** EX_TEMPFAIL if the name server is unavailable. 1173 ** 1174 ** Returns: 1175 ** The mapping, if found. 1176 ** NULL if no mapping found. 1177 ** 1178 ** Side Effects: 1179 ** Looks up the host specified in hbuf. If it is not 1180 ** the canonical name for that host, return the canonical 1181 ** name. 1182 */ 1183 1184 char * 1185 host_map_lookup(map, name, av, statp) 1186 MAP *map; 1187 char *name; 1188 char **av; 1189 int *statp; 1190 { 1191 register struct hostent *hp; 1192 struct in_addr in_addr; 1193 char *cp; 1194 int i; 1195 register STAB *s; 1196 char hbuf[MAXNAME]; 1197 extern struct hostent *gethostbyaddr(); 1198 #if NAMED_BIND 1199 extern int h_errno; 1200 #endif 1201 1202 /* 1203 ** See if we have already looked up this name. If so, just 1204 ** return it. 1205 */ 1206 1207 s = stab(name, ST_NAMECANON, ST_ENTER); 1208 if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1209 { 1210 if (tTd(9, 1)) 1211 printf("host_map_lookup(%s) => CACHE %s\n", 1212 name, s->s_namecanon.nc_cname); 1213 errno = s->s_namecanon.nc_errno; 1214 #if NAMED_BIND 1215 h_errno = s->s_namecanon.nc_herrno; 1216 #endif 1217 *statp = s->s_namecanon.nc_stat; 1218 if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 1219 { 1220 sprintf(hbuf, "%s: Name server timeout", 1221 shortenstring(name, 33)); 1222 CurEnv->e_message = newstr(hbuf); 1223 } 1224 return s->s_namecanon.nc_cname; 1225 } 1226 1227 /* 1228 ** If first character is a bracket, then it is an address 1229 ** lookup. Address is copied into a temporary buffer to 1230 ** strip the brackets and to preserve name if address is 1231 ** unknown. 1232 */ 1233 1234 if (*name != '[') 1235 { 1236 extern bool getcanonname(); 1237 1238 if (tTd(9, 1)) 1239 printf("host_map_lookup(%s) => ", name); 1240 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1241 (void) strcpy(hbuf, name); 1242 if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 1243 { 1244 if (tTd(9, 1)) 1245 printf("%s\n", hbuf); 1246 cp = map_rewrite(map, hbuf, strlen(hbuf), av); 1247 s->s_namecanon.nc_cname = newstr(cp); 1248 return cp; 1249 } 1250 else 1251 { 1252 register struct hostent *hp; 1253 1254 s->s_namecanon.nc_errno = errno; 1255 #if NAMED_BIND 1256 s->s_namecanon.nc_herrno = h_errno; 1257 if (tTd(9, 1)) 1258 printf("FAIL (%d)\n", h_errno); 1259 switch (h_errno) 1260 { 1261 case TRY_AGAIN: 1262 if (UseNameServer) 1263 { 1264 sprintf(hbuf, "%s: Name server timeout", 1265 shortenstring(name, 33)); 1266 message("%s", hbuf); 1267 if (CurEnv->e_message == NULL) 1268 CurEnv->e_message = newstr(hbuf); 1269 } 1270 *statp = EX_TEMPFAIL; 1271 break; 1272 1273 case HOST_NOT_FOUND: 1274 *statp = EX_NOHOST; 1275 break; 1276 1277 case NO_RECOVERY: 1278 *statp = EX_SOFTWARE; 1279 break; 1280 1281 default: 1282 *statp = EX_UNAVAILABLE; 1283 break; 1284 } 1285 #else 1286 if (tTd(9, 1)) 1287 printf("FAIL\n"); 1288 *statp = EX_NOHOST; 1289 #endif 1290 s->s_namecanon.nc_stat = *statp; 1291 if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 1292 UseNameServer) 1293 return NULL; 1294 1295 /* 1296 ** Try to look it up in /etc/hosts 1297 */ 1298 1299 hp = gethostbyname(name); 1300 if (hp == NULL) 1301 { 1302 /* no dice there either */ 1303 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1304 return NULL; 1305 } 1306 1307 s->s_namecanon.nc_stat = *statp = EX_OK; 1308 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1309 s->s_namecanon.nc_cname = newstr(cp); 1310 return cp; 1311 } 1312 } 1313 if ((cp = strchr(name, ']')) == NULL) 1314 return (NULL); 1315 *cp = '\0'; 1316 in_addr.s_addr = inet_addr(&name[1]); 1317 1318 /* nope -- ask the name server */ 1319 hp = gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 1320 s->s_namecanon.nc_errno = errno; 1321 #if NAMED_BIND 1322 s->s_namecanon.nc_herrno = h_errno; 1323 #endif 1324 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1325 if (hp == NULL) 1326 { 1327 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1328 return (NULL); 1329 } 1330 1331 /* found a match -- copy out */ 1332 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1333 s->s_namecanon.nc_stat = *statp = EX_OK; 1334 s->s_namecanon.nc_cname = newstr(cp); 1335 return cp; 1336 } 1337 /* 1338 ** ANYNET_NTOA -- convert a network address to printable form. 1339 ** 1340 ** Parameters: 1341 ** sap -- a pointer to a sockaddr structure. 1342 ** 1343 ** Returns: 1344 ** A printable version of that sockaddr. 1345 */ 1346 1347 char * 1348 anynet_ntoa(sap) 1349 register SOCKADDR *sap; 1350 { 1351 register char *bp; 1352 register char *ap; 1353 int l; 1354 static char buf[100]; 1355 1356 /* check for null/zero family */ 1357 if (sap == NULL) 1358 return "NULLADDR"; 1359 if (sap->sa.sa_family == 0) 1360 return "0"; 1361 1362 switch (sap->sa.sa_family) 1363 { 1364 #ifdef NETUNIX 1365 case AF_UNIX: 1366 if (sap->sunix.sun_path[0] != '\0') 1367 sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1368 else 1369 sprintf(buf, "[UNIX: localhost]"); 1370 return buf; 1371 #endif 1372 1373 #ifdef NETINET 1374 case AF_INET: 1375 return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 1376 #endif 1377 1378 default: 1379 /* this case is only to ensure syntactic correctness */ 1380 break; 1381 } 1382 1383 /* unknown family -- just dump bytes */ 1384 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1385 bp = &buf[strlen(buf)]; 1386 ap = sap->sa.sa_data; 1387 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1388 { 1389 (void) sprintf(bp, "%02x:", *ap++ & 0377); 1390 bp += 3; 1391 } 1392 *--bp = '\0'; 1393 return buf; 1394 } 1395 /* 1396 ** HOSTNAMEBYANYADDR -- return name of host based on address 1397 ** 1398 ** Parameters: 1399 ** sap -- SOCKADDR pointer 1400 ** 1401 ** Returns: 1402 ** text representation of host name. 1403 ** 1404 ** Side Effects: 1405 ** none. 1406 */ 1407 1408 char * 1409 hostnamebyanyaddr(sap) 1410 register SOCKADDR *sap; 1411 { 1412 register struct hostent *hp; 1413 int saveretry; 1414 1415 #if NAMED_BIND 1416 /* shorten name server timeout to avoid higher level timeouts */ 1417 saveretry = _res.retry; 1418 _res.retry = 3; 1419 #endif /* NAMED_BIND */ 1420 1421 switch (sap->sa.sa_family) 1422 { 1423 #ifdef NETINET 1424 case AF_INET: 1425 hp = gethostbyaddr((char *) &sap->sin.sin_addr, 1426 INADDRSZ, 1427 AF_INET); 1428 break; 1429 #endif 1430 1431 #ifdef NETISO 1432 case AF_ISO: 1433 hp = gethostbyaddr((char *) &sap->siso.siso_addr, 1434 sizeof sap->siso.siso_addr, 1435 AF_ISO); 1436 break; 1437 #endif 1438 1439 case AF_UNIX: 1440 hp = NULL; 1441 break; 1442 1443 default: 1444 hp = gethostbyaddr(sap->sa.sa_data, 1445 sizeof sap->sa.sa_data, 1446 sap->sa.sa_family); 1447 break; 1448 } 1449 1450 #if NAMED_BIND 1451 _res.retry = saveretry; 1452 #endif /* NAMED_BIND */ 1453 1454 if (hp != NULL) 1455 return hp->h_name; 1456 else 1457 { 1458 /* produce a dotted quad */ 1459 static char buf[512]; 1460 1461 (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 1462 return buf; 1463 } 1464 } 1465 1466 # else /* DAEMON */ 1467 /* code for systems without sophisticated networking */ 1468 1469 /* 1470 ** MYHOSTNAME -- stub version for case of no daemon code. 1471 ** 1472 ** Can't convert to upper case here because might be a UUCP name. 1473 ** 1474 ** Mark, you can change this to be anything you want...... 1475 */ 1476 1477 char ** 1478 myhostname(hostbuf, size) 1479 char hostbuf[]; 1480 int size; 1481 { 1482 register FILE *f; 1483 1484 hostbuf[0] = '\0'; 1485 f = fopen("/usr/include/whoami", "r"); 1486 if (f != NULL) 1487 { 1488 (void) fgets(hostbuf, size, f); 1489 fixcrlf(hostbuf, TRUE); 1490 (void) fclose(f); 1491 } 1492 return (NULL); 1493 } 1494 /* 1495 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1496 ** 1497 ** Parameters: 1498 ** fd -- the descriptor 1499 ** 1500 ** Returns: 1501 ** The host name associated with this descriptor, if it can 1502 ** be determined. 1503 ** NULL otherwise. 1504 ** 1505 ** Side Effects: 1506 ** none 1507 */ 1508 1509 char * 1510 getauthinfo(fd) 1511 int fd; 1512 { 1513 return NULL; 1514 } 1515 /* 1516 ** MAPHOSTNAME -- turn a hostname into canonical form 1517 ** 1518 ** Parameters: 1519 ** map -- a pointer to the database map. 1520 ** name -- a buffer containing a hostname. 1521 ** avp -- a pointer to a (cf file defined) argument vector. 1522 ** statp -- an exit status (out parameter). 1523 ** 1524 ** Returns: 1525 ** mapped host name 1526 ** FALSE otherwise. 1527 ** 1528 ** Side Effects: 1529 ** Looks up the host specified in name. If it is not 1530 ** the canonical name for that host, replace it with 1531 ** the canonical name. If the name is unknown, or it 1532 ** is already the canonical name, leave it unchanged. 1533 */ 1534 1535 /*ARGSUSED*/ 1536 char * 1537 host_map_lookup(map, name, avp, statp) 1538 MAP *map; 1539 char *name; 1540 char **avp; 1541 char *statp; 1542 { 1543 register struct hostent *hp; 1544 1545 hp = gethostbyname(name); 1546 if (hp != NULL) 1547 return hp->h_name; 1548 *statp = EX_NOHOST; 1549 return NULL; 1550 } 1551 1552 #endif /* DAEMON */ 1553