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