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