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