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.41 (Berkeley) 04/21/93 (with daemon mode)"; 16 #else 17 static char sccsid[] = "@(#)daemon.c 6.41 (Berkeley) 04/21/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 OpMode = MD_SMTP; 258 259 /* determine host name */ 260 RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 261 262 #ifdef LOG 263 if (LogLevel > 10) 264 { 265 /* log connection information */ 266 syslog(LOG_INFO, "connect from %s (%s)", 267 RealHostName, anynet_ntoa(&RealHostAddr)); 268 } 269 #endif 270 271 (void) close(DaemonSocket); 272 InChannel = fdopen(t, "r"); 273 OutChannel = fdopen(dup(t), "w"); 274 275 /* should we check for illegal connection here? XXX */ 276 #ifdef XLA 277 if (!xla_host_ok(RealHostName)) 278 { 279 message("421 Too many SMTP sessions for this host"); 280 exit(0); 281 } 282 #endif 283 284 if (tTd(15, 2)) 285 printf("getreq: returning\n"); 286 return; 287 } 288 289 /* close the port so that others will hang (for a while) */ 290 (void) close(t); 291 } 292 /*NOTREACHED*/ 293 } 294 /* 295 ** CLRDAEMON -- reset the daemon connection 296 ** 297 ** Parameters: 298 ** none. 299 ** 300 ** Returns: 301 ** none. 302 ** 303 ** Side Effects: 304 ** releases any resources used by the passive daemon. 305 */ 306 307 clrdaemon() 308 { 309 if (DaemonSocket >= 0) 310 (void) close(DaemonSocket); 311 DaemonSocket = -1; 312 } 313 /* 314 ** SETDAEMONOPTIONS -- set options for running the daemon 315 ** 316 ** Parameters: 317 ** p -- the options line. 318 ** 319 ** Returns: 320 ** none. 321 */ 322 323 setdaemonoptions(p) 324 register char *p; 325 { 326 if (DaemonAddr.sa.sa_family == AF_UNSPEC) 327 DaemonAddr.sa.sa_family = AF_INET; 328 329 while (p != NULL) 330 { 331 register char *f; 332 register char *v; 333 334 while (isascii(*p) && isspace(*p)) 335 p++; 336 if (*p == '\0') 337 break; 338 f = p; 339 p = strchr(p, ','); 340 if (p != NULL) 341 *p++ = '\0'; 342 v = strchr(f, '='); 343 if (v == NULL) 344 continue; 345 while (isascii(*++v) && isspace(*v)) 346 continue; 347 348 switch (*f) 349 { 350 case 'F': /* address family */ 351 if (isascii(*v) && isdigit(*v)) 352 DaemonAddr.sa.sa_family = atoi(v); 353 #ifdef NETINET 354 else if (strcasecmp(v, "inet") == 0) 355 DaemonAddr.sa.sa_family = AF_INET; 356 #endif 357 #ifdef NETISO 358 else if (strcasecmp(v, "iso") == 0) 359 DaemonAddr.sa.sa_family = AF_ISO; 360 #endif 361 #ifdef NETNS 362 else if (strcasecmp(v, "ns") == 0) 363 DaemonAddr.sa.sa_family = AF_NS; 364 #endif 365 #ifdef NETX25 366 else if (strcasecmp(v, "x.25") == 0) 367 DaemonAddr.sa.sa_family = AF_CCITT; 368 #endif 369 else 370 syserr("554 Unknown address family %s in Family=option", v); 371 break; 372 373 case 'A': /* address */ 374 switch (DaemonAddr.sa.sa_family) 375 { 376 #ifdef NETINET 377 case AF_INET: 378 if (isascii(*v) && isdigit(*v)) 379 DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 380 else 381 { 382 register struct netent *np; 383 384 np = getnetbyname(v); 385 if (np == NULL) 386 syserr("554 network \"%s\" unknown", v); 387 else 388 DaemonAddr.sin.sin_addr.s_addr = np->n_net; 389 } 390 break; 391 #endif 392 393 default: 394 syserr("554 Address= option unsupported for family %d", 395 DaemonAddr.sa.sa_family); 396 break; 397 } 398 break; 399 400 case 'P': /* port */ 401 switch (DaemonAddr.sa.sa_family) 402 { 403 short port; 404 405 #ifdef NETINET 406 case AF_INET: 407 if (isascii(*v) && isdigit(*v)) 408 DaemonAddr.sin.sin_port = atoi(v); 409 else 410 { 411 register struct servent *sp; 412 413 sp = getservbyname(v, "tcp"); 414 if (sp == NULL) 415 syserr("554 service \"%s\" unknown", v); 416 else 417 DaemonAddr.sin.sin_port = sp->s_port; 418 } 419 break; 420 #endif 421 422 #ifdef NETISO 423 case AF_ISO: 424 /* assume two byte transport selector */ 425 if (isascii(*v) && isdigit(*v)) 426 port = atoi(v); 427 else 428 { 429 register struct servent *sp; 430 431 sp = getservbyname(v, "tcp"); 432 if (sp == NULL) 433 syserr("554 service \"%s\" unknown", v); 434 else 435 port = sp->s_port; 436 } 437 bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 438 break; 439 #endif 440 441 default: 442 syserr("554 Port= option unsupported for family %d", 443 DaemonAddr.sa.sa_family); 444 break; 445 } 446 break; 447 } 448 } 449 } 450 /* 451 ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 452 ** 453 ** Parameters: 454 ** host -- the name of the host. 455 ** port -- the port number to connect to. 456 ** mci -- a pointer to the mail connection information 457 ** structure to be filled in. 458 ** usesecureport -- if set, use a low numbered (reserved) 459 ** port to provide some rudimentary authentication. 460 ** 461 ** Returns: 462 ** An exit code telling whether the connection could be 463 ** made and if not why not. 464 ** 465 ** Side Effects: 466 ** none. 467 */ 468 469 SOCKADDR CurHostAddr; /* address of current host */ 470 471 int 472 makeconnection(host, port, mci, usesecureport) 473 char *host; 474 u_short port; 475 register MCI *mci; 476 bool usesecureport; 477 { 478 register int i, s; 479 register struct hostent *hp = (struct hostent *)NULL; 480 SOCKADDR addr; 481 int sav_errno; 482 int addrlen; 483 #ifdef NAMED_BIND 484 extern int h_errno; 485 #endif 486 487 /* 488 ** Set up the address for the mailer. 489 ** Accept "[a.b.c.d]" syntax for host name. 490 */ 491 492 #ifdef NAMED_BIND 493 h_errno = 0; 494 #endif 495 errno = 0; 496 bzero(&CurHostAddr, sizeof CurHostAddr); 497 CurHostName = host; 498 499 if (host[0] == '[') 500 { 501 long hid; 502 register char *p = strchr(host, ']'); 503 504 if (p != NULL) 505 { 506 *p = '\0'; 507 hid = inet_addr(&host[1]); 508 if (hid == -1) 509 { 510 /* try it as a host name (avoid MX lookup) */ 511 hp = gethostbyname(&host[1]); 512 *p = ']'; 513 goto gothostent; 514 } 515 *p = ']'; 516 } 517 if (p == NULL) 518 { 519 usrerr("553 Invalid numeric domain spec \"%s\"", host); 520 return (EX_NOHOST); 521 } 522 addr.sin.sin_family = AF_INET; 523 addr.sin.sin_addr.s_addr = hid; 524 } 525 else 526 { 527 hp = gethostbyname(host); 528 gothostent: 529 if (hp == NULL) 530 { 531 #ifdef NAMED_BIND 532 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 533 return (EX_TEMPFAIL); 534 535 /* if name server is specified, assume temp fail */ 536 if (errno == ECONNREFUSED && UseNameServer) 537 return (EX_TEMPFAIL); 538 #endif 539 return (EX_NOHOST); 540 } 541 addr.sa.sa_family = hp->h_addrtype; 542 switch (hp->h_addrtype) 543 { 544 #ifdef NETINET 545 case AF_INET: 546 bcopy(hp->h_addr, 547 &addr.sin.sin_addr, 548 hp->h_length); 549 break; 550 #endif 551 552 default: 553 bcopy(hp->h_addr, 554 addr.sa.sa_data, 555 hp->h_length); 556 break; 557 } 558 i = 1; 559 } 560 561 /* 562 ** Determine the port number. 563 */ 564 565 if (port != 0) 566 port = htons(port); 567 else 568 { 569 register struct servent *sp = getservbyname("smtp", "tcp"); 570 571 if (sp == NULL) 572 { 573 syserr("554 makeconnection: service \"smtp\" unknown"); 574 return (EX_OSERR); 575 } 576 port = sp->s_port; 577 } 578 579 switch (addr.sa.sa_family) 580 { 581 case AF_INET: 582 addr.sin.sin_port = port; 583 addrlen = sizeof (struct sockaddr_in); 584 break; 585 586 #ifdef NETISO 587 case AF_ISO: 588 /* assume two byte transport selector */ 589 bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 590 addrlen = sizeof (struct sockaddr_iso); 591 break; 592 #endif 593 594 default: 595 syserr("Can't connect to address family %d", addr.sa.sa_family); 596 return (EX_NOHOST); 597 } 598 599 /* 600 ** Try to actually open the connection. 601 */ 602 603 #ifdef XLA 604 /* if too many connections, don't bother trying */ 605 if (!xla_noqueue_ok(host)) 606 return EX_TEMPFAIL; 607 #endif 608 609 for (;;) 610 { 611 if (tTd(16, 1)) 612 printf("makeconnection (%s [%s])\n", 613 host, anynet_ntoa(&addr)); 614 615 /* save for logging */ 616 CurHostAddr = addr; 617 618 if (usesecureport) 619 { 620 int rport = IPPORT_RESERVED - 1; 621 622 s = rresvport(&rport); 623 } 624 else 625 { 626 s = socket(AF_INET, SOCK_STREAM, 0); 627 } 628 if (s < 0) 629 { 630 sav_errno = errno; 631 syserr("makeconnection: no socket"); 632 goto failure; 633 } 634 635 if (tTd(16, 1)) 636 printf("makeconnection: fd=%d\n", s); 637 638 /* turn on network debugging? */ 639 if (tTd(16, 101)) 640 { 641 int on = 1; 642 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 643 (char *)&on, sizeof on); 644 } 645 if (CurEnv->e_xfp != NULL) 646 (void) fflush(CurEnv->e_xfp); /* for debugging */ 647 errno = 0; /* for debugging */ 648 if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 649 break; 650 651 /* couldn't connect.... figure out why */ 652 sav_errno = errno; 653 (void) close(s); 654 if (hp && hp->h_addr_list[i]) 655 { 656 extern char *errstring(); 657 658 if (tTd(16, 1)) 659 printf("Connect failed (%s); trying new address....\n", 660 errstring(sav_errno)); 661 switch (addr.sa.sa_family) 662 { 663 #ifdef NETINET 664 case AF_INET: 665 bcopy(hp->h_addr_list[i++], 666 &addr.sin.sin_addr, 667 hp->h_length); 668 break; 669 #endif 670 671 default: 672 bcopy(hp->h_addr_list[i++], 673 addr.sa.sa_data, 674 hp->h_length); 675 break; 676 } 677 continue; 678 } 679 680 /* failure, decide if temporary or not */ 681 failure: 682 #ifdef XLA 683 xla_host_end(host); 684 #endif 685 if (transienterror(sav_errno)) 686 return EX_TEMPFAIL; 687 else 688 { 689 extern char *errstring(); 690 691 message("%s", errstring(sav_errno)); 692 return (EX_UNAVAILABLE); 693 } 694 } 695 696 /* connection ok, put it into canonical form */ 697 mci->mci_out = fdopen(s, "w"); 698 mci->mci_in = fdopen(dup(s), "r"); 699 700 return (EX_OK); 701 } 702 /* 703 ** MYHOSTNAME -- return the name of this host. 704 ** 705 ** Parameters: 706 ** hostbuf -- a place to return the name of this host. 707 ** size -- the size of hostbuf. 708 ** 709 ** Returns: 710 ** A list of aliases for this host. 711 ** 712 ** Side Effects: 713 ** Sets the MyIpAddrs buffer to a list of my IP addresses. 714 */ 715 716 struct in_addr MyIpAddrs[MAXIPADDR + 1]; 717 718 char ** 719 myhostname(hostbuf, size) 720 char hostbuf[]; 721 int size; 722 { 723 register struct hostent *hp; 724 extern struct hostent *gethostbyname(); 725 726 if (gethostname(hostbuf, size) < 0) 727 { 728 (void) strcpy(hostbuf, "localhost"); 729 } 730 hp = gethostbyname(hostbuf); 731 if (hp != NULL) 732 { 733 (void) strncpy(hostbuf, hp->h_name, size - 1); 734 hostbuf[size - 1] = '\0'; 735 736 if (hp->h_addrtype == AF_INET && hp->h_length == 4) 737 { 738 register int i; 739 740 for (i = 0; i < MAXIPADDR; i++) 741 { 742 if (hp->h_addr_list[i] == NULL) 743 break; 744 MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i]; 745 } 746 MyIpAddrs[i].s_addr = 0; 747 } 748 749 return (hp->h_aliases); 750 } 751 else 752 return (NULL); 753 } 754 /* 755 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 756 ** 757 ** Uses RFC1413 protocol to try to get info from the other end. 758 ** 759 ** Parameters: 760 ** fd -- the descriptor 761 ** 762 ** Returns: 763 ** The user@host information associated with this descriptor. 764 ** 765 ** Side Effects: 766 ** Sets RealHostName to the name of the host at the other end. 767 */ 768 769 #ifdef IDENTPROTO 770 771 static jmp_buf CtxAuthTimeout; 772 773 static 774 authtimeout() 775 { 776 longjmp(CtxAuthTimeout, 1); 777 } 778 779 #endif 780 781 char * 782 getauthinfo(fd) 783 int fd; 784 { 785 SOCKADDR fa; 786 int falen; 787 register char *p; 788 #ifdef IDENTPROTO 789 SOCKADDR la; 790 int lalen; 791 register struct servent *sp; 792 int s; 793 int i; 794 EVENT *ev; 795 #endif 796 static char hbuf[MAXNAME * 2 + 2]; 797 extern char *hostnamebyanyaddr(); 798 extern char RealUserName[]; /* main.c */ 799 800 falen = sizeof fa; 801 if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0) 802 { 803 RealHostName = "localhost"; 804 (void) sprintf(hbuf, "%s@localhost", RealUserName); 805 if (tTd(9, 1)) 806 printf("getauthinfo: %s\n", hbuf); 807 return hbuf; 808 } 809 810 RealHostName = newstr(hostnamebyanyaddr(&fa)); 811 RealHostAddr = fa; 812 813 #ifdef IDENTPROTO 814 lalen = sizeof la; 815 if (fa.sa.sa_family != AF_INET || 816 getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 817 la.sa.sa_family != AF_INET) 818 { 819 /* no ident info */ 820 goto noident; 821 } 822 823 /* create ident query */ 824 (void) sprintf(hbuf, "%d,%d\r\n", fa.sin.sin_port, la.sin.sin_port); 825 826 /* create local address */ 827 bzero(&la, sizeof la); 828 829 /* create foreign address */ 830 sp = getservbyname("auth", "tcp"); 831 if (sp != NULL) 832 fa.sin.sin_port = sp->s_port; 833 else 834 fa.sin.sin_port = htons(113); 835 836 s = -1; 837 if (setjmp(CtxAuthTimeout) != 0) 838 { 839 if (s >= 0) 840 (void) close(s); 841 goto noident; 842 } 843 844 /* put a timeout around the whole thing */ 845 ev = setevent((time_t) 30, authtimeout, 0); 846 847 /* connect to foreign IDENT server */ 848 s = socket(AF_INET, SOCK_STREAM, 0); 849 if (s < 0) 850 { 851 clrevent(ev); 852 goto noident; 853 } 854 if (connect(s, &fa.sa, sizeof fa.sin) < 0) 855 { 856 closeident: 857 (void) close(s); 858 clrevent(ev); 859 goto noident; 860 } 861 862 if (tTd(9, 10)) 863 printf("getauthinfo: sent %s", hbuf); 864 865 /* send query */ 866 if (write(s, hbuf, strlen(hbuf)) < 0) 867 goto closeident; 868 869 /* get result */ 870 i = read(s, hbuf, sizeof hbuf); 871 (void) close(s); 872 clrevent(ev); 873 if (i <= 0) 874 goto noident; 875 if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 876 i--; 877 hbuf[++i] = '\0'; 878 879 if (tTd(9, 3)) 880 printf("getauthinfo: got %s\n", hbuf); 881 882 /* parse result */ 883 p = strchr(hbuf, ':'); 884 if (p == NULL) 885 { 886 /* malformed response */ 887 goto noident; 888 } 889 while (isascii(*++p) && isspace(*p)) 890 continue; 891 if (strncasecmp(p, "userid", 6) != 0) 892 { 893 /* presumably an error string */ 894 goto noident; 895 } 896 p += 6; 897 while (isascii(*p) && isspace(*p)) 898 p++; 899 if (*p++ != ':') 900 { 901 /* either useridxx or malformed response */ 902 goto noident; 903 } 904 905 /* p now points to the OSTYPE field */ 906 p = strchr(p, ':'); 907 if (p == NULL) 908 { 909 /* malformed response */ 910 goto noident; 911 } 912 913 /* 1413 says don't do this -- but it's broken otherwise */ 914 while (isascii(*++p) && isspace(*p)) 915 continue; 916 917 /* p now points to the authenticated name */ 918 (void) sprintf(hbuf, "%s@%s", p, RealHostName); 919 goto finish; 920 921 #endif /* IDENTPROTO */ 922 923 noident: 924 (void) strcpy(hbuf, RealHostName); 925 926 finish: 927 if (RealHostName[0] != '[') 928 { 929 p = &hbuf[strlen(hbuf)]; 930 (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 931 } 932 if (tTd(9, 1)) 933 printf("getauthinfo: %s\n", hbuf); 934 return hbuf; 935 } 936 /* 937 ** MAPHOSTNAME -- turn a hostname into canonical form 938 ** 939 ** Parameters: 940 ** map -- a pointer to this map (unused). 941 ** hbuf -- a buffer containing a hostname. 942 ** hbsize -- the size of hbuf. 943 ** avp -- unused -- for compatibility with other mapping 944 ** functions. 945 ** statp -- an exit status (out parameter) -- set to 946 ** EX_TEMPFAIL if the name server is unavailable. 947 ** 948 ** Returns: 949 ** The mapping, if found. 950 ** NULL if no mapping found. 951 ** 952 ** Side Effects: 953 ** Looks up the host specified in hbuf. If it is not 954 ** the canonical name for that host, return the canonical 955 ** name. 956 */ 957 958 char * 959 maphostname(map, hbuf, hbsize, avp, statp) 960 MAP *map; 961 char *hbuf; 962 int hbsize; 963 char **avp; 964 int *statp; 965 { 966 register struct hostent *hp; 967 u_long in_addr; 968 char *cp; 969 int i; 970 struct hostent *gethostbyaddr(); 971 972 /* allow room for null */ 973 hbsize--; 974 975 /* 976 * If first character is a bracket, then it is an address 977 * lookup. Address is copied into a temporary buffer to 978 * strip the brackets and to preserve hbuf if address is 979 * unknown. 980 */ 981 982 if (*hbuf != '[') 983 { 984 extern bool getcanonname(); 985 986 if (tTd(9, 1)) 987 printf("maphostname(%s, %d) => ", hbuf, hbsize); 988 if (getcanonname(hbuf, hbsize)) 989 { 990 if (tTd(9, 1)) 991 printf("%s\n", hbuf); 992 return hbuf; 993 } 994 else 995 { 996 register struct hostent *hp; 997 extern int h_errno; 998 999 if (tTd(9, 1)) 1000 printf("FAIL (%d)\n", h_errno); 1001 switch (h_errno) 1002 { 1003 case TRY_AGAIN: 1004 *statp = EX_TEMPFAIL; 1005 break; 1006 1007 case HOST_NOT_FOUND: 1008 *statp = EX_NOHOST; 1009 break; 1010 1011 case NO_RECOVERY: 1012 *statp = EX_SOFTWARE; 1013 break; 1014 1015 default: 1016 *statp = EX_UNAVAILABLE; 1017 break; 1018 } 1019 if (*statp != EX_TEMPFAIL || UseNameServer) 1020 return NULL; 1021 1022 /* 1023 ** Try to look it up in /etc/hosts 1024 */ 1025 1026 hp = gethostbyname(hbuf); 1027 if (hp == NULL) 1028 { 1029 /* no dice there either */ 1030 *statp = EX_NOHOST; 1031 return NULL; 1032 } 1033 1034 *statp = EX_OK; 1035 return hp->h_name; 1036 } 1037 } 1038 if ((cp = strchr(hbuf, ']')) == NULL) 1039 return (NULL); 1040 *cp = '\0'; 1041 in_addr = inet_addr(&hbuf[1]); 1042 1043 /* check to see if this is one of our addresses */ 1044 for (i = 0; MyIpAddrs[i].s_addr != 0; i++) 1045 { 1046 if (MyIpAddrs[i].s_addr == in_addr) 1047 { 1048 strncpy(hbuf, MyHostName, hbsize); 1049 hbuf[hbsize] = '\0'; 1050 return hbuf; 1051 } 1052 } 1053 1054 /* nope -- ask the name server */ 1055 hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 1056 if (hp == NULL) 1057 return (NULL); 1058 1059 /* found a match -- copy out */ 1060 if (strlen(hp->h_name) > hbsize) 1061 hp->h_name[hbsize] = '\0'; 1062 (void) strcpy(hbuf, hp->h_name); 1063 return hbuf; 1064 } 1065 /* 1066 ** ANYNET_NTOA -- convert a network address to printable form. 1067 ** 1068 ** Parameters: 1069 ** sap -- a pointer to a sockaddr structure. 1070 ** 1071 ** Returns: 1072 ** A printable version of that sockaddr. 1073 */ 1074 1075 char * 1076 anynet_ntoa(sap) 1077 register SOCKADDR *sap; 1078 { 1079 register char *bp; 1080 register char *ap; 1081 int l; 1082 static char buf[80]; 1083 1084 /* check for null/zero family */ 1085 if (sap == NULL) 1086 return "NULLADDR"; 1087 if (sap->sa.sa_family == 0) 1088 return "0"; 1089 1090 #ifdef NETINET 1091 if (sap->sa.sa_family == AF_INET) 1092 { 1093 extern char *inet_ntoa(); 1094 1095 return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 1096 } 1097 #endif 1098 1099 /* unknown family -- just dump bytes */ 1100 (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1101 bp = &buf[strlen(buf)]; 1102 ap = sap->sa.sa_data; 1103 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1104 { 1105 (void) sprintf(bp, "%02x:", *ap++ & 0377); 1106 bp += 3; 1107 } 1108 *--bp = '\0'; 1109 return buf; 1110 } 1111 /* 1112 ** HOSTNAMEBYANYADDR -- return name of host based on address 1113 ** 1114 ** Parameters: 1115 ** sap -- SOCKADDR pointer 1116 ** 1117 ** Returns: 1118 ** text representation of host name. 1119 ** 1120 ** Side Effects: 1121 ** none. 1122 */ 1123 1124 char * 1125 hostnamebyanyaddr(sap) 1126 register SOCKADDR *sap; 1127 { 1128 register struct hostent *hp; 1129 1130 #ifdef NAMED_BIND 1131 int saveretry; 1132 1133 /* shorten name server timeout to avoid higher level timeouts */ 1134 saveretry = _res.retry; 1135 _res.retry = 3; 1136 #endif /* NAMED_BIND */ 1137 1138 switch (sap->sa.sa_family) 1139 { 1140 #ifdef NETINET 1141 case AF_INET: 1142 hp = gethostbyaddr((char *) &sap->sin.sin_addr, 1143 sizeof sap->sin.sin_addr, 1144 AF_INET); 1145 break; 1146 #endif 1147 1148 #ifdef NETISO 1149 case AF_ISO: 1150 hp = gethostbyaddr((char *) &sap->siso.siso_addr, 1151 sizeof sap->siso.siso_addr, 1152 AF_ISO); 1153 break; 1154 #endif 1155 1156 default: 1157 hp = gethostbyaddr(sap->sa.sa_data, 1158 sizeof sap->sa.sa_data, 1159 sap->sa.sa_family); 1160 break; 1161 } 1162 1163 #ifdef NAMED_BIND 1164 _res.retry = saveretry; 1165 #endif /* NAMED_BIND */ 1166 1167 if (hp != NULL) 1168 return hp->h_name; 1169 else 1170 { 1171 /* produce a dotted quad */ 1172 static char buf[512]; 1173 1174 (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 1175 return buf; 1176 } 1177 } 1178 1179 # else /* DAEMON */ 1180 /* code for systems without sophisticated networking */ 1181 1182 /* 1183 ** MYHOSTNAME -- stub version for case of no daemon code. 1184 ** 1185 ** Can't convert to upper case here because might be a UUCP name. 1186 ** 1187 ** Mark, you can change this to be anything you want...... 1188 */ 1189 1190 char ** 1191 myhostname(hostbuf, size) 1192 char hostbuf[]; 1193 int size; 1194 { 1195 register FILE *f; 1196 1197 hostbuf[0] = '\0'; 1198 f = fopen("/usr/include/whoami", "r"); 1199 if (f != NULL) 1200 { 1201 (void) fgets(hostbuf, size, f); 1202 fixcrlf(hostbuf, TRUE); 1203 (void) fclose(f); 1204 } 1205 return (NULL); 1206 } 1207 /* 1208 ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1209 ** 1210 ** Parameters: 1211 ** fd -- the descriptor 1212 ** 1213 ** Returns: 1214 ** The host name associated with this descriptor, if it can 1215 ** be determined. 1216 ** NULL otherwise. 1217 ** 1218 ** Side Effects: 1219 ** none 1220 */ 1221 1222 char * 1223 getauthinfo(fd) 1224 int fd; 1225 { 1226 return NULL; 1227 } 1228 /* 1229 ** MAPHOSTNAME -- turn a hostname into canonical form 1230 ** 1231 ** Parameters: 1232 ** map -- a pointer to the database map. 1233 ** hbuf -- a buffer containing a hostname. 1234 ** hbsize -- size of hbuf. 1235 ** avp -- a pointer to a (cf file defined) argument vector. 1236 ** statp -- an exit status (out parameter). 1237 ** 1238 ** Returns: 1239 ** mapped host name 1240 ** FALSE otherwise. 1241 ** 1242 ** Side Effects: 1243 ** Looks up the host specified in hbuf. If it is not 1244 ** the canonical name for that host, replace it with 1245 ** the canonical name. If the name is unknown, or it 1246 ** is already the canonical name, leave it unchanged. 1247 */ 1248 1249 /*ARGSUSED*/ 1250 char * 1251 maphostname(map, hbuf, hbsize, avp, statp) 1252 MAP *map; 1253 char *hbuf; 1254 int hbsize; 1255 char **avp; 1256 char *statp; 1257 { 1258 register struct hostent *hp; 1259 1260 hp = gethostbyname(hbuf); 1261 if (hp != NULL) 1262 return hp->h_name; 1263 *statp = EX_NOHOST; 1264 return NULL; 1265 } 1266 1267 #endif /* DAEMON */ 1268