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