daemon.c revision 71345
1/* 2 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14#include <sendmail.h> 15 16 17#ifndef lint 18# ifdef DAEMON 19static char id[] = "@(#)$Id: daemon.c,v 8.401.4.41 2000/12/28 23:46:43 gshapiro Exp $ (with daemon mode)"; 20# else /* DAEMON */ 21static char id[] = "@(#)$Id: daemon.c,v 8.401.4.41 2000/12/28 23:46:43 gshapiro Exp $ (without daemon mode)"; 22# endif /* DAEMON */ 23#endif /* ! lint */ 24 25#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 26# define USE_SOCK_STREAM 1 27#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */ 28 29#if DAEMON || defined(USE_SOCK_STREAM) 30# if NETINET || NETINET6 31# include <arpa/inet.h> 32# endif /* NETINET || NETINET6 */ 33# if NAMED_BIND 34# ifndef NO_DATA 35# define NO_DATA NO_ADDRESS 36# endif /* ! NO_DATA */ 37# endif /* NAMED_BIND */ 38#endif /* DAEMON || defined(USE_SOCK_STREAM) */ 39 40#if DAEMON 41 42# if STARTTLS 43# include <openssl/rand.h> 44# endif /* STARTTLS */ 45 46# include <sys/time.h> 47 48# if IP_SRCROUTE && NETINET 49# include <netinet/in_systm.h> 50# include <netinet/ip.h> 51# if HAS_IN_H 52# include <netinet/in.h> 53# ifndef IPOPTION 54# define IPOPTION ip_opts 55# define IP_LIST ip_opts 56# define IP_DST ip_dst 57# endif /* ! IPOPTION */ 58# else /* HAS_IN_H */ 59# include <netinet/ip_var.h> 60# ifndef IPOPTION 61# define IPOPTION ipoption 62# define IP_LIST ipopt_list 63# define IP_DST ipopt_dst 64# endif /* ! IPOPTION */ 65# endif /* HAS_IN_H */ 66# endif /* IP_SRCROUTE && NETINET */ 67 68/* structure to describe a daemon */ 69struct daemon 70{ 71 int d_socket; /* fd for socket */ 72 SOCKADDR d_addr; /* socket for incoming */ 73 u_short d_port; /* port number */ 74 int d_listenqueue; /* size of listen queue */ 75 int d_tcprcvbufsize; /* size of TCP receive buffer */ 76 int d_tcpsndbufsize; /* size of TCP send buffer */ 77 time_t d_refuse_connections_until; 78 bool d_firsttime; 79 int d_socksize; 80 BITMAP256 d_flags; /* flags; see sendmail.h */ 81 char *d_mflags; /* flags for use in macro */ 82 char *d_name; /* user-supplied name */ 83}; 84 85typedef struct daemon DAEMON_T; 86 87static void connecttimeout __P((void)); 88static int opendaemonsocket __P((struct daemon *, bool)); 89static u_short setupdaemon __P((SOCKADDR *)); 90 91/* 92** DAEMON.C -- routines to use when running as a daemon. 93** 94** This entire file is highly dependent on the 4.2 BSD 95** interprocess communication primitives. No attempt has 96** been made to make this file portable to Version 7, 97** Version 6, MPX files, etc. If you should try such a 98** thing yourself, I recommend chucking the entire file 99** and starting from scratch. Basic semantics are: 100** 101** getrequests(e) 102** Opens a port and initiates a connection. 103** Returns in a child. Must set InChannel and 104** OutChannel appropriately. 105** clrdaemon() 106** Close any open files associated with getting 107** the connection; this is used when running the queue, 108** etc., to avoid having extra file descriptors during 109** the queue run and to avoid confusing the network 110** code (if it cares). 111** makeconnection(host, port, outfile, infile, e) 112** Make a connection to the named host on the given 113** port. Set *outfile and *infile to the files 114** appropriate for communication. Returns zero on 115** success, else an exit status describing the 116** error. 117** host_map_lookup(map, hbuf, avp, pstat) 118** Convert the entry in hbuf into a canonical form. 119*/ 120 121static DAEMON_T Daemons[MAXDAEMONS]; 122static int ndaemons = 0; /* actual number of daemons */ 123 124/* options for client */ 125static int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 126static int TcpSndBufferSize = 0; /* size of TCP send buffer */ 127 128/* 129** GETREQUESTS -- open mail IPC port and get requests. 130** 131** Parameters: 132** e -- the current envelope. 133** 134** Returns: 135** pointer to flags. 136** 137** Side Effects: 138** Waits until some interesting activity occurs. When 139** it does, a child is created to process it, and the 140** parent waits for completion. Return from this 141** routine is always in the child. The file pointers 142** "InChannel" and "OutChannel" should be set to point 143** to the communication channel. 144*/ 145 146BITMAP256 * 147getrequests(e) 148 ENVELOPE *e; 149{ 150 int t; 151 time_t last_disk_space_check = 0; 152 int idx, curdaemon = -1; 153 int i, olddaemon = 0; 154# if XDEBUG 155 bool j_has_dot; 156# endif /* XDEBUG */ 157 char status[MAXLINE]; 158 SOCKADDR sa; 159 SOCKADDR_LEN_T len = sizeof sa; 160# if NETUNIX 161 extern int ControlSocket; 162# endif /* NETUNIX */ 163 extern ENVELOPE BlankEnvelope; 164 165 166 for (idx = 0; idx < ndaemons; idx++) 167 { 168 Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 169 Daemons[idx].d_firsttime = TRUE; 170 Daemons[idx].d_refuse_connections_until = (time_t) 0; 171 } 172 173 /* 174 ** Try to actually open the connection. 175 */ 176 177 if (tTd(15, 1)) 178 { 179 for (idx = 0; idx < ndaemons; idx++) 180 { 181 dprintf("getrequests: daemon %s: port %d\n", 182 Daemons[idx].d_name, 183 ntohs(Daemons[idx].d_port)); 184 } 185 } 186 187 /* get a socket for the SMTP connection */ 188 for (idx = 0; idx < ndaemons; idx++) 189 Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], TRUE); 190 191 if (opencontrolsocket() < 0) 192 sm_syslog(LOG_WARNING, NOQID, 193 "daemon could not open control socket %s: %s", 194 ControlSocketName, errstring(errno)); 195 196 (void) setsignal(SIGCHLD, reapchild); 197 198 /* write the pid to file */ 199 log_sendmail_pid(e); 200 201# if XDEBUG 202 { 203 char jbuf[MAXHOSTNAMELEN]; 204 205 expand("\201j", jbuf, sizeof jbuf, e); 206 j_has_dot = strchr(jbuf, '.') != NULL; 207 } 208# endif /* XDEBUG */ 209 210 /* Add parent process as first item */ 211 proc_list_add(getpid(), "Sendmail daemon", PROC_DAEMON); 212 213 if (tTd(15, 1)) 214 { 215 for (idx = 0; idx < ndaemons; idx++) 216 dprintf("getrequests: daemon %s: %d\n", 217 Daemons[idx].d_name, 218 Daemons[idx].d_socket); 219 } 220 221 for (;;) 222 { 223 register pid_t pid; 224 auto SOCKADDR_LEN_T lotherend; 225 bool timedout = FALSE; 226 bool control = FALSE; 227 int save_errno; 228 int pipefd[2]; 229 time_t timenow; 230# if STARTTLS 231 long seed; 232# endif /* STARTTLS */ 233 extern bool refuseconnections __P((char *, ENVELOPE *, int)); 234 235 /* see if we are rejecting connections */ 236 (void) blocksignal(SIGALRM); 237 238 timenow = curtime(); 239 240 /* 241 ** Use ConnRateThrottle only if the 242 ** last pass was for a connection 243 */ 244 245 if (ConnRateThrottle > 0 && curdaemon >= 0) 246 { 247 static int conncnt = 0; 248 static time_t lastconn = 0; 249 250 if (timenow != lastconn) 251 { 252 lastconn = timenow; 253 conncnt = 1; 254 } 255 else if (++conncnt > ConnRateThrottle) 256 { 257 /* sleep to flatten out connection load */ 258 sm_setproctitle(TRUE, e, 259 "deferring connections: %d per second", 260 ConnRateThrottle); 261 if (LogLevel >= 9) 262 sm_syslog(LOG_INFO, NOQID, 263 "deferring connections: %d per second", 264 ConnRateThrottle); 265 (void) sleep(1); 266 } 267 } 268 269 for (idx = 0; idx < ndaemons; idx++) 270 { 271 if (timenow < Daemons[idx].d_refuse_connections_until) 272 continue; 273 if (refuseconnections(Daemons[idx].d_name, e, idx)) 274 { 275 if (Daemons[idx].d_socket >= 0) 276 { 277 /* close socket so peer fails quickly */ 278 (void) close(Daemons[idx].d_socket); 279 Daemons[idx].d_socket = -1; 280 } 281 282 /* refuse connections for next 15 seconds */ 283 Daemons[idx].d_refuse_connections_until = timenow + 15; 284 } 285 else if (Daemons[idx].d_socket < 0 || 286 Daemons[idx].d_firsttime) 287 { 288 if (!Daemons[idx].d_firsttime && LogLevel >= 9) 289 sm_syslog(LOG_INFO, NOQID, 290 "accepting connections again for daemon %s", 291 Daemons[idx].d_name); 292 293 /* arrange to (re)open the socket if needed */ 294 (void) opendaemonsocket(&Daemons[idx], FALSE); 295 Daemons[idx].d_firsttime = FALSE; 296 } 297 } 298 299 if (timenow >= last_disk_space_check) 300 { 301 bool logged = FALSE; 302 303 if (!enoughdiskspace(MinBlocksFree + 1, FALSE)) 304 { 305 for (idx = 0; idx < ndaemons; idx++) 306 { 307 if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 308 { 309 /* log only if not logged before */ 310 if (!logged) 311 { 312 if (LogLevel >= 9) 313 sm_syslog(LOG_INFO, NOQID, 314 "rejecting new messages: min free: %ld", 315 MinBlocksFree); 316 logged = TRUE; 317 sm_setproctitle(TRUE, e, 318 "rejecting new messages: min free: %ld", 319 MinBlocksFree); 320 } 321 setbitn(D_ETRNONLY, Daemons[idx].d_flags); 322 } 323 } 324 } 325 else 326 { 327 for (idx = 0; idx < ndaemons; idx++) 328 { 329 if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 330 { 331 /* log only if not logged before */ 332 if (!logged) 333 { 334 if (LogLevel >= 9) 335 sm_syslog(LOG_INFO, NOQID, 336 "accepting new messages (again)"); 337 logged = TRUE; 338 } 339 340 /* title will be set below */ 341 clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 342 } 343 } 344 } 345 /* only check disk space once a minute */ 346 last_disk_space_check = timenow + 60; 347 } 348 349# if XDEBUG 350 /* check for disaster */ 351 { 352 char jbuf[MAXHOSTNAMELEN]; 353 354 expand("\201j", jbuf, sizeof jbuf, e); 355 if (!wordinclass(jbuf, 'w')) 356 { 357 dumpstate("daemon lost $j"); 358 sm_syslog(LOG_ALERT, NOQID, 359 "daemon process doesn't have $j in $=w; see syslog"); 360 abort(); 361 } 362 else if (j_has_dot && strchr(jbuf, '.') == NULL) 363 { 364 dumpstate("daemon $j lost dot"); 365 sm_syslog(LOG_ALERT, NOQID, 366 "daemon process $j lost dot; see syslog"); 367 abort(); 368 } 369 } 370# endif /* XDEBUG */ 371 372# if 0 373 /* 374 ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 375 ** fix the SVr4 problem. But it seems to have gone away, 376 ** so is it worth doing this? 377 */ 378 379 if (DaemonSocket >= 0 && 380 SetNonBlocking(DaemonSocket, FALSE) < 0) 381 log an error here; 382# endif /* 0 */ 383 (void) releasesignal(SIGALRM); 384 385 for (;;) 386 { 387 bool setproc = FALSE; 388 int highest = -1; 389 fd_set readfds; 390 struct timeval timeout; 391 392 FD_ZERO(&readfds); 393 394 for (idx = 0; idx < ndaemons; idx++) 395 { 396 /* wait for a connection */ 397 if (Daemons[idx].d_socket >= 0) 398 { 399 if (!setproc && 400 !bitnset(D_ETRNONLY, 401 Daemons[idx].d_flags)) 402 { 403 sm_setproctitle(TRUE, e, 404 "accepting connections"); 405 setproc = TRUE; 406 } 407 if (Daemons[idx].d_socket > highest) 408 highest = Daemons[idx].d_socket; 409 FD_SET((u_int)Daemons[idx].d_socket, &readfds); 410 } 411 } 412 413# if NETUNIX 414 if (ControlSocket >= 0) 415 { 416 if (ControlSocket > highest) 417 highest = ControlSocket; 418 FD_SET(ControlSocket, &readfds); 419 } 420# endif /* NETUNIX */ 421 422 /* 423 ** if one socket is closed, set the timeout 424 ** to 5 seconds (so it might get reopened soon), 425 ** otherwise (all sockets open) 60. 426 */ 427 428 idx = 0; 429 while (idx < ndaemons && Daemons[idx].d_socket >= 0) 430 idx++; 431 if (idx < ndaemons) 432 timeout.tv_sec = 5; 433 else 434 timeout.tv_sec = 60; 435 timeout.tv_usec = 0; 436 437 t = select(highest + 1, FDSET_CAST &readfds, 438 NULL, NULL, &timeout); 439 440 441 442 if (DoQueueRun) 443 (void) runqueue(TRUE, FALSE); 444 445 curdaemon = -1; 446 if (t <= 0) 447 { 448 timedout = TRUE; 449 break; 450 } 451 452 control = FALSE; 453 errno = 0; 454 455 /* look "round-robin" for an active socket */ 456 if ((idx = olddaemon + 1) >= ndaemons) 457 idx = 0; 458 for (i = 0; i < ndaemons; i++) 459 { 460 if (Daemons[idx].d_socket >= 0 && 461 FD_ISSET(Daemons[idx].d_socket, &readfds)) 462 { 463 lotherend = Daemons[idx].d_socksize; 464 t = accept(Daemons[idx].d_socket, 465 (struct sockaddr *)&RealHostAddr, 466 &lotherend); 467 olddaemon = curdaemon = idx; 468 break; 469 } 470 if (++idx >= ndaemons) 471 idx = 0; 472 } 473# if NETUNIX 474 if (curdaemon == -1 && ControlSocket >= 0 && 475 FD_ISSET(ControlSocket, &readfds)) 476 { 477 struct sockaddr_un sa_un; 478 479 lotherend = sizeof sa_un; 480 t = accept(ControlSocket, 481 (struct sockaddr *)&sa_un, 482 &lotherend); 483 control = TRUE; 484 } 485# else /* NETUNIX */ 486 if (curdaemon == -1) 487 { 488 /* No daemon to service */ 489 continue; 490 } 491# endif /* NETUNIX */ 492 if (t >= 0 || errno != EINTR) 493 break; 494 } 495 if (timedout) 496 { 497 timedout = FALSE; 498 continue; 499 } 500 save_errno = errno; 501 timenow = curtime(); 502 (void) blocksignal(SIGALRM); 503 if (t < 0) 504 { 505 errno = save_errno; 506 syserr("getrequests: accept"); 507 508 /* arrange to re-open the socket next time around */ 509 (void) close(Daemons[curdaemon].d_socket); 510 Daemons[curdaemon].d_socket = -1; 511# if SO_REUSEADDR_IS_BROKEN 512 /* 513 ** Give time for bound socket to be released. 514 ** This creates a denial-of-service if you can 515 ** force accept() to fail on affected systems. 516 */ 517 518 Daemons[curdaemon].d_refuse_connections_until = timenow + 15; 519# endif /* SO_REUSEADDR_IS_BROKEN */ 520 continue; 521 } 522 523 if (!control) 524 { 525 /* set some daemon related macros */ 526 switch (Daemons[curdaemon].d_addr.sa.sa_family) 527 { 528 case AF_UNSPEC: 529 define(macid("{daemon_family}", NULL), 530 "unspec", &BlankEnvelope); 531 break; 532# if NETINET 533 case AF_INET: 534 define(macid("{daemon_family}", NULL), 535 "inet", &BlankEnvelope); 536 break; 537# endif /* NETINET */ 538# if NETINET6 539 case AF_INET6: 540 define(macid("{daemon_family}", NULL), 541 "inet6", &BlankEnvelope); 542 break; 543# endif /* NETINET6 */ 544# if NETISO 545 case AF_ISO: 546 define(macid("{daemon_family}", NULL), 547 "iso", &BlankEnvelope); 548 break; 549# endif /* NETISO */ 550# if NETNS 551 case AF_NS: 552 define(macid("{daemon_family}", NULL), 553 "ns", &BlankEnvelope); 554 break; 555# endif /* NETNS */ 556# if NETX25 557 case AF_CCITT: 558 define(macid("{daemon_family}", NULL), 559 "x.25", &BlankEnvelope); 560 break; 561# endif /* NETX25 */ 562 } 563 define(macid("{daemon_name}", NULL), 564 Daemons[curdaemon].d_name, &BlankEnvelope); 565 if (Daemons[curdaemon].d_mflags != NULL) 566 define(macid("{daemon_flags}", NULL), 567 Daemons[curdaemon].d_mflags, 568 &BlankEnvelope); 569 else 570 define(macid("{daemon_flags}", NULL), 571 "", &BlankEnvelope); 572 } 573 574 /* 575 ** Create a subprocess to process the mail. 576 */ 577 578 if (tTd(15, 2)) 579 dprintf("getrequests: forking (fd = %d)\n", t); 580 581 /* 582 ** advance state of PRNG 583 ** this is necessary because otherwise all child processes 584 ** will produce the same PRN sequence and hence the selection 585 ** of a queue directory (and other things, e.g., MX selection) 586 ** are not "really" random. 587 */ 588# if STARTTLS 589 seed = get_random(); 590 RAND_seed((void *) &last_disk_space_check, 591 sizeof last_disk_space_check); 592 RAND_seed((void *) &timenow, sizeof timenow); 593 RAND_seed((void *) &seed, sizeof seed); 594# else /* STARTTLS */ 595 (void) get_random(); 596# endif /* STARTTLS */ 597 598#ifndef DEBUG_NO_FORK 599 /* 600 ** Create a pipe to keep the child from writing to the 601 ** socket until after the parent has closed it. Otherwise 602 ** the parent may hang if the child has closed it first. 603 */ 604 605 if (pipe(pipefd) < 0) 606 pipefd[0] = pipefd[1] = -1; 607 608 (void) blocksignal(SIGCHLD); 609 pid = fork(); 610 if (pid < 0) 611 { 612 syserr("daemon: cannot fork"); 613 if (pipefd[0] != -1) 614 { 615 (void) close(pipefd[0]); 616 (void) close(pipefd[1]); 617 } 618 (void) releasesignal(SIGCHLD); 619 (void) sleep(10); 620 (void) close(t); 621 continue; 622 } 623#else /* ! DEBUG_NO_FORK */ 624 pid = 0; 625#endif /* ! DEBUG_NO_FORK */ 626 627 if (pid == 0) 628 { 629 char *p; 630 FILE *inchannel, *outchannel = NULL; 631 632 /* 633 ** CHILD -- return to caller. 634 ** Collect verified idea of sending host. 635 ** Verify calling user id if possible here. 636 */ 637 638 if (!control) 639 { 640 define(macid("{daemon_addr}", NULL), 641 newstr(anynet_ntoa(&Daemons[curdaemon].d_addr)), 642 &BlankEnvelope); 643 (void) snprintf(status, sizeof status, "%d", 644 ntohs(Daemons[curdaemon].d_port)); 645 define(macid("{daemon_port}", NULL), 646 newstr(status), &BlankEnvelope); 647 } 648 649 (void) releasesignal(SIGALRM); 650 (void) releasesignal(SIGCHLD); 651 (void) setsignal(SIGCHLD, SIG_DFL); 652 (void) setsignal(SIGHUP, intsig); 653 for (idx = 0; idx < ndaemons; idx++) 654 { 655 if (Daemons[idx].d_socket >= 0) 656 (void) close(Daemons[idx].d_socket); 657 } 658 clrcontrol(); 659 660 /* Avoid SMTP daemon actions if control command */ 661 if (control) 662 { 663 /* Add control socket process */ 664 proc_list_add(getpid(), "console socket child", 665 PROC_CONTROL_CHILD); 666 } 667 else 668 { 669 proc_list_clear(); 670 671 /* Add parent process as first child item */ 672 proc_list_add(getpid(), "daemon child", 673 PROC_DAEMON_CHILD); 674 675 /* don't schedule queue runs if ETRN */ 676 QueueIntvl = 0; 677 678 sm_setproctitle(TRUE, e, "startup with %s", 679 anynet_ntoa(&RealHostAddr)); 680 } 681 682#ifndef DEBUG_NO_FORK 683 if (pipefd[0] != -1) 684 { 685 auto char c; 686 687 /* 688 ** Wait for the parent to close the write end 689 ** of the pipe, which we will see as an EOF. 690 ** This guarantees that we won't write to the 691 ** socket until after the parent has closed 692 ** the pipe. 693 */ 694 695 /* close the write end of the pipe */ 696 (void) close(pipefd[1]); 697 698 /* we shouldn't be interrupted, but ... */ 699 while (read(pipefd[0], &c, 1) < 0 && 700 errno == EINTR) 701 continue; 702 (void) close(pipefd[0]); 703 } 704#endif /* ! DEBUG_NO_FORK */ 705 706 /* control socket processing */ 707 if (control) 708 { 709 control_command(t, e); 710 711 /* NOTREACHED */ 712 exit(EX_SOFTWARE); 713 } 714 715 /* determine host name */ 716 p = hostnamebyanyaddr(&RealHostAddr); 717 if (strlen(p) > (SIZE_T) MAXNAME) 718 p[MAXNAME] = '\0'; 719 RealHostName = newstr(p); 720 if (RealHostName[0] == '[') 721 { 722 /* TEMP, FAIL: which one? */ 723 define(macid("{client_resolve}", NULL), 724 (h_errno == TRY_AGAIN) ? "TEMP" : "FAIL", 725 &BlankEnvelope); 726 } 727 else 728 define(macid("{client_resolve}", NULL), "OK", 729 &BlankEnvelope); 730 sm_setproctitle(TRUE, e, "startup with %s", p); 731 732 if ((inchannel = fdopen(t, "r")) == NULL || 733 (t = dup(t)) < 0 || 734 (outchannel = fdopen(t, "w")) == NULL) 735 { 736 syserr("cannot open SMTP server channel, fd=%d", t); 737 finis(FALSE, EX_OK); 738 } 739 740 InChannel = inchannel; 741 OutChannel = outchannel; 742 DisConnected = FALSE; 743 744# ifdef XLA 745 if (!xla_host_ok(RealHostName)) 746 { 747 message("421 4.4.5 Too many SMTP sessions for this host"); 748 finis(FALSE, EX_OK); 749 } 750# endif /* XLA */ 751 /* find out name for interface of connection */ 752 if (getsockname(fileno(InChannel), &sa.sa, 753 &len) == 0) 754 { 755 p = hostnamebyanyaddr(&sa); 756 if (tTd(15, 9)) 757 dprintf("getreq: got name %s\n", p); 758 define(macid("{if_name}", NULL), 759 newstr(p), &BlankEnvelope); 760 761 /* do this only if it is not the loopback */ 762 /* interface: how to figure out? XXX */ 763 if (!isloopback(sa)) 764 { 765 define(macid("{if_addr}", NULL), 766 newstr(anynet_ntoa(&sa)), 767 &BlankEnvelope); 768 p = xalloc(5); 769 snprintf(p, 4, "%d", sa.sa.sa_family); 770 define(macid("{if_family}", NULL), p, 771 &BlankEnvelope); 772 if (tTd(15, 7)) 773 dprintf("getreq: got addr %s and family %s\n", 774 macvalue(macid("{if_addr}", NULL), 775 &BlankEnvelope), 776 macvalue(macid("{if_addr}", NULL), 777 &BlankEnvelope)); 778 } 779 else 780 { 781 define(macid("{if_addr}", NULL), NULL, 782 &BlankEnvelope); 783 define(macid("{if_family}", NULL), NULL, 784 &BlankEnvelope); 785 } 786 } 787 else 788 { 789 if (tTd(15, 7)) 790 dprintf("getreq: getsockname failed\n"); 791 define(macid("{if_name}", NULL), NULL, 792 &BlankEnvelope); 793 define(macid("{if_addr}", NULL), NULL, 794 &BlankEnvelope); 795 define(macid("{if_family}", NULL), NULL, 796 &BlankEnvelope); 797 } 798 break; 799 } 800 801 /* parent -- keep track of children */ 802 if (control) 803 { 804 snprintf(status, sizeof status, "control socket server child"); 805 proc_list_add(pid, status, PROC_CONTROL); 806 } 807 else 808 { 809 snprintf(status, sizeof status, 810 "SMTP server child for %s", 811 anynet_ntoa(&RealHostAddr)); 812 proc_list_add(pid, status, PROC_DAEMON); 813 } 814 (void) releasesignal(SIGCHLD); 815 816 /* close the read end of the synchronization pipe */ 817 if (pipefd[0] != -1) 818 { 819 (void) close(pipefd[0]); 820 pipefd[0] = -1; 821 } 822 823 /* close the port so that others will hang (for a while) */ 824 (void) close(t); 825 826 /* release the child by closing the read end of the sync pipe */ 827 if (pipefd[1] != -1) 828 { 829 (void) close(pipefd[1]); 830 pipefd[1] = -1; 831 } 832 } 833 834 if (tTd(15, 2)) 835 dprintf("getreq: returning\n"); 836 return &Daemons[curdaemon].d_flags; 837} 838/* 839** OPENDAEMONSOCKET -- open SMTP socket 840** 841** Deals with setting all appropriate options. 842** 843** Parameters: 844** d -- the structure for the daemon to open. 845** firsttime -- set if this is the initial open. 846** 847** Returns: 848** Size in bytes of the daemon socket addr. 849** 850** Side Effects: 851** Leaves DaemonSocket set to the open socket. 852** Exits if the socket cannot be created. 853*/ 854 855# define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 856 857static int 858opendaemonsocket(d, firsttime) 859 struct daemon *d; 860 bool firsttime; 861{ 862 int on = 1; 863 int fdflags; 864 SOCKADDR_LEN_T socksize = 0; 865 int ntries = 0; 866 int save_errno; 867 868 if (tTd(15, 2)) 869 dprintf("opendaemonsocket(%s)\n", d->d_name); 870 871 do 872 { 873 if (ntries > 0) 874 (void) sleep(5); 875 if (firsttime || d->d_socket < 0) 876 { 877 d->d_socket = socket(d->d_addr.sa.sa_family, 878 SOCK_STREAM, 0); 879 if (d->d_socket < 0) 880 { 881 save_errno = errno; 882 syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", d->d_name); 883 severe: 884 if (LogLevel > 0) 885 sm_syslog(LOG_ALERT, NOQID, 886 "daemon %s: problem creating SMTP socket", d->d_name); 887 d->d_socket = -1; 888 continue; 889 } 890 891 /* turn on network debugging? */ 892 if (tTd(15, 101)) 893 (void) setsockopt(d->d_socket, SOL_SOCKET, 894 SO_DEBUG, (char *)&on, 895 sizeof on); 896 897 (void) setsockopt(d->d_socket, SOL_SOCKET, 898 SO_REUSEADDR, (char *)&on, sizeof on); 899 (void) setsockopt(d->d_socket, SOL_SOCKET, 900 SO_KEEPALIVE, (char *)&on, sizeof on); 901 902# ifdef SO_RCVBUF 903 if (d->d_tcprcvbufsize > 0) 904 { 905 if (setsockopt(d->d_socket, SOL_SOCKET, 906 SO_RCVBUF, 907 (char *) &d->d_tcprcvbufsize, 908 sizeof(d->d_tcprcvbufsize)) < 0) 909 syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 910 } 911# endif /* SO_RCVBUF */ 912# ifdef SO_SNDBUF 913 if (d->d_tcpsndbufsize > 0) 914 { 915 if (setsockopt(d->d_socket, SOL_SOCKET, 916 SO_SNDBUF, 917 (char *) &d->d_tcpsndbufsize, 918 sizeof(d->d_tcpsndbufsize)) < 0) 919 syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 920 } 921# endif /* SO_SNDBUF */ 922 923 if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 924 fcntl(d->d_socket, F_SETFD, 925 fdflags | FD_CLOEXEC) == -1) 926 { 927 save_errno = errno; 928 syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 929 d->d_name, 930 fdflags == -1 ? "get" : "set", 931 errstring(save_errno)); 932 (void) close(d->d_socket); 933 goto severe; 934 } 935 936 switch (d->d_addr.sa.sa_family) 937 { 938# if NETINET 939 case AF_INET: 940 socksize = sizeof d->d_addr.sin; 941 break; 942# endif /* NETINET */ 943 944# if NETINET6 945 case AF_INET6: 946 socksize = sizeof d->d_addr.sin6; 947 break; 948# endif /* NETINET6 */ 949 950# if NETISO 951 case AF_ISO: 952 socksize = sizeof d->d_addr.siso; 953 break; 954# endif /* NETISO */ 955 956 default: 957 socksize = sizeof d->d_addr; 958 break; 959 } 960 961 if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 962 { 963 /* probably another daemon already */ 964 save_errno = errno; 965 syserr("opendaemonsocket: daemon %s: cannot bind", 966 d->d_name); 967 (void) close(d->d_socket); 968 goto severe; 969 } 970 } 971 if (!firsttime && 972 listen(d->d_socket, d->d_listenqueue) < 0) 973 { 974 save_errno = errno; 975 syserr("opendaemonsocket: daemon %s: cannot listen", 976 d->d_name); 977 (void) close(d->d_socket); 978 goto severe; 979 } 980 return socksize; 981 } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 982 syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 983 d->d_name); 984 /* NOTREACHED */ 985 return -1; /* avoid compiler warning on IRIX */ 986} 987/* 988** SETUPDAEMON -- setup socket for daemon 989** 990** Parameters: 991** daemonaddr -- socket for daemon 992** daemon -- number of daemon 993** 994** Returns: 995** port number on which daemon should run 996** 997*/ 998static u_short 999setupdaemon(daemonaddr) 1000 SOCKADDR *daemonaddr; 1001{ 1002 u_short port; 1003 1004 /* 1005 ** Set up the address for the mailer. 1006 */ 1007 1008 if (daemonaddr->sa.sa_family == AF_UNSPEC) 1009 { 1010 memset(daemonaddr, '\0', sizeof *daemonaddr); 1011# if NETINET 1012 daemonaddr->sa.sa_family = AF_INET; 1013# endif /* NETINET */ 1014 } 1015 1016 switch (daemonaddr->sa.sa_family) 1017 { 1018# if NETINET 1019 case AF_INET: 1020 if (daemonaddr->sin.sin_addr.s_addr == 0) 1021 daemonaddr->sin.sin_addr.s_addr = INADDR_ANY; 1022 port = daemonaddr->sin.sin_port; 1023 break; 1024# endif /* NETINET */ 1025 1026# if NETINET6 1027 case AF_INET6: 1028 if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 1029 daemonaddr->sin6.sin6_addr = in6addr_any; 1030 port = daemonaddr->sin6.sin6_port; 1031 break; 1032# endif /* NETINET6 */ 1033 1034 default: 1035 /* unknown protocol */ 1036 port = 0; 1037 break; 1038 } 1039 if (port == 0) 1040 { 1041# ifdef NO_GETSERVBYNAME 1042 port = htons(25); 1043# else /* NO_GETSERVBYNAME */ 1044 { 1045 register struct servent *sp; 1046 1047 sp = getservbyname("smtp", "tcp"); 1048 if (sp == NULL) 1049 { 1050 syserr("554 5.3.5 service \"smtp\" unknown"); 1051 port = htons(25); 1052 } 1053 else 1054 port = sp->s_port; 1055 } 1056# endif /* NO_GETSERVBYNAME */ 1057 } 1058 1059 switch (daemonaddr->sa.sa_family) 1060 { 1061# if NETINET 1062 case AF_INET: 1063 daemonaddr->sin.sin_port = port; 1064 break; 1065# endif /* NETINET */ 1066 1067# if NETINET6 1068 case AF_INET6: 1069 daemonaddr->sin6.sin6_port = port; 1070 break; 1071# endif /* NETINET6 */ 1072 1073 default: 1074 /* unknown protocol */ 1075 break; 1076 } 1077 return(port); 1078} 1079/* 1080** CLRDAEMON -- reset the daemon connection 1081** 1082** Parameters: 1083** none. 1084** 1085** Returns: 1086** none. 1087** 1088** Side Effects: 1089** releases any resources used by the passive daemon. 1090*/ 1091 1092void 1093clrdaemon() 1094{ 1095 int i; 1096 1097 for (i = 0; i < ndaemons; i++) 1098 { 1099 if (Daemons[i].d_socket >= 0) 1100 (void) close(Daemons[i].d_socket); 1101 Daemons[i].d_socket = -1; 1102 } 1103} 1104/* 1105** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 1106** 1107** Parameters: 1108** p -- the options line. 1109** d -- the daemon structure to fill in. 1110** 1111** Returns: 1112** none. 1113*/ 1114 1115static void 1116setsockaddroptions(p, d) 1117 register char *p; 1118 struct daemon *d; 1119{ 1120# if NETISO 1121 short portno; 1122# endif /* NETISO */ 1123 int l; 1124 char *h, *flags; 1125 char *port = NULL; 1126 char *addr = NULL; 1127 1128# if NETINET 1129 if (d->d_addr.sa.sa_family == AF_UNSPEC) 1130 d->d_addr.sa.sa_family = AF_INET; 1131# endif /* NETINET */ 1132 1133 while (p != NULL) 1134 { 1135 register char *f; 1136 register char *v; 1137 1138 while (isascii(*p) && isspace(*p)) 1139 p++; 1140 if (*p == '\0') 1141 break; 1142 f = p; 1143 p = strchr(p, ','); 1144 if (p != NULL) 1145 *p++ = '\0'; 1146 v = strchr(f, '='); 1147 if (v == NULL) 1148 continue; 1149 while (isascii(*++v) && isspace(*v)) 1150 continue; 1151 if (isascii(*f) && islower(*f)) 1152 *f = toupper(*f); 1153 1154 switch (*f) 1155 { 1156 case 'F': /* address family */ 1157 if (isascii(*v) && isdigit(*v)) 1158 d->d_addr.sa.sa_family = atoi(v); 1159# if NETINET 1160 else if (strcasecmp(v, "inet") == 0) 1161 d->d_addr.sa.sa_family = AF_INET; 1162# endif /* NETINET */ 1163# if NETINET6 1164 else if (strcasecmp(v, "inet6") == 0) 1165 d->d_addr.sa.sa_family = AF_INET6; 1166# endif /* NETINET6 */ 1167# if NETISO 1168 else if (strcasecmp(v, "iso") == 0) 1169 d->d_addr.sa.sa_family = AF_ISO; 1170# endif /* NETISO */ 1171# if NETNS 1172 else if (strcasecmp(v, "ns") == 0) 1173 d->d_addr.sa.sa_family = AF_NS; 1174# endif /* NETNS */ 1175# if NETX25 1176 else if (strcasecmp(v, "x.25") == 0) 1177 d->d_addr.sa.sa_family = AF_CCITT; 1178# endif /* NETX25 */ 1179 else 1180 syserr("554 5.3.5 Unknown address family %s in Family=option", 1181 v); 1182 break; 1183 1184 case 'A': /* address */ 1185 addr = v; 1186 break; 1187 1188 case 'P': /* port */ 1189 port = v; 1190 break; 1191 1192 case 'L': /* listen queue size */ 1193 d->d_listenqueue = atoi(v); 1194 break; 1195 1196 case 'M': /* modifiers (flags) */ 1197 l = 3 * strlen(v) + 3; 1198 h = v; 1199 flags = xalloc(l); 1200 d->d_mflags = flags; 1201 for (; *h != '\0'; h++) 1202 { 1203 if (!(isascii(*h) && isspace(*h))) 1204 { 1205 if (flags != d->d_mflags) 1206 *flags++ = ' '; 1207 *flags++ = *h; 1208 if (isupper(*h)) 1209 *flags++ = *h; 1210 } 1211 } 1212 *flags++ = '\0'; 1213 for (; *v != '\0'; v++) 1214 if (!(isascii(*v) && isspace(*v))) 1215 setbitn(bitidx(*v), d->d_flags); 1216 break; 1217 1218 case 'S': /* send buffer size */ 1219 d->d_tcpsndbufsize = atoi(v); 1220 break; 1221 1222 case 'R': /* receive buffer size */ 1223 d->d_tcprcvbufsize = atoi(v); 1224 break; 1225 1226 case 'N': /* name */ 1227 d->d_name = v; 1228 break; 1229 1230 default: 1231 syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 1232 f); 1233 } 1234 } 1235 1236 /* Check addr and port after finding family */ 1237 if (addr != NULL) 1238 { 1239 switch (d->d_addr.sa.sa_family) 1240 { 1241# if NETINET 1242 case AF_INET: 1243 if (!isascii(*addr) || !isdigit(*addr) || 1244 ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE)) 1245 { 1246 register struct hostent *hp; 1247 1248 hp = sm_gethostbyname(addr, AF_INET); 1249 if (hp == NULL) 1250 syserr("554 5.3.0 host \"%s\" unknown", 1251 addr); 1252 else 1253 { 1254 while (*(hp->h_addr_list) != NULL && 1255 hp->h_addrtype != AF_INET) 1256 hp->h_addr_list++; 1257 if (*(hp->h_addr_list) == NULL) 1258 syserr("554 5.3.0 host \"%s\" unknown", 1259 addr); 1260 else 1261 memmove(&d->d_addr.sin.sin_addr, 1262 *(hp->h_addr_list), 1263 INADDRSZ); 1264# if _FFR_FREEHOSTENT && NETINET6 1265 freehostent(hp); 1266 hp = NULL; 1267# endif /* _FFR_FREEHOSTENT && NETINET6 */ 1268 } 1269 } 1270 break; 1271# endif /* NETINET */ 1272 1273# if NETINET6 1274 case AF_INET6: 1275 if (!isascii(*addr) || 1276 (!isxdigit(*addr) && *addr != ':') || 1277 inet_pton(AF_INET6, addr, 1278 &d->d_addr.sin6.sin6_addr) != 1) 1279 { 1280 register struct hostent *hp; 1281 1282 hp = sm_gethostbyname(addr, AF_INET6); 1283 if (hp == NULL) 1284 syserr("554 5.3.0 host \"%s\" unknown", 1285 addr); 1286 else 1287 { 1288 while (*(hp->h_addr_list) != NULL && 1289 hp->h_addrtype != AF_INET6) 1290 hp->h_addr_list++; 1291 if (*(hp->h_addr_list) == NULL) 1292 syserr("554 5.3.0 host \"%s\" unknown", 1293 addr); 1294 else 1295 memmove(&d->d_addr.sin6.sin6_addr, 1296 *(hp->h_addr_list), 1297 IN6ADDRSZ); 1298# if _FFR_FREEHOSTENT 1299 freehostent(hp); 1300 hp = NULL; 1301# endif /* _FFR_FREEHOSTENT */ 1302 } 1303 } 1304 break; 1305# endif /* NETINET6 */ 1306 1307 default: 1308 syserr("554 5.3.5 address= option unsupported for family %d", 1309 d->d_addr.sa.sa_family); 1310 break; 1311 } 1312 } 1313 1314 if (port != NULL) 1315 { 1316 switch (d->d_addr.sa.sa_family) 1317 { 1318# if NETINET 1319 case AF_INET: 1320 if (isascii(*port) && isdigit(*port)) 1321 d->d_addr.sin.sin_port = htons((u_short)atoi((const char *)port)); 1322 else 1323 { 1324# ifdef NO_GETSERVBYNAME 1325 syserr("554 5.3.5 invalid port number: %s", 1326 port); 1327# else /* NO_GETSERVBYNAME */ 1328 register struct servent *sp; 1329 1330 sp = getservbyname(port, "tcp"); 1331 if (sp == NULL) 1332 syserr("554 5.3.5 service \"%s\" unknown", 1333 port); 1334 else 1335 d->d_addr.sin.sin_port = sp->s_port; 1336# endif /* NO_GETSERVBYNAME */ 1337 } 1338 break; 1339# endif /* NETINET */ 1340 1341# if NETINET6 1342 case AF_INET6: 1343 if (isascii(*port) && isdigit(*port)) 1344 d->d_addr.sin6.sin6_port = htons((u_short)atoi(port)); 1345 else 1346 { 1347# ifdef NO_GETSERVBYNAME 1348 syserr("554 5.3.5 invalid port number: %s", 1349 port); 1350# else /* NO_GETSERVBYNAME */ 1351 register struct servent *sp; 1352 1353 sp = getservbyname(port, "tcp"); 1354 if (sp == NULL) 1355 syserr("554 5.3.5 service \"%s\" unknown", 1356 port); 1357 else 1358 d->d_addr.sin6.sin6_port = sp->s_port; 1359# endif /* NO_GETSERVBYNAME */ 1360 } 1361 break; 1362# endif /* NETINET6 */ 1363 1364# if NETISO 1365 case AF_ISO: 1366 /* assume two byte transport selector */ 1367 if (isascii(*port) && isdigit(*port)) 1368 portno = htons((u_short)atoi(port)); 1369 else 1370 { 1371# ifdef NO_GETSERVBYNAME 1372 syserr("554 5.3.5 invalid port number: %s", 1373 port); 1374# else /* NO_GETSERVBYNAME */ 1375 register struct servent *sp; 1376 1377 sp = getservbyname(port, "tcp"); 1378 if (sp == NULL) 1379 syserr("554 5.3.5 service \"%s\" unknown", 1380 port); 1381 else 1382 portno = sp->s_port; 1383# endif /* NO_GETSERVBYNAME */ 1384 } 1385 memmove(TSEL(&d->d_addr.siso), 1386 (char *) &portno, 2); 1387 break; 1388# endif /* NETISO */ 1389 1390 default: 1391 syserr("554 5.3.5 Port= option unsupported for family %d", 1392 d->d_addr.sa.sa_family); 1393 break; 1394 } 1395 } 1396} 1397/* 1398** SETDAEMONOPTIONS -- set options for running the MTA daemon 1399** 1400** Parameters: 1401** p -- the options line. 1402** 1403** Returns: 1404** TRUE if successful, FALSE otherwise. 1405*/ 1406 1407bool 1408setdaemonoptions(p) 1409 register char *p; 1410{ 1411 if (ndaemons >= MAXDAEMONS) 1412 return FALSE; 1413 Daemons[ndaemons].d_socket = -1; 1414 Daemons[ndaemons].d_listenqueue = 10; 1415 clrbitmap(Daemons[ndaemons].d_flags); 1416 setsockaddroptions(p, &Daemons[ndaemons]); 1417 1418 if (Daemons[ndaemons].d_name != NULL) 1419 Daemons[ndaemons].d_name = newstr(Daemons[ndaemons].d_name); 1420 else 1421 { 1422 char num[30]; 1423 1424 snprintf(num, sizeof num, "Daemon%d", ndaemons); 1425 Daemons[ndaemons].d_name = newstr(num); 1426 } 1427 1428 if (tTd(37, 1)) 1429 { 1430 dprintf("Daemon %s flags: ", Daemons[ndaemons].d_name); 1431 if (bitnset(D_ETRNONLY, Daemons[ndaemons].d_flags)) 1432 dprintf("ETRNONLY "); 1433 if (bitnset(D_NOETRN, Daemons[ndaemons].d_flags)) 1434 dprintf("NOETRN "); 1435 dprintf("\n"); 1436 } 1437 ++ndaemons; 1438 return TRUE; 1439} 1440/* 1441** INITDAEMON -- initialize daemon if not yet done. 1442** 1443** Parameters: 1444** none 1445** 1446** Returns: 1447** none 1448** 1449** Side Effects: 1450** initializes structure for one daemon. 1451*/ 1452void 1453initdaemon() 1454{ 1455 if (ndaemons == 0) 1456 { 1457 Daemons[ndaemons].d_socket = -1; 1458 Daemons[ndaemons].d_listenqueue = 10; 1459 Daemons[ndaemons].d_name = "Daemon0"; 1460 ndaemons = 1; 1461 } 1462} 1463/* 1464** SETCLIENTOPTIONS -- set options for running the client 1465** 1466** Parameters: 1467** p -- the options line. 1468** 1469** Returns: 1470** none. 1471*/ 1472 1473static SOCKADDR ClientAddr; /* address for client */ 1474 1475void 1476setclientoptions(p) 1477 register char *p; 1478{ 1479 struct daemon d; 1480 extern ENVELOPE BlankEnvelope; 1481 1482 memset(&d, '\0', sizeof d); 1483 setsockaddroptions(p, &d); 1484 1485 /* grab what we need */ 1486 memcpy(&ClientAddr, &d.d_addr, sizeof ClientAddr); 1487 TcpSndBufferSize = d.d_tcpsndbufsize; 1488 TcpRcvBufferSize = d.d_tcprcvbufsize; 1489 if (d.d_mflags != NULL) 1490 define(macid("{client_flags}", NULL), d.d_mflags, 1491 &BlankEnvelope); 1492 else 1493 define(macid("{client_flags}", NULL), "", &BlankEnvelope); 1494} 1495/* 1496** ADDR_FAMILY -- determine address family from address 1497** 1498** Parameters: 1499** addr -- the string representation of the address 1500** 1501** Returns: 1502** AF_INET, AF_INET6 or AF_UNSPEC 1503** 1504** Side Effects: 1505** none. 1506*/ 1507 1508static int 1509addr_family(addr) 1510 char *addr; 1511{ 1512# if NETINET6 1513 SOCKADDR clt_addr; 1514# endif /* NETINET6 */ 1515 1516# if NETINET 1517 if (inet_addr(addr) != INADDR_NONE) 1518 { 1519 if (tTd(16, 9)) 1520 printf("addr_family(%s): INET\n", addr); 1521 return AF_INET; 1522 } 1523# endif /* NETINET */ 1524# if NETINET6 1525 if (inet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 1526 { 1527 if (tTd(16, 9)) 1528 printf("addr_family(%s): INET6\n", addr); 1529 return AF_INET6; 1530 } 1531# endif /* NETINET6 */ 1532 if (tTd(16, 9)) 1533 printf("addr_family(%s): UNSPEC\n", addr); 1534 return AF_UNSPEC; 1535} 1536/* 1537** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 1538** 1539** Parameters: 1540** host -- the name of the host. 1541** port -- the port number to connect to. 1542** mci -- a pointer to the mail connection information 1543** structure to be filled in. 1544** e -- the current envelope. 1545** 1546** Returns: 1547** An exit code telling whether the connection could be 1548** made and if not why not. 1549** 1550** Side Effects: 1551** none. 1552*/ 1553 1554static jmp_buf CtxConnectTimeout; 1555 1556SOCKADDR CurHostAddr; /* address of current host */ 1557 1558int 1559makeconnection(host, port, mci, e) 1560 char *host; 1561 volatile u_int port; 1562 register MCI *mci; 1563 ENVELOPE *e; 1564{ 1565 register volatile int addrno = 0; 1566 register volatile int s; 1567 register struct hostent *volatile hp = (struct hostent *)NULL; 1568 SOCKADDR addr; 1569 SOCKADDR clt_addr; 1570 int save_errno = 0; 1571 volatile SOCKADDR_LEN_T addrlen; 1572 volatile bool firstconnect; 1573 EVENT *volatile ev = NULL; 1574# if NETINET6 1575 volatile bool v6found = FALSE; 1576# endif /* NETINET6 */ 1577 volatile int family = InetMode; 1578 SOCKADDR_LEN_T len; 1579 volatile SOCKADDR_LEN_T socksize = 0; 1580 volatile bool clt_bind; 1581 BITMAP256 d_flags; 1582 char *p; 1583 extern ENVELOPE BlankEnvelope; 1584 1585 /* retranslate ${daemon_flags} into bitmap */ 1586 clrbitmap(d_flags); 1587 if ((p = macvalue(macid("{daemon_flags}", NULL), e)) != NULL) 1588 { 1589 for (; *p != '\0'; p++) 1590 { 1591 if (!(isascii(*p) && isspace(*p))) 1592 setbitn(bitidx(*p), d_flags); 1593 } 1594 } 1595 1596 /* "add" ${client_flags} to bitmap */ 1597 if ((p = macvalue(macid("{client_flags}", NULL), e)) != NULL) 1598 { 1599 for (; *p != '\0'; p++) 1600 { 1601 /* look for just this one flag */ 1602 if (*p == D_IFNHELO) 1603 { 1604 setbitn(bitidx(*p), d_flags); 1605 break; 1606 } 1607 } 1608 } 1609 1610# if NETINET6 1611 v4retry: 1612# endif /* NETINET6 */ 1613 clt_bind = FALSE; 1614 1615 /* Set up the address for outgoing connection. */ 1616 if (bitnset(D_BINDIF, d_flags) && 1617 (p = macvalue(macid("{if_addr}", NULL), e)) != NULL) 1618 { 1619# if NETINET6 1620 char p6[INET6_ADDRSTRLEN]; 1621# endif /* NETINET6 */ 1622 1623 memset(&clt_addr, '\0', sizeof clt_addr); 1624 1625 /* infer the address family from the address itself */ 1626 clt_addr.sa.sa_family = addr_family(p); 1627 switch (clt_addr.sa.sa_family) 1628 { 1629# if NETINET 1630 case AF_INET: 1631 if ((clt_addr.sin.sin_addr.s_addr = inet_addr(p)) 1632 != INADDR_NONE) 1633 { 1634 clt_bind = TRUE; 1635 socksize = sizeof (struct sockaddr_in); 1636 } 1637 else if (clt_addr.sin.sin_port != 0) 1638 { 1639 clt_addr.sin.sin_addr.s_addr = INADDR_ANY; 1640 clt_bind = TRUE; 1641 socksize = sizeof (struct sockaddr_in); 1642 } 1643 break; 1644# endif /* NETINET */ 1645 1646# if NETINET6 1647 case AF_INET6: 1648 if (inet_addr(p) != INADDR_NONE) 1649 snprintf(p6, sizeof p6, "::ffff:%s", p); 1650 else 1651 strlcpy(p6, p, sizeof p6); 1652 if (inet_pton(AF_INET6, p6, 1653 &clt_addr.sin6.sin6_addr) == 1) 1654 { 1655 clt_bind = TRUE; 1656 socksize = sizeof (struct sockaddr_in6); 1657 } 1658 else if (clt_addr.sin6.sin6_port != 0) 1659 { 1660 if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 1661 clt_addr.sin6.sin6_addr = in6addr_any; 1662 clt_bind = TRUE; 1663 socksize = sizeof (struct sockaddr_in6); 1664 } 1665 break; 1666# endif /* NETINET6 */ 1667 1668# if 0 1669 default: 1670 syserr("554 5.3.5 Address= option unsupported for family %d", 1671 clt_addr.sa.sa_family); 1672 break; 1673# endif /* 0 */ 1674 } 1675 if (clt_bind) 1676 family = clt_addr.sa.sa_family; 1677 } 1678 else 1679 { 1680 STRUCTCOPY(ClientAddr, clt_addr); 1681 if (clt_addr.sa.sa_family == AF_UNSPEC) 1682 clt_addr.sa.sa_family = InetMode; 1683 switch (clt_addr.sa.sa_family) 1684 { 1685# if NETINET 1686 case AF_INET: 1687 if (clt_addr.sin.sin_addr.s_addr == 0) 1688 clt_addr.sin.sin_addr.s_addr = INADDR_ANY; 1689 else 1690 clt_bind = TRUE; 1691 if (clt_addr.sin.sin_port != 0) 1692 clt_bind = TRUE; 1693 socksize = sizeof (struct sockaddr_in); 1694 break; 1695# endif /* NETINET */ 1696# if NETINET6 1697 case AF_INET6: 1698 if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 1699 clt_addr.sin6.sin6_addr = in6addr_any; 1700 else 1701 clt_bind = TRUE; 1702 socksize = sizeof (struct sockaddr_in6); 1703 if (clt_addr.sin6.sin6_port != 0) 1704 clt_bind = TRUE; 1705 break; 1706# endif /* NETINET6 */ 1707# if NETISO 1708 case AF_ISO: 1709 socksize = sizeof clt_addr.siso; 1710 clt_bind = TRUE; 1711 break; 1712# endif /* NETISO */ 1713 default: 1714 break; 1715 } 1716 } 1717 1718 /* 1719 ** Set up the address for the mailer. 1720 ** Accept "[a.b.c.d]" syntax for host name. 1721 */ 1722 1723# if NAMED_BIND 1724 h_errno = 0; 1725# endif /* NAMED_BIND */ 1726 errno = 0; 1727 memset(&CurHostAddr, '\0', sizeof CurHostAddr); 1728 memset(&addr, '\0', sizeof addr); 1729 SmtpPhase = mci->mci_phase = "initial connection"; 1730 CurHostName = host; 1731 1732 if (host[0] == '[') 1733 { 1734 p = strchr(host, ']'); 1735 if (p != NULL) 1736 { 1737# if NETINET 1738 unsigned long hid = INADDR_NONE; 1739# endif /* NETINET */ 1740# if NETINET6 1741 struct sockaddr_in6 hid6; 1742# endif /* NETINET6 */ 1743 1744 *p = '\0'; 1745# if NETINET6 1746 memset(&hid6, '\0', sizeof hid6); 1747# endif /* NETINET6 */ 1748# if NETINET 1749 if (family == AF_INET && 1750 (hid = inet_addr(&host[1])) != INADDR_NONE) 1751 { 1752 addr.sin.sin_family = AF_INET; 1753 addr.sin.sin_addr.s_addr = hid; 1754 } 1755 else 1756# endif /* NETINET */ 1757# if NETINET6 1758 if (family == AF_INET6 && 1759 inet_pton(AF_INET6, &host[1], 1760 &hid6.sin6_addr) == 1) 1761 { 1762 addr.sin6.sin6_family = AF_INET6; 1763 addr.sin6.sin6_addr = hid6.sin6_addr; 1764 } 1765 else 1766# endif /* NETINET6 */ 1767 { 1768 /* try it as a host name (avoid MX lookup) */ 1769 hp = sm_gethostbyname(&host[1], family); 1770 if (hp == NULL && p[-1] == '.') 1771 { 1772# if NAMED_BIND 1773 int oldopts = _res.options; 1774 1775 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 1776# endif /* NAMED_BIND */ 1777 p[-1] = '\0'; 1778 hp = sm_gethostbyname(&host[1], 1779 family); 1780 p[-1] = '.'; 1781# if NAMED_BIND 1782 _res.options = oldopts; 1783# endif /* NAMED_BIND */ 1784 } 1785 *p = ']'; 1786 goto gothostent; 1787 } 1788 *p = ']'; 1789 } 1790 if (p == NULL) 1791 { 1792 extern char MsgBuf[]; 1793 1794 usrerrenh("5.1.2", 1795 "553 Invalid numeric domain spec \"%s\"", 1796 host); 1797 mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 1798 errno = EINVAL; 1799 return EX_NOHOST; 1800 } 1801 } 1802 else 1803 { 1804 /* contortion to get around SGI cc complaints */ 1805 { 1806 p = &host[strlen(host) - 1]; 1807 hp = sm_gethostbyname(host, family); 1808 if (hp == NULL && *p == '.') 1809 { 1810# if NAMED_BIND 1811 int oldopts = _res.options; 1812 1813 _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 1814# endif /* NAMED_BIND */ 1815 *p = '\0'; 1816 hp = sm_gethostbyname(host, family); 1817 *p = '.'; 1818# if NAMED_BIND 1819 _res.options = oldopts; 1820# endif /* NAMED_BIND */ 1821 } 1822 } 1823gothostent: 1824 if (hp == NULL) 1825 { 1826# if NAMED_BIND 1827 /* check for name server timeouts */ 1828 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 1829 (errno == ECONNREFUSED && UseNameServer)) 1830 { 1831 save_errno = errno; 1832 mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL); 1833 errno = save_errno; 1834 return EX_TEMPFAIL; 1835 } 1836# endif /* NAMED_BIND */ 1837# if NETINET6 1838 /* 1839 ** Try v6 first, then fall back to v4. 1840 ** If we found a v6 address, but no v4 1841 ** addresses, then TEMPFAIL. 1842 */ 1843 1844 if (family == AF_INET6) 1845 { 1846 family = AF_INET; 1847 goto v4retry; 1848 } 1849 if (v6found) 1850 goto v6tempfail; 1851# endif /* NETINET6 */ 1852 save_errno = errno; 1853 mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 1854 errno = save_errno; 1855 return EX_NOHOST; 1856 } 1857 addr.sa.sa_family = hp->h_addrtype; 1858 switch (hp->h_addrtype) 1859 { 1860# if NETINET 1861 case AF_INET: 1862 memmove(&addr.sin.sin_addr, 1863 hp->h_addr, 1864 INADDRSZ); 1865 break; 1866# endif /* NETINET */ 1867 1868# if NETINET6 1869 case AF_INET6: 1870 memmove(&addr.sin6.sin6_addr, 1871 hp->h_addr, 1872 IN6ADDRSZ); 1873 break; 1874# endif /* NETINET6 */ 1875 1876 default: 1877 if (hp->h_length > sizeof addr.sa.sa_data) 1878 { 1879 syserr("makeconnection: long sa_data: family %d len %d", 1880 hp->h_addrtype, hp->h_length); 1881 mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 1882 errno = EINVAL; 1883 return EX_NOHOST; 1884 } 1885 memmove(addr.sa.sa_data, 1886 hp->h_addr, 1887 hp->h_length); 1888 break; 1889 } 1890 addrno = 1; 1891 } 1892 1893 /* 1894 ** Determine the port number. 1895 */ 1896 1897 if (port == 0) 1898 { 1899# ifdef NO_GETSERVBYNAME 1900 port = htons(25); 1901# else /* NO_GETSERVBYNAME */ 1902 register struct servent *sp = getservbyname("smtp", "tcp"); 1903 1904 if (sp == NULL) 1905 { 1906 if (LogLevel > 2) 1907 sm_syslog(LOG_ERR, NOQID, 1908 "makeconnection: service \"smtp\" unknown"); 1909 port = htons(25); 1910 } 1911 else 1912 port = sp->s_port; 1913# endif /* NO_GETSERVBYNAME */ 1914 } 1915 1916 switch (addr.sa.sa_family) 1917 { 1918# if NETINET 1919 case AF_INET: 1920 addr.sin.sin_port = port; 1921 addrlen = sizeof (struct sockaddr_in); 1922 break; 1923# endif /* NETINET */ 1924 1925# if NETINET6 1926 case AF_INET6: 1927 addr.sin6.sin6_port = port; 1928 addrlen = sizeof (struct sockaddr_in6); 1929 break; 1930# endif /* NETINET6 */ 1931 1932# if NETISO 1933 case AF_ISO: 1934 /* assume two byte transport selector */ 1935 memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 1936 addrlen = sizeof (struct sockaddr_iso); 1937 break; 1938# endif /* NETISO */ 1939 1940 default: 1941 syserr("Can't connect to address family %d", addr.sa.sa_family); 1942 mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 1943 errno = EINVAL; 1944# if _FFR_FREEHOSTENT && NETINET6 1945 if (hp != NULL) 1946 freehostent(hp); 1947# endif /* _FFR_FREEHOSTENT && NETINET6 */ 1948 return EX_NOHOST; 1949 } 1950 1951 /* 1952 ** Try to actually open the connection. 1953 */ 1954 1955# ifdef XLA 1956 /* if too many connections, don't bother trying */ 1957 if (!xla_noqueue_ok(host)) 1958 { 1959# if _FFR_FREEHOSTENT && NETINET6 1960 if (hp != NULL) 1961 freehostent(hp); 1962# endif /* _FFR_FREEHOSTENT && NETINET6 */ 1963 return EX_TEMPFAIL; 1964 } 1965# endif /* XLA */ 1966 1967 firstconnect = TRUE; 1968 for (;;) 1969 { 1970 if (tTd(16, 1)) 1971 dprintf("makeconnection (%s [%s])\n", 1972 host, anynet_ntoa(&addr)); 1973 1974 /* save for logging */ 1975 CurHostAddr = addr; 1976 1977 if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 1978 { 1979 int rport = IPPORT_RESERVED - 1; 1980 1981 s = rresvport(&rport); 1982 } 1983 else 1984 { 1985 s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 1986 } 1987 if (s < 0) 1988 { 1989 save_errno = errno; 1990 syserr("makeconnection: cannot create socket"); 1991# ifdef XLA 1992 xla_host_end(host); 1993# endif /* XLA */ 1994 mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 1995# if _FFR_FREEHOSTENT && NETINET6 1996 if (hp != NULL) 1997 freehostent(hp); 1998# endif /* _FFR_FREEHOSTENT && NETINET6 */ 1999 errno = save_errno; 2000 return EX_TEMPFAIL; 2001 } 2002 2003# ifdef SO_SNDBUF 2004 if (TcpSndBufferSize > 0) 2005 { 2006 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 2007 (char *) &TcpSndBufferSize, 2008 sizeof(TcpSndBufferSize)) < 0) 2009 syserr("makeconnection: setsockopt(SO_SNDBUF)"); 2010 } 2011# endif /* SO_SNDBUF */ 2012# ifdef SO_RCVBUF 2013 if (TcpRcvBufferSize > 0) 2014 { 2015 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 2016 (char *) &TcpRcvBufferSize, 2017 sizeof(TcpRcvBufferSize)) < 0) 2018 syserr("makeconnection: setsockopt(SO_RCVBUF)"); 2019 } 2020# endif /* SO_RCVBUF */ 2021 2022 2023 if (tTd(16, 1)) 2024 dprintf("makeconnection: fd=%d\n", s); 2025 2026 /* turn on network debugging? */ 2027 if (tTd(16, 101)) 2028 { 2029 int on = 1; 2030 2031 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 2032 (char *)&on, sizeof on); 2033 } 2034 if (e->e_xfp != NULL) 2035 (void) fflush(e->e_xfp); /* for debugging */ 2036 errno = 0; /* for debugging */ 2037 2038 if (clt_bind) 2039 { 2040 int on = 1; 2041 2042 switch (clt_addr.sa.sa_family) 2043 { 2044# if NETINET 2045 case AF_INET: 2046 if (clt_addr.sin.sin_port != 0) 2047 (void) setsockopt(s, SOL_SOCKET, 2048 SO_REUSEADDR, 2049 (char *) &on, 2050 sizeof on); 2051 break; 2052# endif /* NETINET */ 2053 2054# if NETINET6 2055 case AF_INET6: 2056 if (clt_addr.sin6.sin6_port != 0) 2057 (void) setsockopt(s, SOL_SOCKET, 2058 SO_REUSEADDR, 2059 (char *) &on, 2060 sizeof on); 2061 break; 2062# endif /* NETINET6 */ 2063 } 2064 2065 if (bind(s, &clt_addr.sa, socksize) < 0) 2066 { 2067 save_errno = errno; 2068 (void) close(s); 2069 errno = save_errno; 2070 syserr("makeconnection: cannot bind socket [%s]", 2071 anynet_ntoa(&clt_addr)); 2072# if _FFR_FREEHOSTENT && NETINET6 2073 if (hp != NULL) 2074 freehostent(hp); 2075# endif /* _FFR_FREEHOSTENT && NETINET6 */ 2076 errno = save_errno; 2077 return EX_TEMPFAIL; 2078 } 2079 } 2080 2081 /* 2082 ** Linux seems to hang in connect for 90 minutes (!!!). 2083 ** Time out the connect to avoid this problem. 2084 */ 2085 2086 if (setjmp(CtxConnectTimeout) == 0) 2087 { 2088 int i; 2089 2090 if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 2091 ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0); 2092 else if (TimeOuts.to_connect != 0) 2093 ev = setevent(TimeOuts.to_connect, connecttimeout, 0); 2094 else 2095 ev = NULL; 2096 2097 switch (ConnectOnlyTo.sa.sa_family) 2098 { 2099# if NETINET 2100 case AF_INET: 2101 addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 2102 break; 2103# endif /* NETINET */ 2104 2105# if NETINET6 2106 case AF_INET6: 2107 memmove(&addr.sin6.sin6_addr, 2108 &ConnectOnlyTo.sin6.sin6_addr, 2109 IN6ADDRSZ); 2110 break; 2111# endif /* NETINET6 */ 2112 } 2113 i = connect(s, (struct sockaddr *) &addr, addrlen); 2114 save_errno = errno; 2115 if (ev != NULL) 2116 clrevent(ev); 2117 if (i >= 0) 2118 break; 2119 } 2120 else 2121 save_errno = errno; 2122 2123 /* if running demand-dialed connection, try again */ 2124 if (DialDelay > 0 && firstconnect) 2125 { 2126 if (tTd(16, 1)) 2127 dprintf("Connect failed (%s); trying again...\n", 2128 errstring(save_errno)); 2129 firstconnect = FALSE; 2130 (void) sleep(DialDelay); 2131 continue; 2132 } 2133 2134 /* couldn't connect.... figure out why */ 2135 (void) close(s); 2136 2137 if (LogLevel >= 14) 2138 sm_syslog(LOG_INFO, e->e_id, 2139 "makeconnection (%s [%s]) failed: %s", 2140 host, anynet_ntoa(&addr), 2141 errstring(save_errno)); 2142 2143 if (hp != NULL && hp->h_addr_list[addrno] != NULL) 2144 { 2145 if (tTd(16, 1)) 2146 dprintf("Connect failed (%s); trying new address....\n", 2147 errstring(save_errno)); 2148 switch (addr.sa.sa_family) 2149 { 2150# if NETINET 2151 case AF_INET: 2152 memmove(&addr.sin.sin_addr, 2153 hp->h_addr_list[addrno++], 2154 INADDRSZ); 2155 break; 2156# endif /* NETINET */ 2157 2158# if NETINET6 2159 case AF_INET6: 2160 memmove(&addr.sin6.sin6_addr, 2161 hp->h_addr_list[addrno++], 2162 IN6ADDRSZ); 2163 break; 2164# endif /* NETINET6 */ 2165 2166 default: 2167 memmove(addr.sa.sa_data, 2168 hp->h_addr_list[addrno++], 2169 hp->h_length); 2170 break; 2171 } 2172 continue; 2173 } 2174 errno = save_errno; 2175 2176# if NETINET6 2177 if (family == AF_INET6) 2178 { 2179 if (tTd(16, 1)) 2180 dprintf("Connect failed (%s); retrying with AF_INET....\n", 2181 errstring(save_errno)); 2182 v6found = TRUE; 2183 family = AF_INET; 2184# if _FFR_FREEHOSTENT 2185 if (hp != NULL) 2186 { 2187 freehostent(hp); 2188 hp = NULL; 2189 } 2190# endif /* _FFR_FREEHOSTENT */ 2191 goto v4retry; 2192 } 2193 v6tempfail: 2194# endif /* NETINET6 */ 2195 /* couldn't open connection */ 2196# if NETINET6 2197 /* Don't clobber an already saved errno from v4retry */ 2198 if (errno > 0) 2199# endif /* NETINET6 */ 2200 save_errno = errno; 2201 if (tTd(16, 1)) 2202 dprintf("Connect failed (%s)\n", errstring(save_errno)); 2203# ifdef XLA 2204 xla_host_end(host); 2205# endif /* XLA */ 2206 mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 2207# if _FFR_FREEHOSTENT && NETINET6 2208 if (hp != NULL) 2209 freehostent(hp); 2210# endif /* _FFR_FREEHOSTENT && NETINET6 */ 2211 errno = save_errno; 2212 return EX_TEMPFAIL; 2213 } 2214 2215# if _FFR_FREEHOSTENT && NETINET6 2216 if (hp != NULL) 2217 { 2218 freehostent(hp); 2219 hp = NULL; 2220 } 2221# endif /* _FFR_FREEHOSTENT && NETINET6 */ 2222 2223 /* connection ok, put it into canonical form */ 2224 mci->mci_out = NULL; 2225 if ((mci->mci_out = fdopen(s, "w")) == NULL || 2226 (s = dup(s)) < 0 || 2227 (mci->mci_in = fdopen(s, "r")) == NULL) 2228 { 2229 save_errno = errno; 2230 syserr("cannot open SMTP client channel, fd=%d", s); 2231 mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 2232 if (mci->mci_out != NULL) 2233 (void) fclose(mci->mci_out); 2234 (void) close(s); 2235 errno = save_errno; 2236 return EX_TEMPFAIL; 2237 } 2238 2239 /* find out name for Interface through which we connect */ 2240 len = sizeof addr; 2241 if (getsockname(s, &addr.sa, &len) == 0) 2242 { 2243 char *name; 2244 char *p; 2245 2246 define(macid("{if_addr}", NULL), newstr(anynet_ntoa(&addr)), 2247 &BlankEnvelope); 2248 p = xalloc(5); 2249 snprintf(p, 4, "%d", addr.sa.sa_family); 2250 define(macid("{if_family}", NULL), p, &BlankEnvelope); 2251 2252 name = hostnamebyanyaddr(&addr); 2253 define(macid("{if_name}", NULL), newstr(name), &BlankEnvelope); 2254 if (LogLevel > 11) 2255 { 2256 /* log connection information */ 2257 sm_syslog(LOG_INFO, e->e_id, 2258 "SMTP outgoing connect on %.40s", name); 2259 } 2260 if (bitnset(D_IFNHELO, d_flags)) 2261 { 2262 if (name[0] != '[' && strchr(name, '.') != NULL) 2263 mci->mci_heloname = newstr(name); 2264 } 2265 } 2266 else 2267 { 2268 define(macid("{if_name}", NULL), NULL, &BlankEnvelope); 2269 define(macid("{if_addr}", NULL), NULL, &BlankEnvelope); 2270 define(macid("{if_family}", NULL), NULL, &BlankEnvelope); 2271 } 2272 mci_setstat(mci, EX_OK, NULL, NULL); 2273 return EX_OK; 2274} 2275 2276static void 2277connecttimeout() 2278{ 2279 errno = ETIMEDOUT; 2280 longjmp(CtxConnectTimeout, 1); 2281} 2282/* 2283** MAKECONNECTION_DS -- make a connection to a domain socket. 2284** 2285** Parameters: 2286** mux_path -- the path of the socket to connect to. 2287** mci -- a pointer to the mail connection information 2288** structure to be filled in. 2289** 2290** Returns: 2291** An exit code telling whether the connection could be 2292** made and if not why not. 2293** 2294** Side Effects: 2295** none. 2296*/ 2297 2298# if NETUNIX 2299int makeconnection_ds(mux_path, mci) 2300 char *mux_path; 2301 register MCI *mci; 2302{ 2303 int sock; 2304 int rval, save_errno; 2305 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 2306 struct sockaddr_un unix_addr; 2307 2308 /* if not safe, don't connect */ 2309 rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 2310 sff, S_IRUSR|S_IWUSR, NULL); 2311 2312 if (rval != 0) 2313 { 2314 syserr("makeconnection_ds: unsafe domain socket"); 2315 mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 2316 errno = rval; 2317 return EX_TEMPFAIL; 2318 } 2319 2320 /* prepare address structure */ 2321 memset(&unix_addr, '\0', sizeof unix_addr); 2322 unix_addr.sun_family = AF_UNIX; 2323 2324 if (strlen(mux_path) >= sizeof unix_addr.sun_path) 2325 { 2326 syserr("makeconnection_ds: domain socket name too long"); 2327 /* XXX why TEMPFAIL ? */ 2328 mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 2329 errno = ENAMETOOLONG; 2330 return EX_UNAVAILABLE; 2331 } 2332 (void) strlcpy(unix_addr.sun_path, mux_path, sizeof unix_addr.sun_path); 2333 2334 /* initialize domain socket */ 2335 sock = socket(AF_UNIX, SOCK_STREAM, 0); 2336 if (sock == -1) 2337 { 2338 save_errno = errno; 2339 syserr("makeconnection_ds: could not create domain socket"); 2340 mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 2341 errno = save_errno; 2342 return EX_TEMPFAIL; 2343 } 2344 2345 /* connect to server */ 2346 if (connect(sock, (struct sockaddr *) &unix_addr, 2347 sizeof(unix_addr)) == -1) 2348 { 2349 save_errno = errno; 2350 syserr("Could not connect to socket %s", mux_path); 2351 mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 2352 (void) close(sock); 2353 errno = save_errno; 2354 return EX_TEMPFAIL; 2355 } 2356 2357 /* connection ok, put it into canonical form */ 2358 mci->mci_out = NULL; 2359 if ((mci->mci_out = fdopen(sock, "w")) == NULL || 2360 (sock = dup(sock)) < 0 || 2361 (mci->mci_in = fdopen(sock, "r")) == NULL) 2362 { 2363 save_errno = errno; 2364 syserr("cannot open SMTP client channel, fd=%d", sock); 2365 mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 2366 if (mci->mci_out != NULL) 2367 (void) fclose(mci->mci_out); 2368 (void) close(sock); 2369 errno = save_errno; 2370 return EX_TEMPFAIL; 2371 } 2372 2373 mci_setstat(mci, EX_OK, NULL, NULL); 2374 errno = 0; 2375 return EX_OK; 2376} 2377# endif /* NETUNIX */ 2378/* 2379** MYHOSTNAME -- return the name of this host. 2380** 2381** Parameters: 2382** hostbuf -- a place to return the name of this host. 2383** size -- the size of hostbuf. 2384** 2385** Returns: 2386** A list of aliases for this host. 2387** 2388** Side Effects: 2389** Adds numeric codes to $=w. 2390*/ 2391 2392struct hostent * 2393myhostname(hostbuf, size) 2394 char hostbuf[]; 2395 int size; 2396{ 2397 register struct hostent *hp; 2398 2399 if (gethostname(hostbuf, size) < 0) 2400 { 2401 (void) strlcpy(hostbuf, "localhost", size); 2402 } 2403 hp = sm_gethostbyname(hostbuf, InetMode); 2404 if (hp == NULL) 2405 return NULL; 2406 if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 2407 (void) cleanstrcpy(hostbuf, hp->h_name, size); 2408 2409# if NETINFO 2410 if (strchr(hostbuf, '.') == NULL) 2411 { 2412 char *domainname; 2413 2414 domainname = ni_propval("/locations", NULL, "resolver", 2415 "domain", '\0'); 2416 if (domainname != NULL && 2417 strlen(domainname) + strlen(hostbuf) + 1 < size) 2418 { 2419 (void) strlcat(hostbuf, ".", size); 2420 (void) strlcat(hostbuf, domainname, size); 2421 } 2422 } 2423# endif /* NETINFO */ 2424 2425 /* 2426 ** If there is still no dot in the name, try looking for a 2427 ** dotted alias. 2428 */ 2429 2430 if (strchr(hostbuf, '.') == NULL) 2431 { 2432 char **ha; 2433 2434 for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 2435 { 2436 if (strchr(*ha, '.') != NULL) 2437 { 2438 (void) cleanstrcpy(hostbuf, *ha, size - 1); 2439 hostbuf[size - 1] = '\0'; 2440 break; 2441 } 2442 } 2443 } 2444 2445 /* 2446 ** If _still_ no dot, wait for a while and try again -- it is 2447 ** possible that some service is starting up. This can result 2448 ** in excessive delays if the system is badly configured, but 2449 ** there really isn't a way around that, particularly given that 2450 ** the config file hasn't been read at this point. 2451 ** All in all, a bit of a mess. 2452 */ 2453 2454 if (strchr(hostbuf, '.') == NULL && 2455 !getcanonname(hostbuf, size, TRUE)) 2456 { 2457 sm_syslog(LOG_CRIT, NOQID, 2458 "My unqualified host name (%s) unknown; sleeping for retry", 2459 hostbuf); 2460 message("My unqualified host name (%s) unknown; sleeping for retry", 2461 hostbuf); 2462 (void) sleep(60); 2463 if (!getcanonname(hostbuf, size, TRUE)) 2464 { 2465 sm_syslog(LOG_ALERT, NOQID, 2466 "unable to qualify my own domain name (%s) -- using short name", 2467 hostbuf); 2468 message("WARNING: unable to qualify my own domain name (%s) -- using short name", 2469 hostbuf); 2470 } 2471 } 2472 return hp; 2473} 2474/* 2475** ADDRCMP -- compare two host addresses 2476** 2477** Parameters: 2478** hp -- hostent structure for the first address 2479** ha -- actual first address 2480** sa -- second address 2481** 2482** Returns: 2483** 0 -- if ha and sa match 2484** else -- they don't match 2485*/ 2486 2487static int 2488addrcmp(hp, ha, sa) 2489 struct hostent *hp; 2490 char *ha; 2491 SOCKADDR *sa; 2492{ 2493# if NETINET6 2494 u_char *a; 2495# endif /* NETINET6 */ 2496 2497 switch (sa->sa.sa_family) 2498 { 2499# if NETINET 2500 case AF_INET: 2501 if (hp->h_addrtype == AF_INET) 2502 return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 2503 break; 2504# endif /* NETINET */ 2505 2506# if NETINET6 2507 case AF_INET6: 2508 a = (u_char *) &sa->sin6.sin6_addr; 2509 2510 /* Straight binary comparison */ 2511 if (hp->h_addrtype == AF_INET6) 2512 return memcmp(ha, a, IN6ADDRSZ); 2513 2514 /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 2515 if (hp->h_addrtype == AF_INET && 2516 IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 2517 return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 2518 break; 2519# endif /* NETINET6 */ 2520 } 2521 return -1; 2522} 2523/* 2524** GETAUTHINFO -- get the real host name associated with a file descriptor 2525** 2526** Uses RFC1413 protocol to try to get info from the other end. 2527** 2528** Parameters: 2529** fd -- the descriptor 2530** may_be_forged -- an outage that is set to TRUE if the 2531** forward lookup of RealHostName does not match 2532** RealHostAddr; set to FALSE if they do match. 2533** 2534** Returns: 2535** The user@host information associated with this descriptor. 2536*/ 2537 2538static jmp_buf CtxAuthTimeout; 2539 2540static void 2541authtimeout() 2542{ 2543 longjmp(CtxAuthTimeout, 1); 2544} 2545 2546char * 2547getauthinfo(fd, may_be_forged) 2548 int fd; 2549 bool *may_be_forged; 2550{ 2551 volatile u_short port = 0; 2552 SOCKADDR_LEN_T falen; 2553 register char *volatile p = NULL; 2554 SOCKADDR la; 2555 SOCKADDR_LEN_T lalen; 2556 register struct servent *sp; 2557 volatile int s; 2558 int i = 0; 2559 EVENT *ev; 2560 int nleft; 2561 struct hostent *hp; 2562 char *ostype = NULL; 2563 char **ha; 2564 char ibuf[MAXNAME + 1]; 2565 static char hbuf[MAXNAME * 2 + 11]; 2566 2567 *may_be_forged = FALSE; 2568 falen = sizeof RealHostAddr; 2569 if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 2570 falen <= 0 || RealHostAddr.sa.sa_family == 0) 2571 { 2572 if (i < 0) 2573 { 2574 /* 2575 ** ENOTSOCK is OK: bail on anything else, but reset 2576 ** errno in this case, so a mis-report doesn't 2577 ** happen later. 2578 */ 2579 if (errno != ENOTSOCK) 2580 return NULL; 2581 errno = 0; 2582 } 2583 (void) snprintf(hbuf, sizeof hbuf, "%s@localhost", 2584 RealUserName); 2585 if (tTd(9, 1)) 2586 dprintf("getauthinfo: %s\n", hbuf); 2587 return hbuf; 2588 } 2589 2590 if (RealHostName == NULL) 2591 { 2592 /* translate that to a host name */ 2593 RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 2594 if (strlen(RealHostName) > MAXNAME) 2595 RealHostName[MAXNAME] = '\0'; 2596 } 2597 2598 /* cross check RealHostName with forward DNS lookup */ 2599 if (anynet_ntoa(&RealHostAddr)[0] == '[' || 2600 RealHostName[0] == '[') 2601 { 2602 /* 2603 ** address is not a socket or have an 2604 ** IP address with no forward lookup 2605 */ 2606 *may_be_forged = FALSE; 2607 } 2608 else 2609 { 2610 /* try to match the reverse against the forward lookup */ 2611 hp = sm_gethostbyname(RealHostName, 2612 RealHostAddr.sa.sa_family); 2613 2614 if (hp == NULL) 2615 *may_be_forged = TRUE; 2616 else 2617 { 2618 for (ha = hp->h_addr_list; *ha != NULL; ha++) 2619 if (addrcmp(hp, *ha, &RealHostAddr) == 0) 2620 break; 2621 *may_be_forged = *ha == NULL; 2622# if _FFR_FREEHOSTENT && NETINET6 2623 freehostent(hp); 2624 hp = NULL; 2625# endif /* _FFR_FREEHOSTENT && NETINET6 */ 2626 } 2627 } 2628 2629 if (TimeOuts.to_ident == 0) 2630 goto noident; 2631 2632 lalen = sizeof la; 2633 switch (RealHostAddr.sa.sa_family) 2634 { 2635# if NETINET 2636 case AF_INET: 2637 if (getsockname(fd, &la.sa, &lalen) < 0 || 2638 lalen <= 0 || 2639 la.sa.sa_family != AF_INET) 2640 { 2641 /* no ident info */ 2642 goto noident; 2643 } 2644 port = RealHostAddr.sin.sin_port; 2645 2646 /* create ident query */ 2647 (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 2648 ntohs(RealHostAddr.sin.sin_port), 2649 ntohs(la.sin.sin_port)); 2650 2651 /* create local address */ 2652 la.sin.sin_port = 0; 2653 2654 /* create foreign address */ 2655# ifdef NO_GETSERVBYNAME 2656 RealHostAddr.sin.sin_port = htons(113); 2657# else /* NO_GETSERVBYNAME */ 2658 sp = getservbyname("auth", "tcp"); 2659 if (sp != NULL) 2660 RealHostAddr.sin.sin_port = sp->s_port; 2661 else 2662 RealHostAddr.sin.sin_port = htons(113); 2663 break; 2664# endif /* NO_GETSERVBYNAME */ 2665# endif /* NETINET */ 2666 2667# if NETINET6 2668 case AF_INET6: 2669 if (getsockname(fd, &la.sa, &lalen) < 0 || 2670 lalen <= 0 || 2671 la.sa.sa_family != AF_INET6) 2672 { 2673 /* no ident info */ 2674 goto noident; 2675 } 2676 port = RealHostAddr.sin6.sin6_port; 2677 2678 /* create ident query */ 2679 (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 2680 ntohs(RealHostAddr.sin6.sin6_port), 2681 ntohs(la.sin6.sin6_port)); 2682 2683 /* create local address */ 2684 la.sin6.sin6_port = 0; 2685 2686 /* create foreign address */ 2687# ifdef NO_GETSERVBYNAME 2688 RealHostAddr.sin6.sin6_port = htons(113); 2689# else /* NO_GETSERVBYNAME */ 2690 sp = getservbyname("auth", "tcp"); 2691 if (sp != NULL) 2692 RealHostAddr.sin6.sin6_port = sp->s_port; 2693 else 2694 RealHostAddr.sin6.sin6_port = htons(113); 2695 break; 2696# endif /* NO_GETSERVBYNAME */ 2697# endif /* NETINET6 */ 2698 default: 2699 /* no ident info */ 2700 goto noident; 2701 } 2702 2703 s = -1; 2704 if (setjmp(CtxAuthTimeout) != 0) 2705 { 2706 if (s >= 0) 2707 (void) close(s); 2708 goto noident; 2709 } 2710 2711 /* put a timeout around the whole thing */ 2712 ev = setevent(TimeOuts.to_ident, authtimeout, 0); 2713 2714 2715 /* connect to foreign IDENT server using same address as SMTP socket */ 2716 s = socket(la.sa.sa_family, SOCK_STREAM, 0); 2717 if (s < 0) 2718 { 2719 clrevent(ev); 2720 goto noident; 2721 } 2722 if (bind(s, &la.sa, lalen) < 0 || 2723 connect(s, &RealHostAddr.sa, lalen) < 0) 2724 { 2725 goto closeident; 2726 } 2727 2728 if (tTd(9, 10)) 2729 dprintf("getauthinfo: sent %s", ibuf); 2730 2731 /* send query */ 2732 if (write(s, ibuf, strlen(ibuf)) < 0) 2733 goto closeident; 2734 2735 /* get result */ 2736 p = &ibuf[0]; 2737 nleft = sizeof ibuf - 1; 2738 while ((i = read(s, p, nleft)) > 0) 2739 { 2740 p += i; 2741 nleft -= i; 2742 *p = '\0'; 2743 if (strchr(ibuf, '\n') != NULL) 2744 break; 2745 } 2746 (void) close(s); 2747 clrevent(ev); 2748 if (i < 0 || p == &ibuf[0]) 2749 goto noident; 2750 2751 if (*--p == '\n' && *--p == '\r') 2752 p--; 2753 *++p = '\0'; 2754 2755 if (tTd(9, 3)) 2756 dprintf("getauthinfo: got %s\n", ibuf); 2757 2758 /* parse result */ 2759 p = strchr(ibuf, ':'); 2760 if (p == NULL) 2761 { 2762 /* malformed response */ 2763 goto noident; 2764 } 2765 while (isascii(*++p) && isspace(*p)) 2766 continue; 2767 if (strncasecmp(p, "userid", 6) != 0) 2768 { 2769 /* presumably an error string */ 2770 goto noident; 2771 } 2772 p += 6; 2773 while (isascii(*p) && isspace(*p)) 2774 p++; 2775 if (*p++ != ':') 2776 { 2777 /* either useridxx or malformed response */ 2778 goto noident; 2779 } 2780 2781 /* p now points to the OSTYPE field */ 2782 while (isascii(*p) && isspace(*p)) 2783 p++; 2784 ostype = p; 2785 p = strchr(p, ':'); 2786 if (p == NULL) 2787 { 2788 /* malformed response */ 2789 goto noident; 2790 } 2791 else 2792 { 2793 char *charset; 2794 2795 *p = '\0'; 2796 charset = strchr(ostype, ','); 2797 if (charset != NULL) 2798 *charset = '\0'; 2799 } 2800 2801 /* 1413 says don't do this -- but it's broken otherwise */ 2802 while (isascii(*++p) && isspace(*p)) 2803 continue; 2804 2805 /* p now points to the authenticated name -- copy carefully */ 2806 if (strncasecmp(ostype, "other", 5) == 0 && 2807 (ostype[5] == ' ' || ostype[5] == '\0')) 2808 { 2809 snprintf(hbuf, sizeof hbuf, "IDENT:"); 2810 cleanstrcpy(&hbuf[6], p, MAXNAME); 2811 } 2812 else 2813 cleanstrcpy(hbuf, p, MAXNAME); 2814 i = strlen(hbuf); 2815 snprintf(&hbuf[i], sizeof hbuf - i, "@%s", 2816 RealHostName == NULL ? "localhost" : RealHostName); 2817 goto postident; 2818 2819closeident: 2820 (void) close(s); 2821 clrevent(ev); 2822 2823noident: 2824 /* put back the original incoming port */ 2825 switch (RealHostAddr.sa.sa_family) 2826 { 2827# if NETINET 2828 case AF_INET: 2829 if (port > 0) 2830 RealHostAddr.sin.sin_port = port; 2831 break; 2832# endif /* NETINET */ 2833 2834# if NETINET6 2835 case AF_INET6: 2836 if (port > 0) 2837 RealHostAddr.sin6.sin6_port = port; 2838 break; 2839# endif /* NETINET6 */ 2840 } 2841 2842 if (RealHostName == NULL) 2843 { 2844 if (tTd(9, 1)) 2845 dprintf("getauthinfo: NULL\n"); 2846 return NULL; 2847 } 2848 snprintf(hbuf, sizeof hbuf, "%s", RealHostName); 2849 2850postident: 2851# if IP_SRCROUTE 2852# ifndef GET_IPOPT_DST 2853# define GET_IPOPT_DST(dst) (dst) 2854# endif /* ! GET_IPOPT_DST */ 2855 /* 2856 ** Extract IP source routing information. 2857 ** 2858 ** Format of output for a connection from site a through b 2859 ** through c to d: 2860 ** loose: @site-c@site-b:site-a 2861 ** strict: !@site-c@site-b:site-a 2862 ** 2863 ** o - pointer within ipopt_list structure. 2864 ** q - pointer within ls/ss rr route data 2865 ** p - pointer to hbuf 2866 */ 2867 2868 if (RealHostAddr.sa.sa_family == AF_INET) 2869 { 2870 SOCKOPT_LEN_T ipoptlen; 2871 int j; 2872 u_char *q; 2873 u_char *o; 2874 int l; 2875 struct IPOPTION ipopt; 2876 2877 ipoptlen = sizeof ipopt; 2878 if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 2879 (char *) &ipopt, &ipoptlen) < 0) 2880 goto noipsr; 2881 if (ipoptlen == 0) 2882 goto noipsr; 2883 o = (u_char *) ipopt.IP_LIST; 2884 while (o != NULL && o < (u_char *) &ipopt + ipoptlen) 2885 { 2886 switch (*o) 2887 { 2888 case IPOPT_EOL: 2889 o = NULL; 2890 break; 2891 2892 case IPOPT_NOP: 2893 o++; 2894 break; 2895 2896 case IPOPT_SSRR: 2897 case IPOPT_LSRR: 2898 /* 2899 ** Source routing. 2900 ** o[0] is the option type (loose/strict). 2901 ** o[1] is the length of this option, 2902 ** including option type and 2903 ** length. 2904 ** o[2] is the pointer into the route 2905 ** data. 2906 ** o[3] begins the route data. 2907 */ 2908 2909 p = &hbuf[strlen(hbuf)]; 2910 l = sizeof hbuf - (hbuf - p) - 6; 2911 snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s", 2912 *o == IPOPT_SSRR ? "!" : "", 2913 l > 240 ? 120 : l / 2, 2914 inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 2915 i = strlen(p); 2916 p += i; 2917 l -= strlen(p); 2918 2919 j = o[1] / sizeof(struct in_addr) - 1; 2920 2921 /* q skips length and router pointer to data */ 2922 q = &o[3]; 2923 for ( ; j >= 0; j--) 2924 { 2925 struct in_addr addr; 2926 2927 memcpy(&addr, q, sizeof(addr)); 2928 snprintf(p, SPACELEFT(hbuf, p), 2929 "%c%.*s", 2930 j != 0 ? '@' : ':', 2931 l > 240 ? 120 : 2932 j == 0 ? l : l / 2, 2933 inet_ntoa(addr)); 2934 i = strlen(p); 2935 p += i; 2936 l -= i + 1; 2937 q += sizeof(struct in_addr); 2938 } 2939 o += o[1]; 2940 break; 2941 2942 default: 2943 /* Skip over option */ 2944 o += o[1]; 2945 break; 2946 } 2947 } 2948 snprintf(p, SPACELEFT(hbuf, p), "]"); 2949 goto postipsr; 2950 } 2951 2952noipsr: 2953# endif /* IP_SRCROUTE */ 2954 if (RealHostName != NULL && RealHostName[0] != '[') 2955 { 2956 p = &hbuf[strlen(hbuf)]; 2957 (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 2958 anynet_ntoa(&RealHostAddr)); 2959 } 2960 if (*may_be_forged) 2961 { 2962 p = &hbuf[strlen(hbuf)]; 2963 (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)"); 2964 } 2965 2966# if IP_SRCROUTE 2967postipsr: 2968# endif /* IP_SRCROUTE */ 2969 if (tTd(9, 1)) 2970 dprintf("getauthinfo: %s\n", hbuf); 2971 2972 /* put back the original incoming port */ 2973 switch (RealHostAddr.sa.sa_family) 2974 { 2975# if NETINET 2976 case AF_INET: 2977 if (port > 0) 2978 RealHostAddr.sin.sin_port = port; 2979 break; 2980# endif /* NETINET */ 2981 2982# if NETINET6 2983 case AF_INET6: 2984 if (port > 0) 2985 RealHostAddr.sin6.sin6_port = port; 2986 break; 2987# endif /* NETINET6 */ 2988 } 2989 2990 return hbuf; 2991} 2992/* 2993** HOST_MAP_LOOKUP -- turn a hostname into canonical form 2994** 2995** Parameters: 2996** map -- a pointer to this map. 2997** name -- the (presumably unqualified) hostname. 2998** av -- unused -- for compatibility with other mapping 2999** functions. 3000** statp -- an exit status (out parameter) -- set to 3001** EX_TEMPFAIL if the name server is unavailable. 3002** 3003** Returns: 3004** The mapping, if found. 3005** NULL if no mapping found. 3006** 3007** Side Effects: 3008** Looks up the host specified in hbuf. If it is not 3009** the canonical name for that host, return the canonical 3010** name (unless MF_MATCHONLY is set, which will cause the 3011** status only to be returned). 3012*/ 3013 3014char * 3015host_map_lookup(map, name, av, statp) 3016 MAP *map; 3017 char *name; 3018 char **av; 3019 int *statp; 3020{ 3021 register struct hostent *hp; 3022# if NETINET 3023 struct in_addr in_addr; 3024# endif /* NETINET */ 3025# if NETINET6 3026 struct in6_addr in6_addr; 3027# endif /* NETINET6 */ 3028 char *cp, *ans = NULL; 3029 register STAB *s; 3030 char hbuf[MAXNAME + 1]; 3031 3032 /* 3033 ** See if we have already looked up this name. If so, just 3034 ** return it. 3035 */ 3036 3037 s = stab(name, ST_NAMECANON, ST_ENTER); 3038 if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 3039 { 3040 if (tTd(9, 1)) 3041 dprintf("host_map_lookup(%s) => CACHE %s\n", 3042 name, 3043 s->s_namecanon.nc_cname == NULL 3044 ? "NULL" 3045 : s->s_namecanon.nc_cname); 3046 errno = s->s_namecanon.nc_errno; 3047# if NAMED_BIND 3048 h_errno = s->s_namecanon.nc_herrno; 3049# endif /* NAMED_BIND */ 3050 *statp = s->s_namecanon.nc_stat; 3051 if (*statp == EX_TEMPFAIL) 3052 { 3053 CurEnv->e_status = "4.4.3"; 3054 message("851 %s: Name server timeout", 3055 shortenstring(name, 33)); 3056 } 3057 if (*statp != EX_OK) 3058 return NULL; 3059 if (s->s_namecanon.nc_cname == NULL) 3060 { 3061 syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", 3062 name, 3063 s->s_namecanon.nc_errno, 3064 s->s_namecanon.nc_herrno); 3065 return NULL; 3066 } 3067 if (bitset(MF_MATCHONLY, map->map_mflags)) 3068 cp = map_rewrite(map, name, strlen(name), NULL); 3069 else 3070 cp = map_rewrite(map, 3071 s->s_namecanon.nc_cname, 3072 strlen(s->s_namecanon.nc_cname), 3073 av); 3074 return cp; 3075 } 3076 3077 /* 3078 ** If we are running without a regular network connection (usually 3079 ** dial-on-demand) and we are just queueing, we want to avoid DNS 3080 ** lookups because those could try to connect to a server. 3081 */ 3082 3083 if (CurEnv->e_sendmode == SM_DEFER && 3084 bitset(MF_DEFER, map->map_mflags)) 3085 { 3086 if (tTd(9, 1)) 3087 dprintf("host_map_lookup(%s) => DEFERRED\n", name); 3088 *statp = EX_TEMPFAIL; 3089 return NULL; 3090 } 3091 3092 /* 3093 ** If first character is a bracket, then it is an address 3094 ** lookup. Address is copied into a temporary buffer to 3095 ** strip the brackets and to preserve name if address is 3096 ** unknown. 3097 */ 3098 3099 if (tTd(9, 1)) 3100 dprintf("host_map_lookup(%s) => ", name); 3101 if (*name != '[') 3102 { 3103 snprintf(hbuf, sizeof hbuf, "%s", name); 3104 if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX)) 3105 ans = hbuf; 3106 } 3107 else 3108 { 3109 if ((cp = strchr(name, ']')) == NULL) 3110 { 3111 if (tTd(9, 1)) 3112 dprintf("FAILED\n"); 3113 return NULL; 3114 } 3115 *cp = '\0'; 3116 3117 hp = NULL; 3118# if NETINET 3119 if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 3120 hp = sm_gethostbyaddr((char *)&in_addr, 3121 INADDRSZ, AF_INET); 3122# endif /* NETINET */ 3123# if NETINET6 3124 if (hp == NULL && 3125 inet_pton(AF_INET6, &name[1], &in6_addr) == 1) 3126 hp = sm_gethostbyaddr((char *)&in6_addr, 3127 IN6ADDRSZ, AF_INET6); 3128# endif /* NETINET6 */ 3129 *cp = ']'; 3130 3131 if (hp != NULL) 3132 { 3133 /* found a match -- copy out */ 3134 ans = denlstring((char *) hp->h_name, TRUE, TRUE); 3135# if _FFR_FREEHOSTENT && NETINET6 3136 freehostent(hp); 3137 hp = NULL; 3138# endif /* _FFR_FREEHOSTENT && NETINET6 */ 3139 } 3140 } 3141 3142 s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 3143 3144 /* Found an answer */ 3145 if (ans != NULL) 3146 { 3147 s->s_namecanon.nc_stat = *statp = EX_OK; 3148 s->s_namecanon.nc_cname = newstr(ans); 3149 if (bitset(MF_MATCHONLY, map->map_mflags)) 3150 cp = map_rewrite(map, name, strlen(name), NULL); 3151 else 3152 cp = map_rewrite(map, ans, strlen(ans), av); 3153 if (tTd(9, 1)) 3154 dprintf("FOUND %s\n", ans); 3155 return cp; 3156 } 3157 3158 3159 /* No match found */ 3160 s->s_namecanon.nc_errno = errno; 3161# if NAMED_BIND 3162 s->s_namecanon.nc_herrno = h_errno; 3163 if (tTd(9, 1)) 3164 dprintf("FAIL (%d)\n", h_errno); 3165 switch (h_errno) 3166 { 3167 case TRY_AGAIN: 3168 if (UseNameServer) 3169 { 3170 CurEnv->e_status = "4.4.3"; 3171 message("851 %s: Name server timeout", 3172 shortenstring(name, 33)); 3173 } 3174 *statp = EX_TEMPFAIL; 3175 break; 3176 3177 case HOST_NOT_FOUND: 3178 case NO_DATA: 3179 *statp = EX_NOHOST; 3180 break; 3181 3182 case NO_RECOVERY: 3183 *statp = EX_SOFTWARE; 3184 break; 3185 3186 default: 3187 *statp = EX_UNAVAILABLE; 3188 break; 3189 } 3190# else /* NAMED_BIND */ 3191 if (tTd(9, 1)) 3192 dprintf("FAIL\n"); 3193 *statp = EX_NOHOST; 3194# endif /* NAMED_BIND */ 3195 s->s_namecanon.nc_stat = *statp; 3196 return NULL; 3197} 3198#else /* DAEMON */ 3199/* code for systems without sophisticated networking */ 3200 3201/* 3202** MYHOSTNAME -- stub version for case of no daemon code. 3203** 3204** Can't convert to upper case here because might be a UUCP name. 3205** 3206** Mark, you can change this to be anything you want...... 3207*/ 3208 3209char ** 3210myhostname(hostbuf, size) 3211 char hostbuf[]; 3212 int size; 3213{ 3214 register FILE *f; 3215 3216 hostbuf[0] = '\0'; 3217 f = fopen("/usr/include/whoami", "r"); 3218 if (f != NULL) 3219 { 3220 (void) fgets(hostbuf, size, f); 3221 fixcrlf(hostbuf, TRUE); 3222 (void) fclose(f); 3223 } 3224 return NULL; 3225} 3226/* 3227** GETAUTHINFO -- get the real host name associated with a file descriptor 3228** 3229** Parameters: 3230** fd -- the descriptor 3231** may_be_forged -- an outage that is set to TRUE if the 3232** forward lookup of RealHostName does not match 3233** RealHostAddr; set to FALSE if they do match. 3234** 3235** Returns: 3236** The host name associated with this descriptor, if it can 3237** be determined. 3238** NULL otherwise. 3239** 3240** Side Effects: 3241** none 3242*/ 3243 3244char * 3245getauthinfo(fd, may_be_forged) 3246 int fd; 3247 bool *may_be_forged; 3248{ 3249 *may_be_forged = FALSE; 3250 return NULL; 3251} 3252/* 3253** HOST_MAP_LOOKUP -- turn a hostname into canonical form 3254** 3255** Parameters: 3256** map -- a pointer to the database map. 3257** name -- a buffer containing a hostname. 3258** avp -- a pointer to a (cf file defined) argument vector. 3259** statp -- an exit status (out parameter). 3260** 3261** Returns: 3262** mapped host name 3263** FALSE otherwise. 3264** 3265** Side Effects: 3266** Looks up the host specified in name. If it is not 3267** the canonical name for that host, replace it with 3268** the canonical name. If the name is unknown, or it 3269** is already the canonical name, leave it unchanged. 3270*/ 3271 3272/*ARGSUSED*/ 3273char * 3274host_map_lookup(map, name, avp, statp) 3275 MAP *map; 3276 char *name; 3277 char **avp; 3278 char *statp; 3279{ 3280 register struct hostent *hp = NULL; 3281 char *cp; 3282 3283 hp = sm_gethostbyname(name, InetMode); 3284 if (hp == NULL && InetMode != AF_INET) 3285 hp = sm_gethostbyname(name, AF_INET); 3286 if (hp == NULL) 3287 { 3288# if NAMED_BIND 3289 if (tTd(9, 1)) 3290 dprintf("FAIL (%d)\n", h_errno); 3291 switch (h_errno) 3292 { 3293 case TRY_AGAIN: 3294 if (UseNameServer) 3295 { 3296 CurEnv->e_status = "4.4.3"; 3297 message("851 %s: Name server timeout", 3298 shortenstring(name, 33)); 3299 } 3300 *statp = EX_TEMPFAIL; 3301 break; 3302 3303 case HOST_NOT_FOUND: 3304 case NO_DATA: 3305 *statp = EX_NOHOST; 3306 break; 3307 3308 case NO_RECOVERY: 3309 *statp = EX_SOFTWARE; 3310 break; 3311 3312 default: 3313 *statp = EX_UNAVAILABLE; 3314 break; 3315 } 3316#else /* NAMED_BIND */ 3317 *statp = EX_NOHOST; 3318#endif /* NAMED_BIND */ 3319 return NULL; 3320 } 3321 if (bitset(MF_MATCHONLY, map->map_mflags)) 3322 cp = map_rewrite(map, name, strlen(name), NULL); 3323 else 3324 cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp); 3325# if _FFR_FREEHOSTENT && NETINET6 3326 freehostent(hp); 3327# endif /* _FFR_FREEHOSTENT && NETINET6 */ 3328 return cp; 3329} 3330 3331#endif /* DAEMON */ 3332/* 3333** HOST_MAP_INIT -- initialize host class structures 3334*/ 3335 3336bool 3337host_map_init(map, args) 3338 MAP *map; 3339 char *args; 3340{ 3341 register char *p = args; 3342 3343 for (;;) 3344 { 3345 while (isascii(*p) && isspace(*p)) 3346 p++; 3347 if (*p != '-') 3348 break; 3349 switch (*++p) 3350 { 3351 case 'a': 3352 map->map_app = ++p; 3353 break; 3354 3355 case 'T': 3356 map->map_tapp = ++p; 3357 break; 3358 3359 case 'm': 3360 map->map_mflags |= MF_MATCHONLY; 3361 break; 3362 3363 case 't': 3364 map->map_mflags |= MF_NODEFER; 3365 break; 3366 3367 case 'S': /* only for consistency */ 3368 map->map_spacesub = *++p; 3369 break; 3370 3371 case 'D': 3372 map->map_mflags |= MF_DEFER; 3373 break; 3374 } 3375 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 3376 p++; 3377 if (*p != '\0') 3378 *p++ = '\0'; 3379 } 3380 if (map->map_app != NULL) 3381 map->map_app = newstr(map->map_app); 3382 if (map->map_tapp != NULL) 3383 map->map_tapp = newstr(map->map_tapp); 3384 return TRUE; 3385} 3386 3387#if NETINET6 3388/* 3389** ANYNET_NTOP -- convert an IPv6 network address to printable form. 3390** 3391** Parameters: 3392** s6a -- a pointer to an in6_addr structure. 3393** dst -- buffer to store result in 3394** dst_len -- size of dst buffer 3395** 3396** Returns: 3397** A printable version of that structure. 3398*/ 3399char * 3400anynet_ntop(s6a, dst, dst_len) 3401 struct in6_addr *s6a; 3402 char *dst; 3403 size_t dst_len; 3404{ 3405 register char *ap; 3406 3407 if (IN6_IS_ADDR_V4MAPPED(s6a)) 3408 ap = (char *) inet_ntop(AF_INET, 3409 &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 3410 dst, dst_len); 3411 else 3412 ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 3413 return ap; 3414} 3415#endif /* NETINET6 */ 3416/* 3417** ANYNET_NTOA -- convert a network address to printable form. 3418** 3419** Parameters: 3420** sap -- a pointer to a sockaddr structure. 3421** 3422** Returns: 3423** A printable version of that sockaddr. 3424*/ 3425 3426#ifdef USE_SOCK_STREAM 3427 3428# if NETLINK 3429# include <net/if_dl.h> 3430# endif /* NETLINK */ 3431 3432char * 3433anynet_ntoa(sap) 3434 register SOCKADDR *sap; 3435{ 3436 register char *bp; 3437 register char *ap; 3438 int l; 3439 static char buf[100]; 3440 3441 /* check for null/zero family */ 3442 if (sap == NULL) 3443 return "NULLADDR"; 3444 if (sap->sa.sa_family == 0) 3445 return "0"; 3446 3447 switch (sap->sa.sa_family) 3448 { 3449# if NETUNIX 3450 case AF_UNIX: 3451 if (sap->sunix.sun_path[0] != '\0') 3452 snprintf(buf, sizeof buf, "[UNIX: %.64s]", 3453 sap->sunix.sun_path); 3454 else 3455 snprintf(buf, sizeof buf, "[UNIX: localhost]"); 3456 return buf; 3457# endif /* NETUNIX */ 3458 3459# if NETINET 3460 case AF_INET: 3461 return (char *) inet_ntoa(sap->sin.sin_addr); 3462# endif /* NETINET */ 3463 3464# if NETINET6 3465 case AF_INET6: 3466 ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf); 3467 if (ap != NULL) 3468 return ap; 3469 break; 3470# endif /* NETINET6 */ 3471 3472# if NETLINK 3473 case AF_LINK: 3474 snprintf(buf, sizeof buf, "[LINK: %s]", 3475 link_ntoa((struct sockaddr_dl *) &sap->sa)); 3476 return buf; 3477# endif /* NETLINK */ 3478 default: 3479 /* this case is needed when nothing is #defined */ 3480 /* in order to keep the switch syntactically correct */ 3481 break; 3482 } 3483 3484 /* unknown family -- just dump bytes */ 3485 (void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family); 3486 bp = &buf[strlen(buf)]; 3487 ap = sap->sa.sa_data; 3488 for (l = sizeof sap->sa.sa_data; --l >= 0; ) 3489 { 3490 (void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377); 3491 bp += 3; 3492 } 3493 *--bp = '\0'; 3494 return buf; 3495} 3496/* 3497** HOSTNAMEBYANYADDR -- return name of host based on address 3498** 3499** Parameters: 3500** sap -- SOCKADDR pointer 3501** 3502** Returns: 3503** text representation of host name. 3504** 3505** Side Effects: 3506** none. 3507*/ 3508 3509char * 3510hostnamebyanyaddr(sap) 3511 register SOCKADDR *sap; 3512{ 3513 register struct hostent *hp; 3514# if NAMED_BIND 3515 int saveretry; 3516# endif /* NAMED_BIND */ 3517# if NETINET6 3518 struct in6_addr in6_addr; 3519# endif /* NETINET6 */ 3520 3521# if NAMED_BIND 3522 /* shorten name server timeout to avoid higher level timeouts */ 3523 saveretry = _res.retry; 3524 if (_res.retry * _res.retrans > 20) 3525 _res.retry = 20 / _res.retrans; 3526# endif /* NAMED_BIND */ 3527 3528 switch (sap->sa.sa_family) 3529 { 3530# if NETINET 3531 case AF_INET: 3532 hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 3533 INADDRSZ, 3534 AF_INET); 3535 break; 3536# endif /* NETINET */ 3537 3538# if NETINET6 3539 case AF_INET6: 3540 hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 3541 IN6ADDRSZ, 3542 AF_INET6); 3543 break; 3544# endif /* NETINET6 */ 3545 3546# if NETISO 3547 case AF_ISO: 3548 hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 3549 sizeof sap->siso.siso_addr, 3550 AF_ISO); 3551 break; 3552# endif /* NETISO */ 3553 3554# if NETUNIX 3555 case AF_UNIX: 3556 hp = NULL; 3557 break; 3558# endif /* NETUNIX */ 3559 3560 default: 3561 hp = sm_gethostbyaddr(sap->sa.sa_data, 3562 sizeof sap->sa.sa_data, 3563 sap->sa.sa_family); 3564 break; 3565 } 3566 3567# if NAMED_BIND 3568 _res.retry = saveretry; 3569# endif /* NAMED_BIND */ 3570 3571# if NETINET || NETINET6 3572 if (hp != NULL && hp->h_name[0] != '[' 3573# if NETINET6 3574 && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 3575# endif /* NETINET6 */ 3576# if NETINET 3577 && inet_addr(hp->h_name) == INADDR_NONE 3578# endif /* NETINET */ 3579 ) 3580 { 3581 char *name; 3582 3583 name = denlstring((char *) hp->h_name, TRUE, TRUE); 3584 3585# if _FFR_FREEHOSTENT && NETINET6 3586 if (name == hp->h_name) 3587 { 3588 static char n[MAXNAME + 1]; 3589 3590 /* Copy the string, hp->h_name is about to disappear */ 3591 strlcpy(n, name, sizeof n); 3592 name = n; 3593 } 3594 3595 freehostent(hp); 3596# endif /* _FFR_FREEHOSTENT && NETINET6 */ 3597 return name; 3598 } 3599# endif /* NETINET || NETINET6 */ 3600 3601# if _FFR_FREEHOSTENT && NETINET6 3602 if (hp != NULL) 3603 { 3604 freehostent(hp); 3605 hp = NULL; 3606 } 3607# endif /* _FFR_FREEHOSTENT && NETINET6 */ 3608 3609# if NETUNIX 3610 if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 3611 return "localhost"; 3612# endif /* NETUNIX */ 3613 { 3614 static char buf[203]; 3615 3616 (void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap)); 3617 return buf; 3618 } 3619} 3620#endif /* USE_SOCK_STREAM */ 3621