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.37 (Berkeley) 02/08/94 (with daemon mode)"; 15 #else 16 static char sccsid[] = "@(#)daemon.c 8.37 (Berkeley) 02/08/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 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 #ifdef 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 #ifdef 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 *p = ']'; 559 goto gothostent; 560 } 561 *p = ']'; 562 } 563 if (p == NULL) 564 { 565 usrerr("553 Invalid numeric domain spec \"%s\"", host); 566 return (EX_NOHOST); 567 } 568 #ifdef NETINET 569 addr.sin.sin_family = AF_INET; /*XXX*/ 570 addr.sin.sin_addr.s_addr = hid; 571 #endif 572 } 573 else 574 { 575 hp = gethostbyname(host); 576 gothostent: 577 if (hp == NULL) 578 { 579 #ifdef NAMED_BIND 580 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 581 return (EX_TEMPFAIL); 582 583 /* if name server is specified, assume temp fail */ 584 if (errno == ECONNREFUSED && UseNameServer) 585 return (EX_TEMPFAIL); 586 #endif 587 return (EX_NOHOST); 588 } 589 addr.sa.sa_family = hp->h_addrtype; 590 switch (hp->h_addrtype) 591 { 592 #ifdef NETINET 593 case AF_INET: 594 bcopy(hp->h_addr, 595 &addr.sin.sin_addr, 596 sizeof addr.sin.sin_addr); 597 break; 598 #endif 599 600 default: 601 bcopy(hp->h_addr, 602 addr.sa.sa_data, 603 hp->h_length); 604 break; 605 } 606 i = 1; 607 } 608 609 /* 610 ** Determine the port number. 611 */ 612 613 if (port != 0) 614 port = htons(port); 615 else 616 { 617 register struct servent *sp = getservbyname("smtp", "tcp"); 618 619 if (sp == NULL) 620 { 621 syserr("554 makeconnection: service \"smtp\" unknown"); 622 port = htons(25); 623 } 624 else 625 port = sp->s_port; 626 } 627 628 switch (addr.sa.sa_family) 629 { 630 #ifdef NETINET 631 case AF_INET: 632 addr.sin.sin_port = port; 633 addrlen = sizeof (struct sockaddr_in); 634 break; 635 #endif 636 637 #ifdef NETISO 638 case AF_ISO: 639 /* assume two byte transport selector */ 640 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 641 addrlen = sizeof (struct sockaddr_iso); 642 break; 643 #endif 644 645 default: 646 syserr("Can't connect to address family %d", addr.sa.sa_family); 647 return (EX_NOHOST); 648 } 649 650 /* 651 ** Try to actually open the connection. 652 */ 653 654 #ifdef XLA 655 /* if too many connections, don't bother trying */ 656 if (!xla_noqueue_ok(host)) 657 return EX_TEMPFAIL; 658 #endif 659 660 for (;;) 661 { 662 if (tTd(16, 1)) 663 printf("makeconnection (%s [%s])\n", 664 host, anynet_ntoa(&addr)); 665 666 /* save for logging */ 667 CurHostAddr = addr; 668 669 if (usesecureport) 670 { 671 int rport = IPPORT_RESERVED - 1; 672 673 s = rresvport(&rport); 674 } 675 else 676 { 677 s = socket(AF_INET, SOCK_STREAM, 0); 678 } 679 if (s < 0) 680 { 681 sav_errno = errno; 682 syserr("makeconnection: no socket"); 683 goto failure; 684 } 685 686 #ifdef SO_SNDBUF 687 if (TcpSndBufferSize > 0) 688 { 689 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 690 (char *) &TcpSndBufferSize, 691 sizeof(TcpSndBufferSize)) < 0) 692 syserr("makeconnection: setsockopt(SO_SNDBUF)"); 693 } 694 #endif 695 696 if (tTd(16, 1)) 697 printf("makeconnection: fd=%d\n", s); 698 699 /* turn on network debugging? */ 700 if (tTd(16, 101)) 701 { 702 int on = 1; 703 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 704 (char *)&on, sizeof on); 705 } 706 if (CurEnv->e_xfp != NULL) 707 (void) fflush(CurEnv->e_xfp); /* for debugging */ 708 errno = 0; /* for debugging */ 709 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 710 break; 711 712 /* couldn't connect.... figure out why */ 713 sav_errno = errno; 714 (void) close(s); 715 if (hp && hp->h_addr_list[i]) 716 { 717 if (tTd(16, 1)) 718 printf("Connect failed (%s); trying new address....\n", 719 errstring(sav_errno)); 720 switch (addr.sa.sa_family) 721 { 722 #ifdef NETINET 723 case AF_INET: 724 bcopy(hp->h_addr_list[i++], 725 &addr.sin.sin_addr, 726 sizeof addr.sin.sin_addr); 727 break; 728 #endif 729 730 default: 731 bcopy(hp->h_addr_list[i++], 732 addr.sa.sa_data, 733 hp->h_length); 734 break; 735 } 736 continue; 737 } 738 739 /* failure, decide if temporary or not */ 740 failure: 741 #ifdef XLA 742 xla_host_end(host); 743 #endif 744 if (transienterror(sav_errno)) 745 return EX_TEMPFAIL; 746 else 747 { 748 message("%s", errstring(sav_errno)); 749 return (EX_UNAVAILABLE); 750 } 751 } 752 753 /* connection ok, put it into canonical form */ 754 if ((mci->mci_out = fdopen(s, "w")) == NULL || 755 (s = dup(s)) < 0 || 756 (mci->mci_in = fdopen(s, "r")) == NULL) 757 { 758 syserr("cannot open SMTP client channel, fd=%d", s); 759 return EX_TEMPFAIL; 760 } 761 762 return (EX_OK); 763 } 764 /* 765 ** MYHOSTNAME -- return the name of this host. 766 ** 767 ** Parameters: 768 ** hostbuf -- a place to return the name of this host. 769 ** size -- the size of hostbuf. 770 ** 771 ** Returns: 772 ** A list of aliases for this host. 773 ** 774 ** Side Effects: 775 ** Adds numeric codes to $=w. 776 */ 777 778 char ** 779 myhostname(hostbuf, size) 780 char hostbuf[]; 781 int size; 782 { 783 register struct hostent *hp; 784 extern struct hostent *gethostbyname(); 785 786 if (gethostname(hostbuf, size) < 0) 787 { 788 (void) strcpy(hostbuf, "localhost"); 789 } 790 hp = gethostbyname(hostbuf); 791 if (hp != NULL) 792 { 793 (void) strncpy(hostbuf, hp->h_name, size - 1); 794 hostbuf[size - 1] = '\0'; 795 796 if (hp->h_addrtype == AF_INET && hp->h_length == 4) 797 { 798 register int i; 799 800 for (i = 0; hp->h_addr_list[i] != NULL; i++) 801 { 802 char ipbuf[100]; 803 804 sprintf(ipbuf, "[%s]", 805 inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); 806 setclass('w', ipbuf); 807 } 808 } 809 810 return (hp->h_aliases); 811 } 812 else 813 return (NULL); 814 } 815 /* 816 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 817 ** 818 ** Uses RFC1413 protocol to try to get info from the other end. 819 ** 820 ** Parameters: 821 ** fd -- the descriptor 822 ** 823 ** Returns: 824 ** The user@host information associated with this descriptor. 825 */ 826 827 #if IDENTPROTO 828 829 static jmp_buf CtxAuthTimeout; 830 831 static 832 authtimeout() 833 { 834 longjmp(CtxAuthTimeout, 1); 835 } 836 837 #endif 838 839 char * 840 getauthinfo(fd) 841 int fd; 842 { 843 SOCKADDR fa; 844 int falen; 845 register char *p; 846 #if IDENTPROTO 847 SOCKADDR la; 848 int lalen; 849 register struct servent *sp; 850 int s; 851 int i; 852 EVENT *ev; 853 #endif 854 static char hbuf[MAXNAME * 2 + 2]; 855 extern char *hostnamebyanyaddr(); 856 extern char RealUserName[]; /* main.c */ 857 858 falen = sizeof fa; 859 if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0 || 860 fa.sa.sa_family == 0) 861 { 862 (void) sprintf(hbuf, "%s@localhost", RealUserName); 863 if (tTd(9, 1)) 864 printf("getauthinfo: %s\n", hbuf); 865 return hbuf; 866 } 867 868 #if IDENTPROTO 869 if (TimeOuts.to_ident == 0) 870 goto noident; 871 872 lalen = sizeof la; 873 if (fa.sa.sa_family != AF_INET || 874 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 875 la.sa.sa_family != AF_INET) 876 { 877 /* no ident info */ 878 goto noident; 879 } 880 881 /* create ident query */ 882 (void) sprintf(hbuf, "%d,%d\r\n", 883 ntohs(fa.sin.sin_port), ntohs(la.sin.sin_port)); 884 885 /* create local address */ 886 la.sin.sin_port = 0; 887 888 /* create foreign address */ 889 sp = getservbyname("auth", "tcp"); 890 if (sp != NULL) 891 fa.sin.sin_port = sp->s_port; 892 else 893 fa.sin.sin_port = htons(113); 894 895 s = -1; 896 if (setjmp(CtxAuthTimeout) != 0) 897 { 898 if (s >= 0) 899 (void) close(s); 900 goto noident; 901 } 902 903 /* put a timeout around the whole thing */ 904 ev = setevent(TimeOuts.to_ident, authtimeout, 0); 905 906 /* connect to foreign IDENT server using same address as SMTP socket */ 907 s = socket(AF_INET, SOCK_STREAM, 0); 908 if (s < 0) 909 { 910 clrevent(ev); 911 goto noident; 912 } 913 if (bind(s, &la.sa, sizeof la.sin) < 0 || 914 connect(s, &fa.sa, sizeof fa.sin) < 0) 915 { 916 goto closeident; 917 } 918 919 if (tTd(9, 10)) 920 printf("getauthinfo: sent %s", hbuf); 921 922 /* send query */ 923 if (write(s, hbuf, strlen(hbuf)) < 0) 924 goto closeident; 925 926 /* get result */ 927 i = read(s, hbuf, sizeof hbuf); 928 (void) close(s); 929 clrevent(ev); 930 if (i <= 0) 931 goto noident; 932 if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 933 i--; 934 hbuf[++i] = '\0'; 935 936 if (tTd(9, 3)) 937 printf("getauthinfo: got %s\n", hbuf); 938 939 /* parse result */ 940 p = strchr(hbuf, ':'); 941 if (p == NULL) 942 { 943 /* malformed response */ 944 goto noident; 945 } 946 while (isascii(*++p) && isspace(*p)) 947 continue; 948 if (strncasecmp(p, "userid", 6) != 0) 949 { 950 /* presumably an error string */ 951 goto noident; 952 } 953 p += 6; 954 while (isascii(*p) && isspace(*p)) 955 p++; 956 if (*p++ != ':') 957 { 958 /* either useridxx or malformed response */ 959 goto noident; 960 } 961 962 /* p now points to the OSTYPE field */ 963 p = strchr(p, ':'); 964 if (p == NULL) 965 { 966 /* malformed response */ 967 goto noident; 968 } 969 970 /* 1413 says don't do this -- but it's broken otherwise */ 971 while (isascii(*++p) && isspace(*p)) 972 continue; 973 974 /* p now points to the authenticated name */ 975 (void) sprintf(hbuf, "%s@%s", 976 p, RealHostName == NULL ? "localhost" : RealHostName); 977 goto finish; 978 979 closeident: 980 (void) close(s); 981 clrevent(ev); 982 983 #endif /* IDENTPROTO */ 984 985 noident: 986 if (RealHostName == NULL) 987 { 988 if (tTd(9, 1)) 989 printf("getauthinfo: NULL\n"); 990 return NULL; 991 } 992 (void) strcpy(hbuf, RealHostName); 993 994 finish: 995 if (RealHostName != NULL && RealHostName[0] != '[') 996 { 997 p = &hbuf[strlen(hbuf)]; 998 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 999 } 1000 if (tTd(9, 1)) 1001 printf("getauthinfo: %s\n", hbuf); 1002 return hbuf; 1003 } 1004 /* 1005 ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 1006 ** 1007 ** Parameters: 1008 ** map -- a pointer to this map (unused). 1009 ** name -- the (presumably unqualified) hostname. 1010 ** av -- unused -- for compatibility with other mapping 1011 ** functions. 1012 ** statp -- an exit status (out parameter) -- set to 1013 ** EX_TEMPFAIL if the name server is unavailable. 1014 ** 1015 ** Returns: 1016 ** The mapping, if found. 1017 ** NULL if no mapping found. 1018 ** 1019 ** Side Effects: 1020 ** Looks up the host specified in hbuf. If it is not 1021 ** the canonical name for that host, return the canonical 1022 ** name. 1023 */ 1024 1025 char * 1026 host_map_lookup(map, name, av, statp) 1027 MAP *map; 1028 char *name; 1029 char **av; 1030 int *statp; 1031 { 1032 register struct hostent *hp; 1033 u_long in_addr; 1034 char *cp; 1035 int i; 1036 register STAB *s; 1037 char hbuf[MAXNAME]; 1038 extern struct hostent *gethostbyaddr(); 1039 #ifdef NAMED_BIND 1040 extern int h_errno; 1041 #endif 1042 1043 /* 1044 ** See if we have already looked up this name. If so, just 1045 ** return it. 1046 */ 1047 1048 s = stab(name, ST_NAMECANON, ST_ENTER); 1049 if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1050 { 1051 if (tTd(9, 1)) 1052 printf("host_map_lookup(%s) => CACHE %s\n", 1053 name, s->s_namecanon.nc_cname); 1054 errno = s->s_namecanon.nc_errno; 1055 #ifdef NAMED_BIND 1056 h_errno = s->s_namecanon.nc_herrno; 1057 #endif 1058 *statp = s->s_namecanon.nc_stat; 1059 if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 1060 { 1061 sprintf(hbuf, "%s: Name server timeout", 1062 shortenstring(name, 33)); 1063 CurEnv->e_message = newstr(hbuf); 1064 } 1065 return s->s_namecanon.nc_cname; 1066 } 1067 1068 /* 1069 ** If first character is a bracket, then it is an address 1070 ** lookup. Address is copied into a temporary buffer to 1071 ** strip the brackets and to preserve name if address is 1072 ** unknown. 1073 */ 1074 1075 if (*name != '[') 1076 { 1077 extern bool getcanonname(); 1078 1079 if (tTd(9, 1)) 1080 printf("host_map_lookup(%s) => ", name); 1081 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1082 (void) strcpy(hbuf, name); 1083 if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 1084 { 1085 if (tTd(9, 1)) 1086 printf("%s\n", hbuf); 1087 cp = map_rewrite(map, hbuf, strlen(hbuf), av); 1088 s->s_namecanon.nc_cname = newstr(cp); 1089 return cp; 1090 } 1091 else 1092 { 1093 register struct hostent *hp; 1094 1095 s->s_namecanon.nc_errno = errno; 1096 #ifdef NAMED_BIND 1097 s->s_namecanon.nc_herrno = h_errno; 1098 if (tTd(9, 1)) 1099 printf("FAIL (%d)\n", h_errno); 1100 switch (h_errno) 1101 { 1102 case TRY_AGAIN: 1103 if (UseNameServer) 1104 { 1105 sprintf(hbuf, "%s: Name server timeout", 1106 shortenstring(name, 33)); 1107 message("%s", hbuf); 1108 if (CurEnv->e_message == NULL) 1109 CurEnv->e_message = newstr(hbuf); 1110 } 1111 *statp = EX_TEMPFAIL; 1112 break; 1113 1114 case HOST_NOT_FOUND: 1115 *statp = EX_NOHOST; 1116 break; 1117 1118 case NO_RECOVERY: 1119 *statp = EX_SOFTWARE; 1120 break; 1121 1122 default: 1123 *statp = EX_UNAVAILABLE; 1124 break; 1125 } 1126 #else 1127 if (tTd(9, 1)) 1128 printf("FAIL\n"); 1129 *statp = EX_NOHOST; 1130 #endif 1131 s->s_namecanon.nc_stat = *statp; 1132 if (*statp != EX_TEMPFAIL || UseNameServer) 1133 return NULL; 1134 1135 /* 1136 ** Try to look it up in /etc/hosts 1137 */ 1138 1139 hp = gethostbyname(name); 1140 if (hp == NULL) 1141 { 1142 /* no dice there either */ 1143 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1144 return NULL; 1145 } 1146 1147 s->s_namecanon.nc_stat = *statp = EX_OK; 1148 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1149 s->s_namecanon.nc_cname = newstr(cp); 1150 return cp; 1151 } 1152 } 1153 if ((cp = strchr(name, ']')) == NULL) 1154 return (NULL); 1155 *cp = '\0'; 1156 in_addr = inet_addr(&name[1]); 1157 1158 /* nope -- ask the name server */ 1159 hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 1160 s->s_namecanon.nc_errno = errno; 1161 #ifdef NAMED_BIND 1162 s->s_namecanon.nc_herrno = h_errno; 1163 #endif 1164 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 1165 if (hp == NULL) 1166 { 1167 s->s_namecanon.nc_stat = *statp = EX_NOHOST; 1168 return (NULL); 1169 } 1170 1171 /* found a match -- copy out */ 1172 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1173 s->s_namecanon.nc_stat = *statp = EX_OK; 1174 s->s_namecanon.nc_cname = newstr(cp); 1175 return cp; 1176 } 1177 /* 1178 ** ANYNET_NTOA -- convert a network address to printable form. 1179 ** 1180 ** Parameters: 1181 ** sap -- a pointer to a sockaddr structure. 1182 ** 1183 ** Returns: 1184 ** A printable version of that sockaddr. 1185 */ 1186 1187 char * 1188 anynet_ntoa(sap) 1189 register SOCKADDR *sap; 1190 { 1191 register char *bp; 1192 register char *ap; 1193 int l; 1194 static char buf[100]; 1195 1196 /* check for null/zero family */ 1197 if (sap == NULL) 1198 return "NULLADDR"; 1199 if (sap->sa.sa_family == 0) 1200 return "0"; 1201 1202 switch (sap->sa.sa_family) 1203 { 1204 #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1205 #ifdef NETUNIX 1206 case AF_UNIX: 1207 if (sap->sunix.sun_path[0] != '\0') 1208 sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1209 else 1210 sprintf(buf, "[UNIX: localhost]"); 1211 return buf; 1212 #endif 1213 #endif 1214 1215 #ifdef NETINET 1216 case AF_INET: 1217 return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 1218 #endif 1219 1220 default: 1221 /* this case is only to ensure syntactic correctness */ 1222 break; 1223 } 1224 1225 /* unknown family -- just dump bytes */ 1226 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1227 bp = &buf[strlen(buf)]; 1228 ap = sap->sa.sa_data; 1229 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1230 { 1231 (void) sprintf(bp, "%02x:", *ap++ & 0377); 1232 bp += 3; 1233 } 1234 *--bp = '\0'; 1235 return buf; 1236 } 1237 /* 1238 ** HOSTNAMEBYANYADDR -- return name of host based on address 1239 ** 1240 ** Parameters: 1241 ** sap -- SOCKADDR pointer 1242 ** 1243 ** Returns: 1244 ** text representation of host name. 1245 ** 1246 ** Side Effects: 1247 ** none. 1248 */ 1249 1250 char * 1251 hostnamebyanyaddr(sap) 1252 register SOCKADDR *sap; 1253 { 1254 register struct hostent *hp; 1255 int saveretry; 1256 1257 #ifdef NAMED_BIND 1258 /* shorten name server timeout to avoid higher level timeouts */ 1259 saveretry = _res.retry; 1260 _res.retry = 3; 1261 #endif /* NAMED_BIND */ 1262 1263 switch (sap->sa.sa_family) 1264 { 1265 #ifdef NETINET 1266 case AF_INET: 1267 hp = gethostbyaddr((char *) &sap->sin.sin_addr, 1268 sizeof sap->sin.sin_addr, 1269 AF_INET); 1270 break; 1271 #endif 1272 1273 #ifdef NETISO 1274 case AF_ISO: 1275 hp = gethostbyaddr((char *) &sap->siso.siso_addr, 1276 sizeof sap->siso.siso_addr, 1277 AF_ISO); 1278 break; 1279 #endif 1280 1281 #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1282 case AF_UNIX: 1283 hp = NULL; 1284 break; 1285 #endif 1286 1287 default: 1288 hp = gethostbyaddr(sap->sa.sa_data, 1289 sizeof sap->sa.sa_data, 1290 sap->sa.sa_family); 1291 break; 1292 } 1293 1294 #ifdef NAMED_BIND 1295 _res.retry = saveretry; 1296 #endif /* NAMED_BIND */ 1297 1298 if (hp != NULL) 1299 return hp->h_name; 1300 else 1301 { 1302 /* produce a dotted quad */ 1303 static char buf[512]; 1304 1305 (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 1306 return buf; 1307 } 1308 } 1309 1310 # else /* DAEMON */ 1311 /* code for systems without sophisticated networking */ 1312 1313 /* 1314 ** MYHOSTNAME -- stub version for case of no daemon code. 1315 ** 1316 ** Can't convert to upper case here because might be a UUCP name. 1317 ** 1318 ** Mark, you can change this to be anything you want...... 1319 */ 1320 1321 char ** 1322 myhostname(hostbuf, size) 1323 char hostbuf[]; 1324 int size; 1325 { 1326 register FILE *f; 1327 1328 hostbuf[0] = '\0'; 1329 f = fopen("/usr/include/whoami", "r"); 1330 if (f != NULL) 1331 { 1332 (void) fgets(hostbuf, size, f); 1333 fixcrlf(hostbuf, TRUE); 1334 (void) fclose(f); 1335 } 1336 return (NULL); 1337 } 1338 /* 1339 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1340 ** 1341 ** Parameters: 1342 ** fd -- the descriptor 1343 ** 1344 ** Returns: 1345 ** The host name associated with this descriptor, if it can 1346 ** be determined. 1347 ** NULL otherwise. 1348 ** 1349 ** Side Effects: 1350 ** none 1351 */ 1352 1353 char * 1354 getauthinfo(fd) 1355 int fd; 1356 { 1357 return NULL; 1358 } 1359 /* 1360 ** MAPHOSTNAME -- turn a hostname into canonical form 1361 ** 1362 ** Parameters: 1363 ** map -- a pointer to the database map. 1364 ** name -- a buffer containing a hostname. 1365 ** avp -- a pointer to a (cf file defined) argument vector. 1366 ** statp -- an exit status (out parameter). 1367 ** 1368 ** Returns: 1369 ** mapped host name 1370 ** FALSE otherwise. 1371 ** 1372 ** Side Effects: 1373 ** Looks up the host specified in name. If it is not 1374 ** the canonical name for that host, replace it with 1375 ** the canonical name. If the name is unknown, or it 1376 ** is already the canonical name, leave it unchanged. 1377 */ 1378 1379 /*ARGSUSED*/ 1380 char * 1381 host_map_lookup(map, name, avp, statp) 1382 MAP *map; 1383 char *name; 1384 char **avp; 1385 char *statp; 1386 { 1387 register struct hostent *hp; 1388 1389 hp = gethostbyname(name); 1390 if (hp != NULL) 1391 return hp->h_name; 1392 *statp = EX_NOHOST; 1393 return NULL; 1394 } 1395 1396 #endif /* DAEMON */ 1397