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.32 (Berkeley) 01/22/94 (with daemon mode)"; 15 #else 16 static char sccsid[] = "@(#)daemon.c 8.32 (Berkeley) 01/22/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 #ifdef 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 int on = 1; 87 bool refusingconnections = TRUE; 88 FILE *pidf; 89 int socksize; 90 extern void reapchild(); 91 92 /* 93 ** Set up the address for the mailer. 94 */ 95 96 if (DaemonAddr.sin.sin_family == 0) 97 DaemonAddr.sin.sin_family = AF_INET; 98 if (DaemonAddr.sin.sin_addr.s_addr == 0) 99 DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 100 if (DaemonAddr.sin.sin_port == 0) 101 { 102 register struct servent *sp; 103 104 sp = getservbyname("smtp", "tcp"); 105 if (sp == NULL) 106 { 107 syserr("554 service \"smtp\" unknown"); 108 DaemonAddr.sin.sin_port = htons(25); 109 } 110 else 111 DaemonAddr.sin.sin_port = sp->s_port; 112 } 113 114 /* 115 ** Try to actually open the connection. 116 */ 117 118 if (tTd(15, 1)) 119 printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 120 121 /* get a socket for the SMTP connection */ 122 DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 123 if (DaemonSocket < 0) 124 { 125 /* probably another daemon already */ 126 syserr("getrequests: can't create socket"); 127 severe: 128 # ifdef LOG 129 if (LogLevel > 0) 130 syslog(LOG_ALERT, "problem creating SMTP socket"); 131 # endif /* LOG */ 132 finis(); 133 } 134 135 /* turn on network debugging? */ 136 if (tTd(15, 101)) 137 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 138 139 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 140 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 141 142 #ifdef SO_RCVBUF 143 if (TcpRcvBufferSize > 0) 144 { 145 if (setsockopt(DaemonSocket, SOL_SOCKET, SO_RCVBUF, 146 (char *) &TcpRcvBufferSize, 147 sizeof(TcpRcvBufferSize)) < 0) 148 syserr("getrequests: setsockopt(SO_RCVBUF)"); 149 } 150 #endif 151 152 switch (DaemonAddr.sa.sa_family) 153 { 154 # ifdef NETINET 155 case AF_INET: 156 socksize = sizeof DaemonAddr.sin; 157 break; 158 # endif 159 160 # ifdef NETISO 161 case AF_ISO: 162 socksize = sizeof DaemonAddr.siso; 163 break; 164 # endif 165 166 default: 167 socksize = sizeof DaemonAddr; 168 break; 169 } 170 171 if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 172 { 173 syserr("getrequests: cannot bind"); 174 (void) close(DaemonSocket); 175 goto severe; 176 } 177 178 (void) setsignal(SIGCHLD, reapchild); 179 180 /* write the pid to the log file for posterity */ 181 pidf = fopen(PidFile, "w"); 182 if (pidf != NULL) 183 { 184 extern char *CommandLineArgs; 185 186 /* write the process id on line 1 */ 187 fprintf(pidf, "%d\n", getpid()); 188 189 /* line 2 contains all command line flags */ 190 fprintf(pidf, "%s\n", CommandLineArgs); 191 192 /* flush and close */ 193 fclose(pidf); 194 } 195 196 197 if (tTd(15, 1)) 198 printf("getrequests: %d\n", DaemonSocket); 199 200 for (;;) 201 { 202 register int pid; 203 auto int lotherend; 204 extern bool refuseconnections(); 205 206 /* see if we are rejecting connections */ 207 CurrentLA = getla(); 208 if (refuseconnections()) 209 { 210 if (!refusingconnections) 211 { 212 /* don't queue so peer will fail quickly */ 213 (void) listen(DaemonSocket, 0); 214 refusingconnections = TRUE; 215 } 216 setproctitle("rejecting connections: load average: %d", 217 CurrentLA); 218 sleep(5); 219 continue; 220 } 221 222 if (refusingconnections) 223 { 224 /* start listening again */ 225 if (listen(DaemonSocket, ListenQueueSize) < 0) 226 { 227 syserr("getrequests: cannot listen"); 228 (void) close(DaemonSocket); 229 goto severe; 230 } 231 setproctitle("accepting connections"); 232 refusingconnections = FALSE; 233 } 234 235 /* wait for a connection */ 236 do 237 { 238 errno = 0; 239 lotherend = socksize; 240 t = accept(DaemonSocket, 241 (struct sockaddr *)&RealHostAddr, &lotherend); 242 } while (t < 0 && errno == EINTR); 243 if (t < 0) 244 { 245 syserr("getrequests: accept"); 246 sleep(5); 247 continue; 248 } 249 250 /* 251 ** Create a subprocess to process the mail. 252 */ 253 254 if (tTd(15, 2)) 255 printf("getrequests: forking (fd = %d)\n", t); 256 257 pid = fork(); 258 if (pid < 0) 259 { 260 syserr("daemon: cannot fork"); 261 sleep(10); 262 (void) close(t); 263 continue; 264 } 265 266 if (pid == 0) 267 { 268 char *p; 269 extern char *hostnamebyanyaddr(); 270 271 /* 272 ** CHILD -- return to caller. 273 ** Collect verified idea of sending host. 274 ** Verify calling user id if possible here. 275 */ 276 277 (void) setsignal(SIGCHLD, SIG_DFL); 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 port = htons(25); 618 } 619 else 620 port = sp->s_port; 621 } 622 623 switch (addr.sa.sa_family) 624 { 625 #ifdef NETINET 626 case AF_INET: 627 addr.sin.sin_port = port; 628 addrlen = sizeof (struct sockaddr_in); 629 break; 630 #endif 631 632 #ifdef NETISO 633 case AF_ISO: 634 /* assume two byte transport selector */ 635 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 636 addrlen = sizeof (struct sockaddr_iso); 637 break; 638 #endif 639 640 default: 641 syserr("Can't connect to address family %d", addr.sa.sa_family); 642 return (EX_NOHOST); 643 } 644 645 /* 646 ** Try to actually open the connection. 647 */ 648 649 #ifdef XLA 650 /* if too many connections, don't bother trying */ 651 if (!xla_noqueue_ok(host)) 652 return EX_TEMPFAIL; 653 #endif 654 655 for (;;) 656 { 657 if (tTd(16, 1)) 658 printf("makeconnection (%s [%s])\n", 659 host, anynet_ntoa(&addr)); 660 661 /* save for logging */ 662 CurHostAddr = addr; 663 664 if (usesecureport) 665 { 666 int rport = IPPORT_RESERVED - 1; 667 668 s = rresvport(&rport); 669 } 670 else 671 { 672 s = socket(AF_INET, SOCK_STREAM, 0); 673 } 674 if (s < 0) 675 { 676 sav_errno = errno; 677 syserr("makeconnection: no socket"); 678 goto failure; 679 } 680 681 #ifdef SO_SNDBUF 682 if (TcpSndBufferSize > 0) 683 { 684 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 685 (char *) &TcpSndBufferSize, 686 sizeof(TcpSndBufferSize)) < 0) 687 syserr("makeconnection: setsockopt(SO_SNDBUF)"); 688 } 689 #endif 690 691 if (tTd(16, 1)) 692 printf("makeconnection: fd=%d\n", s); 693 694 /* turn on network debugging? */ 695 if (tTd(16, 101)) 696 { 697 int on = 1; 698 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 699 (char *)&on, sizeof on); 700 } 701 if (CurEnv->e_xfp != NULL) 702 (void) fflush(CurEnv->e_xfp); /* for debugging */ 703 errno = 0; /* for debugging */ 704 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 705 break; 706 707 /* couldn't connect.... figure out why */ 708 sav_errno = errno; 709 (void) close(s); 710 if (hp && hp->h_addr_list[i]) 711 { 712 if (tTd(16, 1)) 713 printf("Connect failed (%s); trying new address....\n", 714 errstring(sav_errno)); 715 switch (addr.sa.sa_family) 716 { 717 #ifdef NETINET 718 case AF_INET: 719 bcopy(hp->h_addr_list[i++], 720 &addr.sin.sin_addr, 721 sizeof addr.sin.sin_addr); 722 break; 723 #endif 724 725 default: 726 bcopy(hp->h_addr_list[i++], 727 addr.sa.sa_data, 728 hp->h_length); 729 break; 730 } 731 continue; 732 } 733 734 /* failure, decide if temporary or not */ 735 failure: 736 #ifdef XLA 737 xla_host_end(host); 738 #endif 739 if (transienterror(sav_errno)) 740 return EX_TEMPFAIL; 741 else 742 { 743 message("%s", errstring(sav_errno)); 744 return (EX_UNAVAILABLE); 745 } 746 } 747 748 /* connection ok, put it into canonical form */ 749 if ((mci->mci_out = fdopen(s, "w")) == NULL || 750 (s = dup(s)) < 0 || 751 (mci->mci_in = fdopen(s, "r")) == NULL) 752 { 753 syserr("cannot open SMTP client channel, fd=%d", s); 754 return EX_TEMPFAIL; 755 } 756 757 return (EX_OK); 758 } 759 /* 760 ** MYHOSTNAME -- return the name of this host. 761 ** 762 ** Parameters: 763 ** hostbuf -- a place to return the name of this host. 764 ** size -- the size of hostbuf. 765 ** 766 ** Returns: 767 ** A list of aliases for this host. 768 ** 769 ** Side Effects: 770 ** Adds numeric codes to $=w. 771 */ 772 773 char ** 774 myhostname(hostbuf, size) 775 char hostbuf[]; 776 int size; 777 { 778 register struct hostent *hp; 779 extern struct hostent *gethostbyname(); 780 781 if (gethostname(hostbuf, size) < 0) 782 { 783 (void) strcpy(hostbuf, "localhost"); 784 } 785 hp = gethostbyname(hostbuf); 786 if (hp != NULL) 787 { 788 (void) strncpy(hostbuf, hp->h_name, size - 1); 789 hostbuf[size - 1] = '\0'; 790 791 if (hp->h_addrtype == AF_INET && hp->h_length == 4) 792 { 793 register int i; 794 795 for (i = 0; hp->h_addr_list[i] != NULL; i++) 796 { 797 char ipbuf[100]; 798 799 sprintf(ipbuf, "[%s]", 800 inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); 801 setclass('w', ipbuf); 802 } 803 } 804 805 return (hp->h_aliases); 806 } 807 else 808 return (NULL); 809 } 810 /* 811 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 812 ** 813 ** Uses RFC1413 protocol to try to get info from the other end. 814 ** 815 ** Parameters: 816 ** fd -- the descriptor 817 ** 818 ** Returns: 819 ** The user@host information associated with this descriptor. 820 ** 821 ** Side Effects: 822 ** Sets RealHostName to the name of the host at the other end. 823 */ 824 825 #if IDENTPROTO 826 827 static jmp_buf CtxAuthTimeout; 828 829 static 830 authtimeout() 831 { 832 longjmp(CtxAuthTimeout, 1); 833 } 834 835 #endif 836 837 char * 838 getauthinfo(fd) 839 int fd; 840 { 841 SOCKADDR fa; 842 int falen; 843 register char *p; 844 #if IDENTPROTO 845 SOCKADDR la; 846 int lalen; 847 register struct servent *sp; 848 int s; 849 int i; 850 EVENT *ev; 851 #endif 852 static char hbuf[MAXNAME * 2 + 2]; 853 extern char *hostnamebyanyaddr(); 854 extern char RealUserName[]; /* main.c */ 855 856 falen = sizeof fa; 857 if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0 || 858 fa.sa.sa_family == 0) 859 { 860 RealHostName = "localhost"; 861 (void) sprintf(hbuf, "%s@localhost", RealUserName); 862 if (tTd(9, 1)) 863 printf("getauthinfo: %s\n", hbuf); 864 return hbuf; 865 } 866 867 p = hostnamebyanyaddr(&fa); 868 RealHostName = newstr(p); 869 RealHostAddr = fa; 870 871 #if IDENTPROTO 872 if (TimeOuts.to_ident == 0) 873 goto noident; 874 875 lalen = sizeof la; 876 if (fa.sa.sa_family != AF_INET || 877 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 878 la.sa.sa_family != AF_INET) 879 { 880 /* no ident info */ 881 goto noident; 882 } 883 884 /* create ident query */ 885 (void) sprintf(hbuf, "%d,%d\r\n", 886 ntohs(fa.sin.sin_port), ntohs(la.sin.sin_port)); 887 888 /* create local address */ 889 la.sin.sin_port = 0; 890 891 /* create foreign address */ 892 sp = getservbyname("auth", "tcp"); 893 if (sp != NULL) 894 fa.sin.sin_port = sp->s_port; 895 else 896 fa.sin.sin_port = htons(113); 897 898 s = -1; 899 if (setjmp(CtxAuthTimeout) != 0) 900 { 901 if (s >= 0) 902 (void) close(s); 903 goto noident; 904 } 905 906 /* put a timeout around the whole thing */ 907 ev = setevent(TimeOuts.to_ident, authtimeout, 0); 908 909 /* connect to foreign IDENT server using same address as SMTP socket */ 910 s = socket(AF_INET, SOCK_STREAM, 0); 911 if (s < 0) 912 { 913 clrevent(ev); 914 goto noident; 915 } 916 if (bind(s, &la.sa, sizeof la.sin) < 0 || 917 connect(s, &fa.sa, sizeof fa.sin) < 0) 918 { 919 closeident: 920 (void) close(s); 921 clrevent(ev); 922 goto noident; 923 } 924 925 if (tTd(9, 10)) 926 printf("getauthinfo: sent %s", hbuf); 927 928 /* send query */ 929 if (write(s, hbuf, strlen(hbuf)) < 0) 930 goto closeident; 931 932 /* get result */ 933 i = read(s, hbuf, sizeof hbuf); 934 (void) close(s); 935 clrevent(ev); 936 if (i <= 0) 937 goto noident; 938 if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 939 i--; 940 hbuf[++i] = '\0'; 941 942 if (tTd(9, 3)) 943 printf("getauthinfo: got %s\n", hbuf); 944 945 /* parse result */ 946 p = strchr(hbuf, ':'); 947 if (p == NULL) 948 { 949 /* malformed response */ 950 goto noident; 951 } 952 while (isascii(*++p) && isspace(*p)) 953 continue; 954 if (strncasecmp(p, "userid", 6) != 0) 955 { 956 /* presumably an error string */ 957 goto noident; 958 } 959 p += 6; 960 while (isascii(*p) && isspace(*p)) 961 p++; 962 if (*p++ != ':') 963 { 964 /* either useridxx or malformed response */ 965 goto noident; 966 } 967 968 /* p now points to the OSTYPE field */ 969 p = strchr(p, ':'); 970 if (p == NULL) 971 { 972 /* malformed response */ 973 goto noident; 974 } 975 976 /* 1413 says don't do this -- but it's broken otherwise */ 977 while (isascii(*++p) && isspace(*p)) 978 continue; 979 980 /* p now points to the authenticated name */ 981 (void) sprintf(hbuf, "%s@%s", p, RealHostName); 982 goto finish; 983 984 #endif /* IDENTPROTO */ 985 986 noident: 987 (void) strcpy(hbuf, RealHostName); 988 989 finish: 990 if (RealHostName[0] != '[') 991 { 992 p = &hbuf[strlen(hbuf)]; 993 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 994 } 995 if (tTd(9, 1)) 996 printf("getauthinfo: %s\n", hbuf); 997 return hbuf; 998 } 999 /* 1000 ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 1001 ** 1002 ** Parameters: 1003 ** map -- a pointer to this map (unused). 1004 ** name -- the (presumably unqualified) hostname. 1005 ** av -- unused -- for compatibility with other mapping 1006 ** functions. 1007 ** statp -- an exit status (out parameter) -- set to 1008 ** EX_TEMPFAIL if the name server is unavailable. 1009 ** 1010 ** Returns: 1011 ** The mapping, if found. 1012 ** NULL if no mapping found. 1013 ** 1014 ** Side Effects: 1015 ** Looks up the host specified in hbuf. If it is not 1016 ** the canonical name for that host, return the canonical 1017 ** name. 1018 */ 1019 1020 char * 1021 host_map_lookup(map, name, av, statp) 1022 MAP *map; 1023 char *name; 1024 char **av; 1025 int *statp; 1026 { 1027 register struct hostent *hp; 1028 u_long in_addr; 1029 char *cp; 1030 int i; 1031 register STAB *s; 1032 char hbuf[MAXNAME]; 1033 extern struct hostent *gethostbyaddr(); 1034 extern int h_errno; 1035 1036 /* 1037 ** See if we have already looked up this name. If so, just 1038 ** return it. 1039 */ 1040 1041 s = stab(name, ST_NAMECANON, ST_ENTER); 1042 if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1043 { 1044 if (tTd(9, 1)) 1045 printf("host_map_lookup(%s) => CACHE %s\n", 1046 name, s->s_namecanon.nc_cname); 1047 errno = s->s_namecanon.nc_errno; 1048 h_errno = s->s_namecanon.nc_herrno; 1049 *statp = s->s_namecanon.nc_stat; 1050 if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 1051 { 1052 sprintf(hbuf, "%s: Name server timeout", 1053 shortenstring(name, 33)); 1054 CurEnv->e_message = newstr(hbuf); 1055 } 1056 return s->s_namecanon.nc_cname; 1057 } 1058 1059 /* 1060 ** If first character is a bracket, then it is an address 1061 ** lookup. Address is copied into a temporary buffer to 1062 ** strip the brackets and to preserve name if address is 1063 ** unknown. 1064 */ 1065 1066 if (*name != '[') 1067 { 1068 extern bool getcanonname(); 1069 1070 if (tTd(9, 1)) 1071 printf("host_map_lookup(%s) => ", name); 1072 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1073 (void) strcpy(hbuf, name); 1074 if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 1075 { 1076 if (tTd(9, 1)) 1077 printf("%s\n", hbuf); 1078 cp = map_rewrite(map, hbuf, strlen(hbuf), av); 1079 s->s_namecanon.nc_cname = newstr(cp); 1080 return cp; 1081 } 1082 else 1083 { 1084 register struct hostent *hp; 1085 1086 if (tTd(9, 1)) 1087 printf("FAIL (%d)\n", h_errno); 1088 s->s_namecanon.nc_errno = errno; 1089 s->s_namecanon.nc_herrno = h_errno; 1090 switch (h_errno) 1091 { 1092 case TRY_AGAIN: 1093 if (UseNameServer) 1094 { 1095 sprintf(hbuf, "%s: Name server timeout", 1096 shortenstring(name, 33)); 1097 message("%s", hbuf); 1098 if (CurEnv->e_message == NULL) 1099 CurEnv->e_message = newstr(hbuf); 1100 } 1101 *statp = EX_TEMPFAIL; 1102 break; 1103 1104 case HOST_NOT_FOUND: 1105 *statp = EX_NOHOST; 1106 break; 1107 1108 case NO_RECOVERY: 1109 *statp = EX_SOFTWARE; 1110 break; 1111 1112 default: 1113 *statp = EX_UNAVAILABLE; 1114 break; 1115 } 1116 s->s_namecanon.nc_stat = *statp; 1117 if (*statp != EX_TEMPFAIL || UseNameServer) 1118 return NULL; 1119 1120 /* 1121 ** Try to look it up in /etc/hosts 1122 */ 1123 1124 hp = gethostbyname(name); 1125 if (hp == NULL) 1126 { 1127 /* no dice there either */ 1128 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1129 return NULL; 1130 } 1131 1132 s->s_namecanon.nc_stat = *statp = EX_OK; 1133 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1134 s->s_namecanon.nc_cname = newstr(cp); 1135 return cp; 1136 } 1137 } 1138 if ((cp = strchr(name, ']')) == NULL) 1139 return (NULL); 1140 *cp = '\0'; 1141 in_addr = inet_addr(&name[1]); 1142 1143 /* nope -- ask the name server */ 1144 hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 1145 s->s_namecanon.nc_errno = errno; 1146 s->s_namecanon.nc_herrno = h_errno; 1147 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1148 if (hp == NULL) 1149 { 1150 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1151 return (NULL); 1152 } 1153 1154 /* found a match -- copy out */ 1155 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1156 s->s_namecanon.nc_stat = *statp = EX_OK; 1157 s->s_namecanon.nc_cname = newstr(cp); 1158 return cp; 1159 } 1160 /* 1161 ** ANYNET_NTOA -- convert a network address to printable form. 1162 ** 1163 ** Parameters: 1164 ** sap -- a pointer to a sockaddr structure. 1165 ** 1166 ** Returns: 1167 ** A printable version of that sockaddr. 1168 */ 1169 1170 char * 1171 anynet_ntoa(sap) 1172 register SOCKADDR *sap; 1173 { 1174 register char *bp; 1175 register char *ap; 1176 int l; 1177 static char buf[100]; 1178 1179 /* check for null/zero family */ 1180 if (sap == NULL) 1181 return "NULLADDR"; 1182 if (sap->sa.sa_family == 0) 1183 return "0"; 1184 1185 switch (sap->sa.sa_family) 1186 { 1187 #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1188 #ifdef NETUNIX 1189 case AF_UNIX: 1190 if (sap->sunix.sun_path[0] != '\0') 1191 sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1192 else 1193 sprintf(buf, "[UNIX: localhost]"); 1194 return buf; 1195 #endif 1196 #endif 1197 1198 #ifdef NETINET 1199 case AF_INET: 1200 return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 1201 #endif 1202 1203 default: 1204 /* this case is only to ensure syntactic correctness */ 1205 break; 1206 } 1207 1208 /* unknown family -- just dump bytes */ 1209 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1210 bp = &buf[strlen(buf)]; 1211 ap = sap->sa.sa_data; 1212 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1213 { 1214 (void) sprintf(bp, "%02x:", *ap++ & 0377); 1215 bp += 3; 1216 } 1217 *--bp = '\0'; 1218 return buf; 1219 } 1220 /* 1221 ** HOSTNAMEBYANYADDR -- return name of host based on address 1222 ** 1223 ** Parameters: 1224 ** sap -- SOCKADDR pointer 1225 ** 1226 ** Returns: 1227 ** text representation of host name. 1228 ** 1229 ** Side Effects: 1230 ** none. 1231 */ 1232 1233 char * 1234 hostnamebyanyaddr(sap) 1235 register SOCKADDR *sap; 1236 { 1237 register struct hostent *hp; 1238 int saveretry; 1239 1240 #ifdef NAMED_BIND 1241 /* shorten name server timeout to avoid higher level timeouts */ 1242 saveretry = _res.retry; 1243 _res.retry = 3; 1244 #endif /* NAMED_BIND */ 1245 1246 switch (sap->sa.sa_family) 1247 { 1248 #ifdef NETINET 1249 case AF_INET: 1250 hp = gethostbyaddr((char *) &sap->sin.sin_addr, 1251 sizeof sap->sin.sin_addr, 1252 AF_INET); 1253 break; 1254 #endif 1255 1256 #ifdef NETISO 1257 case AF_ISO: 1258 hp = gethostbyaddr((char *) &sap->siso.siso_addr, 1259 sizeof sap->siso.siso_addr, 1260 AF_ISO); 1261 break; 1262 #endif 1263 1264 #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1265 case AF_UNIX: 1266 hp = NULL; 1267 break; 1268 #endif 1269 1270 default: 1271 hp = gethostbyaddr(sap->sa.sa_data, 1272 sizeof sap->sa.sa_data, 1273 sap->sa.sa_family); 1274 break; 1275 } 1276 1277 #ifdef NAMED_BIND 1278 _res.retry = saveretry; 1279 #endif /* NAMED_BIND */ 1280 1281 if (hp != NULL) 1282 return hp->h_name; 1283 else 1284 { 1285 /* produce a dotted quad */ 1286 static char buf[512]; 1287 1288 (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 1289 return buf; 1290 } 1291 } 1292 1293 # else /* DAEMON */ 1294 /* code for systems without sophisticated networking */ 1295 1296 /* 1297 ** MYHOSTNAME -- stub version for case of no daemon code. 1298 ** 1299 ** Can't convert to upper case here because might be a UUCP name. 1300 ** 1301 ** Mark, you can change this to be anything you want...... 1302 */ 1303 1304 char ** 1305 myhostname(hostbuf, size) 1306 char hostbuf[]; 1307 int size; 1308 { 1309 register FILE *f; 1310 1311 hostbuf[0] = '\0'; 1312 f = fopen("/usr/include/whoami", "r"); 1313 if (f != NULL) 1314 { 1315 (void) fgets(hostbuf, size, f); 1316 fixcrlf(hostbuf, TRUE); 1317 (void) fclose(f); 1318 } 1319 return (NULL); 1320 } 1321 /* 1322 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1323 ** 1324 ** Parameters: 1325 ** fd -- the descriptor 1326 ** 1327 ** Returns: 1328 ** The host name associated with this descriptor, if it can 1329 ** be determined. 1330 ** NULL otherwise. 1331 ** 1332 ** Side Effects: 1333 ** none 1334 */ 1335 1336 char * 1337 getauthinfo(fd) 1338 int fd; 1339 { 1340 return NULL; 1341 } 1342 /* 1343 ** MAPHOSTNAME -- turn a hostname into canonical form 1344 ** 1345 ** Parameters: 1346 ** map -- a pointer to the database map. 1347 ** name -- a buffer containing a hostname. 1348 ** avp -- a pointer to a (cf file defined) argument vector. 1349 ** statp -- an exit status (out parameter). 1350 ** 1351 ** Returns: 1352 ** mapped host name 1353 ** FALSE otherwise. 1354 ** 1355 ** Side Effects: 1356 ** Looks up the host specified in name. If it is not 1357 ** the canonical name for that host, replace it with 1358 ** the canonical name. If the name is unknown, or it 1359 ** is already the canonical name, leave it unchanged. 1360 */ 1361 1362 /*ARGSUSED*/ 1363 char * 1364 host_map_lookup(map, name, avp, statp) 1365 MAP *map; 1366 char *name; 1367 char **avp; 1368 char *statp; 1369 { 1370 register struct hostent *hp; 1371 1372 hp = gethostbyname(name); 1373 if (hp != NULL) 1374 return hp->h_name; 1375 *statp = EX_NOHOST; 1376 return NULL; 1377 } 1378 1379 #endif /* DAEMON */ 1380