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