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