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