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