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