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