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