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