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