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