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