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