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