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