daemon.c revision 80785
138032Speter/* 273188Sgshapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1538032Speter 1664562Sgshapiro 1738032Speter#ifndef lint 1864562Sgshapiro# ifdef DAEMON 1980785Sgshapirostatic char id[] = "@(#)$Id: daemon.c,v 8.401.4.68 2001/07/20 18:45:58 gshapiro Exp $ (with daemon mode)"; 2064562Sgshapiro# else /* DAEMON */ 2180785Sgshapirostatic char id[] = "@(#)$Id: daemon.c,v 8.401.4.68 2001/07/20 18:45:58 gshapiro Exp $ (without daemon mode)"; 2264562Sgshapiro# endif /* DAEMON */ 2364562Sgshapiro#endif /* ! lint */ 2438032Speter 2538032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 2638032Speter# define USE_SOCK_STREAM 1 2764562Sgshapiro#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */ 2838032Speter 2938032Speter#if DAEMON || defined(USE_SOCK_STREAM) 3064562Sgshapiro# if NETINET || NETINET6 3164562Sgshapiro# include <arpa/inet.h> 3264562Sgshapiro# endif /* NETINET || NETINET6 */ 3338032Speter# if NAMED_BIND 3438032Speter# ifndef NO_DATA 3538032Speter# define NO_DATA NO_ADDRESS 3664562Sgshapiro# endif /* ! NO_DATA */ 3764562Sgshapiro# endif /* NAMED_BIND */ 3864562Sgshapiro#endif /* DAEMON || defined(USE_SOCK_STREAM) */ 3938032Speter 4038032Speter#if DAEMON 4138032Speter 4266494Sgshapiro# if STARTTLS 4366494Sgshapiro# include <openssl/rand.h> 4466494Sgshapiro# endif /* STARTTLS */ 4566494Sgshapiro 4638032Speter# include <sys/time.h> 4738032Speter 4864562Sgshapiro# if IP_SRCROUTE && NETINET 4938032Speter# include <netinet/in_systm.h> 5038032Speter# include <netinet/ip.h> 5164562Sgshapiro# if HAS_IN_H 5264562Sgshapiro# include <netinet/in.h> 5364562Sgshapiro# ifndef IPOPTION 5464562Sgshapiro# define IPOPTION ip_opts 5564562Sgshapiro# define IP_LIST ip_opts 5664562Sgshapiro# define IP_DST ip_dst 5764562Sgshapiro# endif /* ! IPOPTION */ 5864562Sgshapiro# else /* HAS_IN_H */ 5964562Sgshapiro# include <netinet/ip_var.h> 6064562Sgshapiro# ifndef IPOPTION 6164562Sgshapiro# define IPOPTION ipoption 6264562Sgshapiro# define IP_LIST ipopt_list 6364562Sgshapiro# define IP_DST ipopt_dst 6464562Sgshapiro# endif /* ! IPOPTION */ 6564562Sgshapiro# endif /* HAS_IN_H */ 6664562Sgshapiro# endif /* IP_SRCROUTE && NETINET */ 6738032Speter 6864562Sgshapiro/* structure to describe a daemon */ 6964562Sgshapirostruct daemon 7064562Sgshapiro{ 7164562Sgshapiro int d_socket; /* fd for socket */ 7264562Sgshapiro SOCKADDR d_addr; /* socket for incoming */ 7364562Sgshapiro u_short d_port; /* port number */ 7464562Sgshapiro int d_listenqueue; /* size of listen queue */ 7564562Sgshapiro int d_tcprcvbufsize; /* size of TCP receive buffer */ 7664562Sgshapiro int d_tcpsndbufsize; /* size of TCP send buffer */ 7764562Sgshapiro time_t d_refuse_connections_until; 7864562Sgshapiro bool d_firsttime; 7964562Sgshapiro int d_socksize; 8064562Sgshapiro BITMAP256 d_flags; /* flags; see sendmail.h */ 8164562Sgshapiro char *d_mflags; /* flags for use in macro */ 8264562Sgshapiro char *d_name; /* user-supplied name */ 8364562Sgshapiro}; 8464562Sgshapiro 8564562Sgshapirotypedef struct daemon DAEMON_T; 8664562Sgshapiro 8764562Sgshapirostatic void connecttimeout __P((void)); 8864562Sgshapirostatic int opendaemonsocket __P((struct daemon *, bool)); 8964562Sgshapirostatic u_short setupdaemon __P((SOCKADDR *)); 9077349Sgshapirostatic SIGFUNC_DECL sighup __P((int)); 9177349Sgshapirostatic void restart_daemon __P((void)); 9264562Sgshapiro 9338032Speter/* 9438032Speter** DAEMON.C -- routines to use when running as a daemon. 9538032Speter** 9638032Speter** This entire file is highly dependent on the 4.2 BSD 9738032Speter** interprocess communication primitives. No attempt has 9838032Speter** been made to make this file portable to Version 7, 9938032Speter** Version 6, MPX files, etc. If you should try such a 10038032Speter** thing yourself, I recommend chucking the entire file 10138032Speter** and starting from scratch. Basic semantics are: 10238032Speter** 10338032Speter** getrequests(e) 10438032Speter** Opens a port and initiates a connection. 10538032Speter** Returns in a child. Must set InChannel and 10638032Speter** OutChannel appropriately. 10738032Speter** clrdaemon() 10838032Speter** Close any open files associated with getting 10938032Speter** the connection; this is used when running the queue, 11038032Speter** etc., to avoid having extra file descriptors during 11138032Speter** the queue run and to avoid confusing the network 11238032Speter** code (if it cares). 11338032Speter** makeconnection(host, port, outfile, infile, e) 11438032Speter** Make a connection to the named host on the given 11538032Speter** port. Set *outfile and *infile to the files 11638032Speter** appropriate for communication. Returns zero on 11738032Speter** success, else an exit status describing the 11838032Speter** error. 11938032Speter** host_map_lookup(map, hbuf, avp, pstat) 12038032Speter** Convert the entry in hbuf into a canonical form. 12138032Speter*/ 12264562Sgshapiro 12364562Sgshapirostatic DAEMON_T Daemons[MAXDAEMONS]; 12464562Sgshapirostatic int ndaemons = 0; /* actual number of daemons */ 12564562Sgshapiro 12664562Sgshapiro/* options for client */ 12764562Sgshapirostatic int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 12864562Sgshapirostatic int TcpSndBufferSize = 0; /* size of TCP send buffer */ 12964562Sgshapiro 13038032Speter/* 13138032Speter** GETREQUESTS -- open mail IPC port and get requests. 13238032Speter** 13338032Speter** Parameters: 13438032Speter** e -- the current envelope. 13538032Speter** 13638032Speter** Returns: 13764562Sgshapiro** pointer to flags. 13838032Speter** 13938032Speter** Side Effects: 14038032Speter** Waits until some interesting activity occurs. When 14138032Speter** it does, a child is created to process it, and the 14238032Speter** parent waits for completion. Return from this 14338032Speter** routine is always in the child. The file pointers 14438032Speter** "InChannel" and "OutChannel" should be set to point 14538032Speter** to the communication channel. 14638032Speter*/ 14738032Speter 14864562SgshapiroBITMAP256 * 14938032Spetergetrequests(e) 15038032Speter ENVELOPE *e; 15138032Speter{ 15238032Speter int t; 15364562Sgshapiro time_t last_disk_space_check = 0; 15464562Sgshapiro int idx, curdaemon = -1; 15564562Sgshapiro int i, olddaemon = 0; 15664562Sgshapiro# if XDEBUG 15738032Speter bool j_has_dot; 15864562Sgshapiro# endif /* XDEBUG */ 15942575Speter char status[MAXLINE]; 16064562Sgshapiro SOCKADDR sa; 16164562Sgshapiro SOCKADDR_LEN_T len = sizeof sa; 16264562Sgshapiro# if NETUNIX 16342575Speter extern int ControlSocket; 16464562Sgshapiro# endif /* NETUNIX */ 16564562Sgshapiro extern ENVELOPE BlankEnvelope; 16638032Speter 16738032Speter 16864562Sgshapiro for (idx = 0; idx < ndaemons; idx++) 16938032Speter { 17064562Sgshapiro Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 17164562Sgshapiro Daemons[idx].d_firsttime = TRUE; 17264562Sgshapiro Daemons[idx].d_refuse_connections_until = (time_t) 0; 17338032Speter } 17471345Sgshapiro 17538032Speter /* 17638032Speter ** Try to actually open the connection. 17738032Speter */ 17838032Speter 17938032Speter if (tTd(15, 1)) 18064562Sgshapiro { 18164562Sgshapiro for (idx = 0; idx < ndaemons; idx++) 18271345Sgshapiro { 18364562Sgshapiro dprintf("getrequests: daemon %s: port %d\n", 18464562Sgshapiro Daemons[idx].d_name, 18564562Sgshapiro ntohs(Daemons[idx].d_port)); 18671345Sgshapiro } 18764562Sgshapiro } 18838032Speter 18938032Speter /* get a socket for the SMTP connection */ 19064562Sgshapiro for (idx = 0; idx < ndaemons; idx++) 19164562Sgshapiro Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], TRUE); 19238032Speter 19342575Speter if (opencontrolsocket() < 0) 19442575Speter sm_syslog(LOG_WARNING, NOQID, 19543730Speter "daemon could not open control socket %s: %s", 19643730Speter ControlSocketName, errstring(errno)); 19742575Speter 19838032Speter (void) setsignal(SIGCHLD, reapchild); 19977349Sgshapiro (void) setsignal(SIGHUP, sighup); 20038032Speter 20177349Sgshapiro /* workaround: can't seem to release the signal in the parent */ 20277349Sgshapiro (void) releasesignal(SIGHUP); 20377349Sgshapiro 20464562Sgshapiro /* write the pid to file */ 20564562Sgshapiro log_sendmail_pid(e); 20638032Speter 20764562Sgshapiro# if XDEBUG 20838032Speter { 20938032Speter char jbuf[MAXHOSTNAMELEN]; 21038032Speter 21138032Speter expand("\201j", jbuf, sizeof jbuf, e); 21238032Speter j_has_dot = strchr(jbuf, '.') != NULL; 21338032Speter } 21464562Sgshapiro# endif /* XDEBUG */ 21538032Speter 21642575Speter /* Add parent process as first item */ 21764562Sgshapiro proc_list_add(getpid(), "Sendmail daemon", PROC_DAEMON); 21842575Speter 21938032Speter if (tTd(15, 1)) 22064562Sgshapiro { 22164562Sgshapiro for (idx = 0; idx < ndaemons; idx++) 22264562Sgshapiro dprintf("getrequests: daemon %s: %d\n", 22364562Sgshapiro Daemons[idx].d_name, 22464562Sgshapiro Daemons[idx].d_socket); 22564562Sgshapiro } 22638032Speter 22738032Speter for (;;) 22838032Speter { 22938032Speter register pid_t pid; 23038032Speter auto SOCKADDR_LEN_T lotherend; 23142575Speter bool timedout = FALSE; 23242575Speter bool control = FALSE; 23364562Sgshapiro int save_errno; 23438032Speter int pipefd[2]; 23571345Sgshapiro time_t timenow; 23666494Sgshapiro# if STARTTLS 23766494Sgshapiro long seed; 23866494Sgshapiro# endif /* STARTTLS */ 23971345Sgshapiro extern bool refuseconnections __P((char *, ENVELOPE *, int)); 24038032Speter 24138032Speter /* see if we are rejecting connections */ 24238032Speter (void) blocksignal(SIGALRM); 24364562Sgshapiro 24477349Sgshapiro if (ShutdownRequest != NULL) 24577349Sgshapiro shutdown_daemon(); 24677349Sgshapiro else if (RestartRequest != NULL) 24777349Sgshapiro restart_daemon(); 24877349Sgshapiro 24971345Sgshapiro timenow = curtime(); 25071345Sgshapiro 25171345Sgshapiro /* 25271345Sgshapiro ** Use ConnRateThrottle only if the 25371345Sgshapiro ** last pass was for a connection 25471345Sgshapiro */ 25571345Sgshapiro 25671345Sgshapiro if (ConnRateThrottle > 0 && curdaemon >= 0) 25771345Sgshapiro { 25871345Sgshapiro static int conncnt = 0; 25971345Sgshapiro static time_t lastconn = 0; 26071345Sgshapiro 26171345Sgshapiro if (timenow != lastconn) 26271345Sgshapiro { 26371345Sgshapiro lastconn = timenow; 26471345Sgshapiro conncnt = 1; 26571345Sgshapiro } 26671345Sgshapiro else if (++conncnt > ConnRateThrottle) 26771345Sgshapiro { 26871345Sgshapiro /* sleep to flatten out connection load */ 26971345Sgshapiro sm_setproctitle(TRUE, e, 27071345Sgshapiro "deferring connections: %d per second", 27171345Sgshapiro ConnRateThrottle); 27271345Sgshapiro if (LogLevel >= 9) 27371345Sgshapiro sm_syslog(LOG_INFO, NOQID, 27471345Sgshapiro "deferring connections: %d per second", 27571345Sgshapiro ConnRateThrottle); 27671345Sgshapiro (void) sleep(1); 27771345Sgshapiro } 27871345Sgshapiro } 27971345Sgshapiro 28064562Sgshapiro for (idx = 0; idx < ndaemons; idx++) 28138032Speter { 28271345Sgshapiro if (timenow < Daemons[idx].d_refuse_connections_until) 28364562Sgshapiro continue; 28464562Sgshapiro if (refuseconnections(Daemons[idx].d_name, e, idx)) 28538032Speter { 28664562Sgshapiro if (Daemons[idx].d_socket >= 0) 28742575Speter { 28871345Sgshapiro /* close socket so peer fails quickly */ 28971345Sgshapiro (void) close(Daemons[idx].d_socket); 29071345Sgshapiro Daemons[idx].d_socket = -1; 29142575Speter } 29242575Speter 29342575Speter /* refuse connections for next 15 seconds */ 29471345Sgshapiro Daemons[idx].d_refuse_connections_until = timenow + 15; 29538032Speter } 29664562Sgshapiro else if (Daemons[idx].d_socket < 0 || 29764562Sgshapiro Daemons[idx].d_firsttime) 29842575Speter { 29971345Sgshapiro if (!Daemons[idx].d_firsttime && LogLevel >= 9) 30071345Sgshapiro sm_syslog(LOG_INFO, NOQID, 30171345Sgshapiro "accepting connections again for daemon %s", 30271345Sgshapiro Daemons[idx].d_name); 30364562Sgshapiro 30471345Sgshapiro /* arrange to (re)open the socket if needed */ 30571345Sgshapiro (void) opendaemonsocket(&Daemons[idx], FALSE); 30671345Sgshapiro Daemons[idx].d_firsttime = FALSE; 30742575Speter } 30838032Speter } 30938032Speter 31077349Sgshapiro /* May have been sleeping above, check again */ 31177349Sgshapiro if (ShutdownRequest != NULL) 31277349Sgshapiro shutdown_daemon(); 31377349Sgshapiro else if (RestartRequest != NULL) 31477349Sgshapiro restart_daemon(); 31577349Sgshapiro 31671345Sgshapiro if (timenow >= last_disk_space_check) 31764562Sgshapiro { 31871345Sgshapiro bool logged = FALSE; 31971345Sgshapiro 32064562Sgshapiro if (!enoughdiskspace(MinBlocksFree + 1, FALSE)) 32164562Sgshapiro { 32271345Sgshapiro for (idx = 0; idx < ndaemons; idx++) 32364562Sgshapiro { 32471345Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 32571345Sgshapiro { 32671345Sgshapiro /* log only if not logged before */ 32771345Sgshapiro if (!logged) 32871345Sgshapiro { 32971345Sgshapiro if (LogLevel >= 9) 33071345Sgshapiro sm_syslog(LOG_INFO, NOQID, 33171345Sgshapiro "rejecting new messages: min free: %ld", 33271345Sgshapiro MinBlocksFree); 33371345Sgshapiro logged = TRUE; 33471345Sgshapiro sm_setproctitle(TRUE, e, 33571345Sgshapiro "rejecting new messages: min free: %ld", 33671345Sgshapiro MinBlocksFree); 33771345Sgshapiro } 33871345Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 33971345Sgshapiro } 34064562Sgshapiro } 34164562Sgshapiro } 34271345Sgshapiro else 34364562Sgshapiro { 34471345Sgshapiro for (idx = 0; idx < ndaemons; idx++) 34571345Sgshapiro { 34671345Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 34771345Sgshapiro { 34871345Sgshapiro /* log only if not logged before */ 34971345Sgshapiro if (!logged) 35071345Sgshapiro { 35171345Sgshapiro if (LogLevel >= 9) 35271345Sgshapiro sm_syslog(LOG_INFO, NOQID, 35371345Sgshapiro "accepting new messages (again)"); 35471345Sgshapiro logged = TRUE; 35571345Sgshapiro } 35671345Sgshapiro 35771345Sgshapiro /* title will be set below */ 35871345Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 35971345Sgshapiro } 36071345Sgshapiro } 36164562Sgshapiro } 36264562Sgshapiro /* only check disk space once a minute */ 36371345Sgshapiro last_disk_space_check = timenow + 60; 36464562Sgshapiro } 36564562Sgshapiro 36664562Sgshapiro# if XDEBUG 36738032Speter /* check for disaster */ 36838032Speter { 36938032Speter char jbuf[MAXHOSTNAMELEN]; 37038032Speter 37138032Speter expand("\201j", jbuf, sizeof jbuf, e); 37238032Speter if (!wordinclass(jbuf, 'w')) 37338032Speter { 37438032Speter dumpstate("daemon lost $j"); 37538032Speter sm_syslog(LOG_ALERT, NOQID, 37664562Sgshapiro "daemon process doesn't have $j in $=w; see syslog"); 37738032Speter abort(); 37838032Speter } 37938032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 38038032Speter { 38138032Speter dumpstate("daemon $j lost dot"); 38238032Speter sm_syslog(LOG_ALERT, NOQID, 38364562Sgshapiro "daemon process $j lost dot; see syslog"); 38438032Speter abort(); 38538032Speter } 38638032Speter } 38764562Sgshapiro# endif /* XDEBUG */ 38838032Speter 38964562Sgshapiro# if 0 39038032Speter /* 39138032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 39238032Speter ** fix the SVr4 problem. But it seems to have gone away, 39338032Speter ** so is it worth doing this? 39438032Speter */ 39538032Speter 39642575Speter if (DaemonSocket >= 0 && 39742575Speter SetNonBlocking(DaemonSocket, FALSE) < 0) 39838032Speter log an error here; 39964562Sgshapiro# endif /* 0 */ 40038032Speter (void) releasesignal(SIGALRM); 40164562Sgshapiro 40238032Speter for (;;) 40338032Speter { 40471345Sgshapiro bool setproc = FALSE; 40542575Speter int highest = -1; 40638032Speter fd_set readfds; 40738032Speter struct timeval timeout; 40838032Speter 40977349Sgshapiro if (ShutdownRequest != NULL) 41077349Sgshapiro shutdown_daemon(); 41177349Sgshapiro else if (RestartRequest != NULL) 41277349Sgshapiro restart_daemon(); 41377349Sgshapiro 41438032Speter FD_ZERO(&readfds); 41542575Speter 41664562Sgshapiro for (idx = 0; idx < ndaemons; idx++) 41742575Speter { 41864562Sgshapiro /* wait for a connection */ 41964562Sgshapiro if (Daemons[idx].d_socket >= 0) 42064562Sgshapiro { 42171345Sgshapiro if (!setproc && 42271345Sgshapiro !bitnset(D_ETRNONLY, 42371345Sgshapiro Daemons[idx].d_flags)) 42464562Sgshapiro { 42564562Sgshapiro sm_setproctitle(TRUE, e, 42664562Sgshapiro "accepting connections"); 42771345Sgshapiro setproc = TRUE; 42864562Sgshapiro } 42964562Sgshapiro if (Daemons[idx].d_socket > highest) 43064562Sgshapiro highest = Daemons[idx].d_socket; 43164562Sgshapiro FD_SET((u_int)Daemons[idx].d_socket, &readfds); 43264562Sgshapiro } 43342575Speter } 43464562Sgshapiro 43564562Sgshapiro# if NETUNIX 43642575Speter if (ControlSocket >= 0) 43742575Speter { 43842575Speter if (ControlSocket > highest) 43942575Speter highest = ControlSocket; 44042575Speter FD_SET(ControlSocket, &readfds); 44142575Speter } 44264562Sgshapiro# endif /* NETUNIX */ 44364562Sgshapiro 44477349Sgshapiro timeout.tv_sec = 5; 44538032Speter timeout.tv_usec = 0; 44638032Speter 44742575Speter t = select(highest + 1, FDSET_CAST &readfds, 44864562Sgshapiro NULL, NULL, &timeout); 44942575Speter 45077349Sgshapiro /* Did someone signal while waiting? */ 45177349Sgshapiro if (ShutdownRequest != NULL) 45277349Sgshapiro shutdown_daemon(); 45377349Sgshapiro else if (RestartRequest != NULL) 45477349Sgshapiro restart_daemon(); 45571345Sgshapiro 45671345Sgshapiro 45777349Sgshapiro 45838032Speter if (DoQueueRun) 45938032Speter (void) runqueue(TRUE, FALSE); 46071345Sgshapiro 46171345Sgshapiro curdaemon = -1; 46242575Speter if (t <= 0) 46342575Speter { 46442575Speter timedout = TRUE; 46542575Speter break; 46642575Speter } 46738032Speter 46842575Speter control = FALSE; 46938032Speter errno = 0; 47064562Sgshapiro 47164562Sgshapiro /* look "round-robin" for an active socket */ 47264562Sgshapiro if ((idx = olddaemon + 1) >= ndaemons) 47364562Sgshapiro idx = 0; 47464562Sgshapiro for (i = 0; i < ndaemons; i++) 47542575Speter { 47664562Sgshapiro if (Daemons[idx].d_socket >= 0 && 47764562Sgshapiro FD_ISSET(Daemons[idx].d_socket, &readfds)) 47864562Sgshapiro { 47964562Sgshapiro lotherend = Daemons[idx].d_socksize; 48073188Sgshapiro memset(&RealHostAddr, '\0', 48173188Sgshapiro sizeof RealHostAddr); 48264562Sgshapiro t = accept(Daemons[idx].d_socket, 48364562Sgshapiro (struct sockaddr *)&RealHostAddr, 48464562Sgshapiro &lotherend); 48573188Sgshapiro 48673188Sgshapiro /* 48773188Sgshapiro ** If remote side closes before 48873188Sgshapiro ** accept() finishes, sockaddr 48973188Sgshapiro ** might not be fully filled in. 49073188Sgshapiro */ 49173188Sgshapiro 49273188Sgshapiro if (t >= 0 && 49373188Sgshapiro (lotherend == 0 || 49473188Sgshapiro# ifdef BSD4_4_SOCKADDR 49573188Sgshapiro RealHostAddr.sa.sa_len == 0 || 49673188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 49773188Sgshapiro RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) 49873188Sgshapiro { 49973188Sgshapiro (void) close(t); 50073188Sgshapiro t = -1; 50173188Sgshapiro errno = EINVAL; 50273188Sgshapiro } 50364562Sgshapiro olddaemon = curdaemon = idx; 50464562Sgshapiro break; 50564562Sgshapiro } 50664562Sgshapiro if (++idx >= ndaemons) 50764562Sgshapiro idx = 0; 50842575Speter } 50964562Sgshapiro# if NETUNIX 51064562Sgshapiro if (curdaemon == -1 && ControlSocket >= 0 && 51171345Sgshapiro FD_ISSET(ControlSocket, &readfds)) 51242575Speter { 51342575Speter struct sockaddr_un sa_un; 51442575Speter 51542575Speter lotherend = sizeof sa_un; 51673188Sgshapiro memset(&sa_un, '\0', sizeof sa_un); 51742575Speter t = accept(ControlSocket, 51842575Speter (struct sockaddr *)&sa_un, 51942575Speter &lotherend); 52073188Sgshapiro 52173188Sgshapiro /* 52273188Sgshapiro ** If remote side closes before 52373188Sgshapiro ** accept() finishes, sockaddr 52473188Sgshapiro ** might not be fully filled in. 52573188Sgshapiro */ 52673188Sgshapiro 52773188Sgshapiro if (t >= 0 && 52873188Sgshapiro (lotherend == 0 || 52973188Sgshapiro# ifdef BSD4_4_SOCKADDR 53073188Sgshapiro sa_un.sun_len == 0 || 53173188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 53273188Sgshapiro sa_un.sun_family != AF_UNIX)) 53373188Sgshapiro { 53473188Sgshapiro (void) close(t); 53573188Sgshapiro t = -1; 53673188Sgshapiro errno = EINVAL; 53773188Sgshapiro } 53873188Sgshapiro if (t >= 0) 53973188Sgshapiro control = TRUE; 54042575Speter } 54171345Sgshapiro# else /* NETUNIX */ 54271345Sgshapiro if (curdaemon == -1) 54371345Sgshapiro { 54471345Sgshapiro /* No daemon to service */ 54571345Sgshapiro continue; 54671345Sgshapiro } 54764562Sgshapiro# endif /* NETUNIX */ 54838032Speter if (t >= 0 || errno != EINTR) 54938032Speter break; 55038032Speter } 55142575Speter if (timedout) 55242575Speter { 55342575Speter timedout = FALSE; 55442575Speter continue; 55542575Speter } 55664562Sgshapiro save_errno = errno; 55771345Sgshapiro timenow = curtime(); 55838032Speter (void) blocksignal(SIGALRM); 55938032Speter if (t < 0) 56038032Speter { 56164562Sgshapiro errno = save_errno; 56238032Speter syserr("getrequests: accept"); 56338032Speter 56438032Speter /* arrange to re-open the socket next time around */ 56564562Sgshapiro (void) close(Daemons[curdaemon].d_socket); 56664562Sgshapiro Daemons[curdaemon].d_socket = -1; 56764562Sgshapiro# if SO_REUSEADDR_IS_BROKEN 56864562Sgshapiro /* 56964562Sgshapiro ** Give time for bound socket to be released. 57064562Sgshapiro ** This creates a denial-of-service if you can 57164562Sgshapiro ** force accept() to fail on affected systems. 57264562Sgshapiro */ 57364562Sgshapiro 57471345Sgshapiro Daemons[curdaemon].d_refuse_connections_until = timenow + 15; 57564562Sgshapiro# endif /* SO_REUSEADDR_IS_BROKEN */ 57638032Speter continue; 57738032Speter } 57838032Speter 57964562Sgshapiro if (!control) 58064562Sgshapiro { 58164562Sgshapiro /* set some daemon related macros */ 58264562Sgshapiro switch (Daemons[curdaemon].d_addr.sa.sa_family) 58364562Sgshapiro { 58464562Sgshapiro case AF_UNSPEC: 58564562Sgshapiro define(macid("{daemon_family}", NULL), 58664562Sgshapiro "unspec", &BlankEnvelope); 58764562Sgshapiro break; 58864562Sgshapiro# if NETINET 58964562Sgshapiro case AF_INET: 59064562Sgshapiro define(macid("{daemon_family}", NULL), 59164562Sgshapiro "inet", &BlankEnvelope); 59264562Sgshapiro break; 59364562Sgshapiro# endif /* NETINET */ 59464562Sgshapiro# if NETINET6 59564562Sgshapiro case AF_INET6: 59664562Sgshapiro define(macid("{daemon_family}", NULL), 59764562Sgshapiro "inet6", &BlankEnvelope); 59864562Sgshapiro break; 59964562Sgshapiro# endif /* NETINET6 */ 60064562Sgshapiro# if NETISO 60164562Sgshapiro case AF_ISO: 60264562Sgshapiro define(macid("{daemon_family}", NULL), 60364562Sgshapiro "iso", &BlankEnvelope); 60464562Sgshapiro break; 60564562Sgshapiro# endif /* NETISO */ 60664562Sgshapiro# if NETNS 60764562Sgshapiro case AF_NS: 60864562Sgshapiro define(macid("{daemon_family}", NULL), 60964562Sgshapiro "ns", &BlankEnvelope); 61064562Sgshapiro break; 61164562Sgshapiro# endif /* NETNS */ 61264562Sgshapiro# if NETX25 61364562Sgshapiro case AF_CCITT: 61464562Sgshapiro define(macid("{daemon_family}", NULL), 61564562Sgshapiro "x.25", &BlankEnvelope); 61664562Sgshapiro break; 61764562Sgshapiro# endif /* NETX25 */ 61864562Sgshapiro } 61964562Sgshapiro define(macid("{daemon_name}", NULL), 62064562Sgshapiro Daemons[curdaemon].d_name, &BlankEnvelope); 62164562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 62264562Sgshapiro define(macid("{daemon_flags}", NULL), 62364562Sgshapiro Daemons[curdaemon].d_mflags, 62464562Sgshapiro &BlankEnvelope); 62564562Sgshapiro else 62664562Sgshapiro define(macid("{daemon_flags}", NULL), 62764562Sgshapiro "", &BlankEnvelope); 62864562Sgshapiro } 62964562Sgshapiro 63038032Speter /* 63138032Speter ** Create a subprocess to process the mail. 63238032Speter */ 63338032Speter 63438032Speter if (tTd(15, 2)) 63564562Sgshapiro dprintf("getrequests: forking (fd = %d)\n", t); 63638032Speter 63738032Speter /* 63864562Sgshapiro ** advance state of PRNG 63964562Sgshapiro ** this is necessary because otherwise all child processes 64064562Sgshapiro ** will produce the same PRN sequence and hence the selection 64164562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 64264562Sgshapiro ** are not "really" random. 64364562Sgshapiro */ 64466494Sgshapiro# if STARTTLS 64566494Sgshapiro seed = get_random(); 64666494Sgshapiro RAND_seed((void *) &last_disk_space_check, 64766494Sgshapiro sizeof last_disk_space_check); 64866494Sgshapiro RAND_seed((void *) &timenow, sizeof timenow); 64966494Sgshapiro RAND_seed((void *) &seed, sizeof seed); 65066494Sgshapiro# else /* STARTTLS */ 65164562Sgshapiro (void) get_random(); 65266494Sgshapiro# endif /* STARTTLS */ 65364562Sgshapiro 65471345Sgshapiro#ifndef DEBUG_NO_FORK 65564562Sgshapiro /* 65638032Speter ** Create a pipe to keep the child from writing to the 65738032Speter ** socket until after the parent has closed it. Otherwise 65838032Speter ** the parent may hang if the child has closed it first. 65938032Speter */ 66038032Speter 66138032Speter if (pipe(pipefd) < 0) 66238032Speter pipefd[0] = pipefd[1] = -1; 66338032Speter 66464562Sgshapiro (void) blocksignal(SIGCHLD); 66538032Speter pid = fork(); 66638032Speter if (pid < 0) 66738032Speter { 66838032Speter syserr("daemon: cannot fork"); 66938032Speter if (pipefd[0] != -1) 67038032Speter { 67138032Speter (void) close(pipefd[0]); 67238032Speter (void) close(pipefd[1]); 67338032Speter } 67438032Speter (void) releasesignal(SIGCHLD); 67564562Sgshapiro (void) sleep(10); 67638032Speter (void) close(t); 67738032Speter continue; 67838032Speter } 67971345Sgshapiro#else /* ! DEBUG_NO_FORK */ 68071345Sgshapiro pid = 0; 68171345Sgshapiro#endif /* ! DEBUG_NO_FORK */ 68238032Speter 68338032Speter if (pid == 0) 68438032Speter { 68538032Speter char *p; 68664562Sgshapiro FILE *inchannel, *outchannel = NULL; 68738032Speter 68838032Speter /* 68938032Speter ** CHILD -- return to caller. 69038032Speter ** Collect verified idea of sending host. 69138032Speter ** Verify calling user id if possible here. 69238032Speter */ 69338032Speter 69477349Sgshapiro /* Reset global flags */ 69577349Sgshapiro RestartRequest = NULL; 69677349Sgshapiro ShutdownRequest = NULL; 69777349Sgshapiro PendingSignal = 0; 69877349Sgshapiro 69977349Sgshapiro (void) releasesignal(SIGALRM); 70077349Sgshapiro (void) releasesignal(SIGCHLD); 70177349Sgshapiro (void) setsignal(SIGCHLD, SIG_DFL); 70277349Sgshapiro (void) setsignal(SIGHUP, SIG_DFL); 70377349Sgshapiro (void) setsignal(SIGTERM, intsig); 70477349Sgshapiro 70564562Sgshapiro if (!control) 70664562Sgshapiro { 70764562Sgshapiro define(macid("{daemon_addr}", NULL), 70864562Sgshapiro newstr(anynet_ntoa(&Daemons[curdaemon].d_addr)), 70964562Sgshapiro &BlankEnvelope); 71064562Sgshapiro (void) snprintf(status, sizeof status, "%d", 71164562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 71264562Sgshapiro define(macid("{daemon_port}", NULL), 71364562Sgshapiro newstr(status), &BlankEnvelope); 71464562Sgshapiro } 71564562Sgshapiro 71664562Sgshapiro for (idx = 0; idx < ndaemons; idx++) 71764562Sgshapiro { 71864562Sgshapiro if (Daemons[idx].d_socket >= 0) 71964562Sgshapiro (void) close(Daemons[idx].d_socket); 72080785Sgshapiro Daemons[idx].d_socket = -1; 72164562Sgshapiro } 72242575Speter clrcontrol(); 72338032Speter 72464562Sgshapiro /* Avoid SMTP daemon actions if control command */ 72564562Sgshapiro if (control) 72664562Sgshapiro { 72764562Sgshapiro /* Add control socket process */ 72864562Sgshapiro proc_list_add(getpid(), "console socket child", 72964562Sgshapiro PROC_CONTROL_CHILD); 73064562Sgshapiro } 73164562Sgshapiro else 73264562Sgshapiro { 73364562Sgshapiro proc_list_clear(); 73442575Speter 73564562Sgshapiro /* Add parent process as first child item */ 73664562Sgshapiro proc_list_add(getpid(), "daemon child", 73764562Sgshapiro PROC_DAEMON_CHILD); 73838032Speter 73964562Sgshapiro /* don't schedule queue runs if ETRN */ 74064562Sgshapiro QueueIntvl = 0; 74138032Speter 74264562Sgshapiro sm_setproctitle(TRUE, e, "startup with %s", 74364562Sgshapiro anynet_ntoa(&RealHostAddr)); 74464562Sgshapiro } 74564562Sgshapiro 74671345Sgshapiro#ifndef DEBUG_NO_FORK 74738032Speter if (pipefd[0] != -1) 74838032Speter { 74938032Speter auto char c; 75038032Speter 75138032Speter /* 75238032Speter ** Wait for the parent to close the write end 75338032Speter ** of the pipe, which we will see as an EOF. 75438032Speter ** This guarantees that we won't write to the 75538032Speter ** socket until after the parent has closed 75638032Speter ** the pipe. 75738032Speter */ 75838032Speter 75938032Speter /* close the write end of the pipe */ 76038032Speter (void) close(pipefd[1]); 76138032Speter 76238032Speter /* we shouldn't be interrupted, but ... */ 76338032Speter while (read(pipefd[0], &c, 1) < 0 && 76438032Speter errno == EINTR) 76538032Speter continue; 76638032Speter (void) close(pipefd[0]); 76738032Speter } 76871345Sgshapiro#endif /* ! DEBUG_NO_FORK */ 76938032Speter 77064562Sgshapiro /* control socket processing */ 77164562Sgshapiro if (control) 77264562Sgshapiro { 77364562Sgshapiro control_command(t, e); 77464562Sgshapiro 77564562Sgshapiro /* NOTREACHED */ 77664562Sgshapiro exit(EX_SOFTWARE); 77764562Sgshapiro } 77864562Sgshapiro 77938032Speter /* determine host name */ 78038032Speter p = hostnamebyanyaddr(&RealHostAddr); 78138032Speter if (strlen(p) > (SIZE_T) MAXNAME) 78238032Speter p[MAXNAME] = '\0'; 78338032Speter RealHostName = newstr(p); 78464562Sgshapiro if (RealHostName[0] == '[') 78564562Sgshapiro { 78664562Sgshapiro /* TEMP, FAIL: which one? */ 78764562Sgshapiro define(macid("{client_resolve}", NULL), 78864562Sgshapiro (h_errno == TRY_AGAIN) ? "TEMP" : "FAIL", 78964562Sgshapiro &BlankEnvelope); 79064562Sgshapiro } 79164562Sgshapiro else 79264562Sgshapiro define(macid("{client_resolve}", NULL), "OK", 79364562Sgshapiro &BlankEnvelope); 79464562Sgshapiro sm_setproctitle(TRUE, e, "startup with %s", p); 79538032Speter 79638032Speter if ((inchannel = fdopen(t, "r")) == NULL || 79738032Speter (t = dup(t)) < 0 || 79838032Speter (outchannel = fdopen(t, "w")) == NULL) 79938032Speter { 80038032Speter syserr("cannot open SMTP server channel, fd=%d", t); 80142575Speter finis(FALSE, EX_OK); 80238032Speter } 80338032Speter 80438032Speter InChannel = inchannel; 80538032Speter OutChannel = outchannel; 80638032Speter DisConnected = FALSE; 80738032Speter 80864562Sgshapiro# ifdef XLA 80938032Speter if (!xla_host_ok(RealHostName)) 81038032Speter { 81164562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 81242575Speter finis(FALSE, EX_OK); 81338032Speter } 81464562Sgshapiro# endif /* XLA */ 81564562Sgshapiro /* find out name for interface of connection */ 81664562Sgshapiro if (getsockname(fileno(InChannel), &sa.sa, 81764562Sgshapiro &len) == 0) 81864562Sgshapiro { 81964562Sgshapiro p = hostnamebyanyaddr(&sa); 82064562Sgshapiro if (tTd(15, 9)) 82164562Sgshapiro dprintf("getreq: got name %s\n", p); 82264562Sgshapiro define(macid("{if_name}", NULL), 82364562Sgshapiro newstr(p), &BlankEnvelope); 82464562Sgshapiro 82564562Sgshapiro /* do this only if it is not the loopback */ 82664562Sgshapiro /* interface: how to figure out? XXX */ 82764562Sgshapiro if (!isloopback(sa)) 82864562Sgshapiro { 82964562Sgshapiro define(macid("{if_addr}", NULL), 83064562Sgshapiro newstr(anynet_ntoa(&sa)), 83164562Sgshapiro &BlankEnvelope); 83264562Sgshapiro p = xalloc(5); 83364562Sgshapiro snprintf(p, 4, "%d", sa.sa.sa_family); 83464562Sgshapiro define(macid("{if_family}", NULL), p, 83564562Sgshapiro &BlankEnvelope); 83664562Sgshapiro if (tTd(15, 7)) 83764562Sgshapiro dprintf("getreq: got addr %s and family %s\n", 83864562Sgshapiro macvalue(macid("{if_addr}", NULL), 83964562Sgshapiro &BlankEnvelope), 84064562Sgshapiro macvalue(macid("{if_addr}", NULL), 84164562Sgshapiro &BlankEnvelope)); 84264562Sgshapiro } 84364562Sgshapiro else 84464562Sgshapiro { 84564562Sgshapiro define(macid("{if_addr}", NULL), NULL, 84664562Sgshapiro &BlankEnvelope); 84764562Sgshapiro define(macid("{if_family}", NULL), NULL, 84864562Sgshapiro &BlankEnvelope); 84964562Sgshapiro } 85064562Sgshapiro } 85164562Sgshapiro else 85264562Sgshapiro { 85364562Sgshapiro if (tTd(15, 7)) 85464562Sgshapiro dprintf("getreq: getsockname failed\n"); 85564562Sgshapiro define(macid("{if_name}", NULL), NULL, 85664562Sgshapiro &BlankEnvelope); 85764562Sgshapiro define(macid("{if_addr}", NULL), NULL, 85864562Sgshapiro &BlankEnvelope); 85964562Sgshapiro define(macid("{if_family}", NULL), NULL, 86064562Sgshapiro &BlankEnvelope); 86164562Sgshapiro } 86238032Speter break; 86338032Speter } 86438032Speter 86538032Speter /* parent -- keep track of children */ 86664562Sgshapiro if (control) 86764562Sgshapiro { 86864562Sgshapiro snprintf(status, sizeof status, "control socket server child"); 86964562Sgshapiro proc_list_add(pid, status, PROC_CONTROL); 87064562Sgshapiro } 87164562Sgshapiro else 87264562Sgshapiro { 87364562Sgshapiro snprintf(status, sizeof status, 87464562Sgshapiro "SMTP server child for %s", 87564562Sgshapiro anynet_ntoa(&RealHostAddr)); 87664562Sgshapiro proc_list_add(pid, status, PROC_DAEMON); 87764562Sgshapiro } 87838032Speter (void) releasesignal(SIGCHLD); 87938032Speter 88038032Speter /* close the read end of the synchronization pipe */ 88138032Speter if (pipefd[0] != -1) 88264562Sgshapiro { 88338032Speter (void) close(pipefd[0]); 88464562Sgshapiro pipefd[0] = -1; 88564562Sgshapiro } 88638032Speter 88738032Speter /* close the port so that others will hang (for a while) */ 88838032Speter (void) close(t); 88938032Speter 89038032Speter /* release the child by closing the read end of the sync pipe */ 89138032Speter if (pipefd[1] != -1) 89264562Sgshapiro { 89338032Speter (void) close(pipefd[1]); 89464562Sgshapiro pipefd[1] = -1; 89564562Sgshapiro } 89638032Speter } 89764562Sgshapiro 89838032Speter if (tTd(15, 2)) 89964562Sgshapiro dprintf("getreq: returning\n"); 90064562Sgshapiro return &Daemons[curdaemon].d_flags; 90138032Speter} 90238032Speter/* 90364562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 90438032Speter** 90564562Sgshapiro** Deals with setting all appropriate options. 90638032Speter** 90738032Speter** Parameters: 90864562Sgshapiro** d -- the structure for the daemon to open. 90938032Speter** firsttime -- set if this is the initial open. 91038032Speter** 91138032Speter** Returns: 91238032Speter** Size in bytes of the daemon socket addr. 91338032Speter** 91438032Speter** Side Effects: 91538032Speter** Leaves DaemonSocket set to the open socket. 91638032Speter** Exits if the socket cannot be created. 91738032Speter*/ 91838032Speter 91964562Sgshapiro# define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 92038032Speter 92164562Sgshapirostatic int 92264562Sgshapiroopendaemonsocket(d, firsttime) 92364562Sgshapiro struct daemon *d; 92438032Speter bool firsttime; 92538032Speter{ 92638032Speter int on = 1; 92764562Sgshapiro int fdflags; 92864562Sgshapiro SOCKADDR_LEN_T socksize = 0; 92938032Speter int ntries = 0; 93064562Sgshapiro int save_errno; 93138032Speter 93238032Speter if (tTd(15, 2)) 93364562Sgshapiro dprintf("opendaemonsocket(%s)\n", d->d_name); 93438032Speter 93538032Speter do 93638032Speter { 93738032Speter if (ntries > 0) 93864562Sgshapiro (void) sleep(5); 93964562Sgshapiro if (firsttime || d->d_socket < 0) 94038032Speter { 94164562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 94264562Sgshapiro SOCK_STREAM, 0); 94364562Sgshapiro if (d->d_socket < 0) 94438032Speter { 94564562Sgshapiro save_errno = errno; 94664562Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", d->d_name); 94738032Speter severe: 94838032Speter if (LogLevel > 0) 94938032Speter sm_syslog(LOG_ALERT, NOQID, 95064562Sgshapiro "daemon %s: problem creating SMTP socket", d->d_name); 95164562Sgshapiro d->d_socket = -1; 95238032Speter continue; 95338032Speter } 95438032Speter 95538032Speter /* turn on network debugging? */ 95638032Speter if (tTd(15, 101)) 95764562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 95838032Speter SO_DEBUG, (char *)&on, 95938032Speter sizeof on); 96038032Speter 96164562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 96238032Speter SO_REUSEADDR, (char *)&on, sizeof on); 96364562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 96438032Speter SO_KEEPALIVE, (char *)&on, sizeof on); 96538032Speter 96664562Sgshapiro# ifdef SO_RCVBUF 96764562Sgshapiro if (d->d_tcprcvbufsize > 0) 96838032Speter { 96964562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 97038032Speter SO_RCVBUF, 97164562Sgshapiro (char *) &d->d_tcprcvbufsize, 97264562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 97364562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 97438032Speter } 97564562Sgshapiro# endif /* SO_RCVBUF */ 97664562Sgshapiro# ifdef SO_SNDBUF 97764562Sgshapiro if (d->d_tcpsndbufsize > 0) 97864562Sgshapiro { 97964562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 98064562Sgshapiro SO_SNDBUF, 98164562Sgshapiro (char *) &d->d_tcpsndbufsize, 98264562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 98364562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 98464562Sgshapiro } 98564562Sgshapiro# endif /* SO_SNDBUF */ 98638032Speter 98764562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 98864562Sgshapiro fcntl(d->d_socket, F_SETFD, 98964562Sgshapiro fdflags | FD_CLOEXEC) == -1) 99038032Speter { 99164562Sgshapiro save_errno = errno; 99264562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 99364562Sgshapiro d->d_name, 99464562Sgshapiro fdflags == -1 ? "get" : "set", 99564562Sgshapiro errstring(save_errno)); 99664562Sgshapiro (void) close(d->d_socket); 99764562Sgshapiro goto severe; 99864562Sgshapiro } 99964562Sgshapiro 100064562Sgshapiro switch (d->d_addr.sa.sa_family) 100164562Sgshapiro { 100238032Speter# if NETINET 100338032Speter case AF_INET: 100464562Sgshapiro socksize = sizeof d->d_addr.sin; 100538032Speter break; 100664562Sgshapiro# endif /* NETINET */ 100738032Speter 100864562Sgshapiro# if NETINET6 100964562Sgshapiro case AF_INET6: 101064562Sgshapiro socksize = sizeof d->d_addr.sin6; 101164562Sgshapiro break; 101264562Sgshapiro# endif /* NETINET6 */ 101364562Sgshapiro 101438032Speter# if NETISO 101538032Speter case AF_ISO: 101664562Sgshapiro socksize = sizeof d->d_addr.siso; 101738032Speter break; 101864562Sgshapiro# endif /* NETISO */ 101938032Speter 102038032Speter default: 102164562Sgshapiro socksize = sizeof d->d_addr; 102238032Speter break; 102338032Speter } 102438032Speter 102564562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 102638032Speter { 102738032Speter /* probably another daemon already */ 102864562Sgshapiro save_errno = errno; 102964562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 103064562Sgshapiro d->d_name); 103164562Sgshapiro (void) close(d->d_socket); 103238032Speter goto severe; 103338032Speter } 103438032Speter } 103564562Sgshapiro if (!firsttime && 103664562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 103738032Speter { 103864562Sgshapiro save_errno = errno; 103964562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 104064562Sgshapiro d->d_name); 104164562Sgshapiro (void) close(d->d_socket); 104238032Speter goto severe; 104338032Speter } 104438032Speter return socksize; 104564562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 104664562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 104764562Sgshapiro d->d_name); 104864562Sgshapiro /* NOTREACHED */ 104938032Speter return -1; /* avoid compiler warning on IRIX */ 105038032Speter} 105138032Speter/* 105264562Sgshapiro** SETUPDAEMON -- setup socket for daemon 105364562Sgshapiro** 105464562Sgshapiro** Parameters: 105564562Sgshapiro** daemonaddr -- socket for daemon 105664562Sgshapiro** daemon -- number of daemon 105764562Sgshapiro** 105864562Sgshapiro** Returns: 105964562Sgshapiro** port number on which daemon should run 106064562Sgshapiro** 106164562Sgshapiro*/ 106264562Sgshapirostatic u_short 106364562Sgshapirosetupdaemon(daemonaddr) 106464562Sgshapiro SOCKADDR *daemonaddr; 106564562Sgshapiro{ 106664562Sgshapiro u_short port; 106764562Sgshapiro 106864562Sgshapiro /* 106964562Sgshapiro ** Set up the address for the mailer. 107064562Sgshapiro */ 107164562Sgshapiro 107264562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 107364562Sgshapiro { 107464562Sgshapiro memset(daemonaddr, '\0', sizeof *daemonaddr); 107564562Sgshapiro# if NETINET 107664562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 107764562Sgshapiro# endif /* NETINET */ 107864562Sgshapiro } 107964562Sgshapiro 108064562Sgshapiro switch (daemonaddr->sa.sa_family) 108164562Sgshapiro { 108264562Sgshapiro# if NETINET 108364562Sgshapiro case AF_INET: 108464562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 108564562Sgshapiro daemonaddr->sin.sin_addr.s_addr = INADDR_ANY; 108664562Sgshapiro port = daemonaddr->sin.sin_port; 108764562Sgshapiro break; 108864562Sgshapiro# endif /* NETINET */ 108964562Sgshapiro 109064562Sgshapiro# if NETINET6 109164562Sgshapiro case AF_INET6: 109264562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 109364562Sgshapiro daemonaddr->sin6.sin6_addr = in6addr_any; 109464562Sgshapiro port = daemonaddr->sin6.sin6_port; 109564562Sgshapiro break; 109664562Sgshapiro# endif /* NETINET6 */ 109764562Sgshapiro 109864562Sgshapiro default: 109964562Sgshapiro /* unknown protocol */ 110064562Sgshapiro port = 0; 110164562Sgshapiro break; 110264562Sgshapiro } 110364562Sgshapiro if (port == 0) 110464562Sgshapiro { 110564562Sgshapiro# ifdef NO_GETSERVBYNAME 110664562Sgshapiro port = htons(25); 110764562Sgshapiro# else /* NO_GETSERVBYNAME */ 110864562Sgshapiro { 110964562Sgshapiro register struct servent *sp; 111064562Sgshapiro 111164562Sgshapiro sp = getservbyname("smtp", "tcp"); 111264562Sgshapiro if (sp == NULL) 111364562Sgshapiro { 111464562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 111564562Sgshapiro port = htons(25); 111664562Sgshapiro } 111764562Sgshapiro else 111864562Sgshapiro port = sp->s_port; 111964562Sgshapiro } 112064562Sgshapiro# endif /* NO_GETSERVBYNAME */ 112164562Sgshapiro } 112264562Sgshapiro 112364562Sgshapiro switch (daemonaddr->sa.sa_family) 112464562Sgshapiro { 112564562Sgshapiro# if NETINET 112664562Sgshapiro case AF_INET: 112764562Sgshapiro daemonaddr->sin.sin_port = port; 112864562Sgshapiro break; 112964562Sgshapiro# endif /* NETINET */ 113064562Sgshapiro 113164562Sgshapiro# if NETINET6 113264562Sgshapiro case AF_INET6: 113364562Sgshapiro daemonaddr->sin6.sin6_port = port; 113464562Sgshapiro break; 113564562Sgshapiro# endif /* NETINET6 */ 113664562Sgshapiro 113764562Sgshapiro default: 113864562Sgshapiro /* unknown protocol */ 113964562Sgshapiro break; 114064562Sgshapiro } 114164562Sgshapiro return(port); 114264562Sgshapiro} 114364562Sgshapiro/* 114438032Speter** CLRDAEMON -- reset the daemon connection 114538032Speter** 114638032Speter** Parameters: 114738032Speter** none. 114838032Speter** 114938032Speter** Returns: 115038032Speter** none. 115138032Speter** 115238032Speter** Side Effects: 115338032Speter** releases any resources used by the passive daemon. 115438032Speter*/ 115538032Speter 115638032Spetervoid 115738032Speterclrdaemon() 115838032Speter{ 115964562Sgshapiro int i; 116064562Sgshapiro 116164562Sgshapiro for (i = 0; i < ndaemons; i++) 116264562Sgshapiro { 116364562Sgshapiro if (Daemons[i].d_socket >= 0) 116464562Sgshapiro (void) close(Daemons[i].d_socket); 116564562Sgshapiro Daemons[i].d_socket = -1; 116664562Sgshapiro } 116738032Speter} 116838032Speter/* 116964562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 117038032Speter** 117138032Speter** Parameters: 117238032Speter** p -- the options line. 117364562Sgshapiro** d -- the daemon structure to fill in. 117438032Speter** 117538032Speter** Returns: 117638032Speter** none. 117738032Speter*/ 117838032Speter 117964562Sgshapirostatic void 118064562Sgshapirosetsockaddroptions(p, d) 118138032Speter register char *p; 118264562Sgshapiro struct daemon *d; 118338032Speter{ 118464562Sgshapiro# if NETISO 118571345Sgshapiro short portno; 118664562Sgshapiro# endif /* NETISO */ 118764562Sgshapiro int l; 118864562Sgshapiro char *h, *flags; 118971345Sgshapiro char *port = NULL; 119071345Sgshapiro char *addr = NULL; 119138032Speter 119264562Sgshapiro# if NETINET 119364562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 119464562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 119564562Sgshapiro# endif /* NETINET */ 119664562Sgshapiro 119738032Speter while (p != NULL) 119838032Speter { 119938032Speter register char *f; 120038032Speter register char *v; 120138032Speter 120238032Speter while (isascii(*p) && isspace(*p)) 120338032Speter p++; 120438032Speter if (*p == '\0') 120538032Speter break; 120638032Speter f = p; 120738032Speter p = strchr(p, ','); 120838032Speter if (p != NULL) 120938032Speter *p++ = '\0'; 121038032Speter v = strchr(f, '='); 121138032Speter if (v == NULL) 121238032Speter continue; 121338032Speter while (isascii(*++v) && isspace(*v)) 121438032Speter continue; 121538032Speter if (isascii(*f) && islower(*f)) 121638032Speter *f = toupper(*f); 121738032Speter 121838032Speter switch (*f) 121938032Speter { 122038032Speter case 'F': /* address family */ 122138032Speter if (isascii(*v) && isdigit(*v)) 122264562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 122364562Sgshapiro# if NETINET 122438032Speter else if (strcasecmp(v, "inet") == 0) 122564562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 122664562Sgshapiro# endif /* NETINET */ 122764562Sgshapiro# if NETINET6 122864562Sgshapiro else if (strcasecmp(v, "inet6") == 0) 122964562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 123064562Sgshapiro# endif /* NETINET6 */ 123164562Sgshapiro# if NETISO 123238032Speter else if (strcasecmp(v, "iso") == 0) 123364562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 123464562Sgshapiro# endif /* NETISO */ 123564562Sgshapiro# if NETNS 123638032Speter else if (strcasecmp(v, "ns") == 0) 123764562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 123864562Sgshapiro# endif /* NETNS */ 123964562Sgshapiro# if NETX25 124038032Speter else if (strcasecmp(v, "x.25") == 0) 124164562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 124264562Sgshapiro# endif /* NETX25 */ 124338032Speter else 124464562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 124564562Sgshapiro v); 124638032Speter break; 124738032Speter 124838032Speter case 'A': /* address */ 124971345Sgshapiro addr = v; 125038032Speter break; 125138032Speter 125238032Speter case 'P': /* port */ 125371345Sgshapiro port = v; 125438032Speter break; 125538032Speter 125638032Speter case 'L': /* listen queue size */ 125764562Sgshapiro d->d_listenqueue = atoi(v); 125838032Speter break; 125938032Speter 126064562Sgshapiro case 'M': /* modifiers (flags) */ 126164562Sgshapiro l = 3 * strlen(v) + 3; 126264562Sgshapiro h = v; 126364562Sgshapiro flags = xalloc(l); 126464562Sgshapiro d->d_mflags = flags; 126564562Sgshapiro for (; *h != '\0'; h++) 126664562Sgshapiro { 126764562Sgshapiro if (!(isascii(*h) && isspace(*h))) 126864562Sgshapiro { 126964562Sgshapiro if (flags != d->d_mflags) 127066494Sgshapiro *flags++ = ' '; 127164562Sgshapiro *flags++ = *h; 127264562Sgshapiro if (isupper(*h)) 127364562Sgshapiro *flags++ = *h; 127464562Sgshapiro } 127564562Sgshapiro } 127664562Sgshapiro *flags++ = '\0'; 127764562Sgshapiro for (; *v != '\0'; v++) 127864562Sgshapiro if (!(isascii(*v) && isspace(*v))) 127971345Sgshapiro setbitn(bitidx(*v), d->d_flags); 128064562Sgshapiro break; 128164562Sgshapiro 128238032Speter case 'S': /* send buffer size */ 128364562Sgshapiro d->d_tcpsndbufsize = atoi(v); 128438032Speter break; 128538032Speter 128638032Speter case 'R': /* receive buffer size */ 128764562Sgshapiro d->d_tcprcvbufsize = atoi(v); 128838032Speter break; 128938032Speter 129064562Sgshapiro case 'N': /* name */ 129164562Sgshapiro d->d_name = v; 129264562Sgshapiro break; 129364562Sgshapiro 129438032Speter default: 129564562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 129664562Sgshapiro f); 129738032Speter } 129838032Speter } 129971345Sgshapiro 130071345Sgshapiro /* Check addr and port after finding family */ 130171345Sgshapiro if (addr != NULL) 130271345Sgshapiro { 130371345Sgshapiro switch (d->d_addr.sa.sa_family) 130471345Sgshapiro { 130571345Sgshapiro# if NETINET 130671345Sgshapiro case AF_INET: 130771345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 130871345Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE)) 130971345Sgshapiro { 131071345Sgshapiro register struct hostent *hp; 131171345Sgshapiro 131271345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 131371345Sgshapiro if (hp == NULL) 131471345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 131571345Sgshapiro addr); 131671345Sgshapiro else 131771345Sgshapiro { 131871345Sgshapiro while (*(hp->h_addr_list) != NULL && 131971345Sgshapiro hp->h_addrtype != AF_INET) 132071345Sgshapiro hp->h_addr_list++; 132171345Sgshapiro if (*(hp->h_addr_list) == NULL) 132271345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 132371345Sgshapiro addr); 132471345Sgshapiro else 132571345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 132671345Sgshapiro *(hp->h_addr_list), 132771345Sgshapiro INADDRSZ); 132871345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 132971345Sgshapiro freehostent(hp); 133071345Sgshapiro hp = NULL; 133171345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 133271345Sgshapiro } 133371345Sgshapiro } 133471345Sgshapiro break; 133571345Sgshapiro# endif /* NETINET */ 133671345Sgshapiro 133771345Sgshapiro# if NETINET6 133871345Sgshapiro case AF_INET6: 133971345Sgshapiro if (!isascii(*addr) || 134071345Sgshapiro (!isxdigit(*addr) && *addr != ':') || 134171345Sgshapiro inet_pton(AF_INET6, addr, 134271345Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 134371345Sgshapiro { 134471345Sgshapiro register struct hostent *hp; 134571345Sgshapiro 134671345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 134771345Sgshapiro if (hp == NULL) 134871345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 134971345Sgshapiro addr); 135071345Sgshapiro else 135171345Sgshapiro { 135271345Sgshapiro while (*(hp->h_addr_list) != NULL && 135371345Sgshapiro hp->h_addrtype != AF_INET6) 135471345Sgshapiro hp->h_addr_list++; 135571345Sgshapiro if (*(hp->h_addr_list) == NULL) 135671345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 135771345Sgshapiro addr); 135871345Sgshapiro else 135971345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 136071345Sgshapiro *(hp->h_addr_list), 136171345Sgshapiro IN6ADDRSZ); 136271345Sgshapiro# if _FFR_FREEHOSTENT 136371345Sgshapiro freehostent(hp); 136471345Sgshapiro hp = NULL; 136571345Sgshapiro# endif /* _FFR_FREEHOSTENT */ 136671345Sgshapiro } 136771345Sgshapiro } 136871345Sgshapiro break; 136971345Sgshapiro# endif /* NETINET6 */ 137071345Sgshapiro 137171345Sgshapiro default: 137271345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 137371345Sgshapiro d->d_addr.sa.sa_family); 137471345Sgshapiro break; 137571345Sgshapiro } 137671345Sgshapiro } 137771345Sgshapiro 137871345Sgshapiro if (port != NULL) 137971345Sgshapiro { 138071345Sgshapiro switch (d->d_addr.sa.sa_family) 138171345Sgshapiro { 138271345Sgshapiro# if NETINET 138371345Sgshapiro case AF_INET: 138471345Sgshapiro if (isascii(*port) && isdigit(*port)) 138571345Sgshapiro d->d_addr.sin.sin_port = htons((u_short)atoi((const char *)port)); 138671345Sgshapiro else 138771345Sgshapiro { 138871345Sgshapiro# ifdef NO_GETSERVBYNAME 138971345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 139071345Sgshapiro port); 139171345Sgshapiro# else /* NO_GETSERVBYNAME */ 139271345Sgshapiro register struct servent *sp; 139371345Sgshapiro 139471345Sgshapiro sp = getservbyname(port, "tcp"); 139571345Sgshapiro if (sp == NULL) 139671345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 139771345Sgshapiro port); 139871345Sgshapiro else 139971345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 140071345Sgshapiro# endif /* NO_GETSERVBYNAME */ 140171345Sgshapiro } 140271345Sgshapiro break; 140371345Sgshapiro# endif /* NETINET */ 140471345Sgshapiro 140571345Sgshapiro# if NETINET6 140671345Sgshapiro case AF_INET6: 140771345Sgshapiro if (isascii(*port) && isdigit(*port)) 140871345Sgshapiro d->d_addr.sin6.sin6_port = htons((u_short)atoi(port)); 140971345Sgshapiro else 141071345Sgshapiro { 141171345Sgshapiro# ifdef NO_GETSERVBYNAME 141271345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 141371345Sgshapiro port); 141471345Sgshapiro# else /* NO_GETSERVBYNAME */ 141571345Sgshapiro register struct servent *sp; 141671345Sgshapiro 141771345Sgshapiro sp = getservbyname(port, "tcp"); 141871345Sgshapiro if (sp == NULL) 141971345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 142071345Sgshapiro port); 142171345Sgshapiro else 142271345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 142371345Sgshapiro# endif /* NO_GETSERVBYNAME */ 142471345Sgshapiro } 142571345Sgshapiro break; 142671345Sgshapiro# endif /* NETINET6 */ 142771345Sgshapiro 142871345Sgshapiro# if NETISO 142971345Sgshapiro case AF_ISO: 143071345Sgshapiro /* assume two byte transport selector */ 143171345Sgshapiro if (isascii(*port) && isdigit(*port)) 143271345Sgshapiro portno = htons((u_short)atoi(port)); 143371345Sgshapiro else 143471345Sgshapiro { 143571345Sgshapiro# ifdef NO_GETSERVBYNAME 143671345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 143771345Sgshapiro port); 143871345Sgshapiro# else /* NO_GETSERVBYNAME */ 143971345Sgshapiro register struct servent *sp; 144071345Sgshapiro 144171345Sgshapiro sp = getservbyname(port, "tcp"); 144271345Sgshapiro if (sp == NULL) 144371345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 144471345Sgshapiro port); 144571345Sgshapiro else 144671345Sgshapiro portno = sp->s_port; 144771345Sgshapiro# endif /* NO_GETSERVBYNAME */ 144871345Sgshapiro } 144971345Sgshapiro memmove(TSEL(&d->d_addr.siso), 145071345Sgshapiro (char *) &portno, 2); 145171345Sgshapiro break; 145271345Sgshapiro# endif /* NETISO */ 145371345Sgshapiro 145471345Sgshapiro default: 145571345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 145671345Sgshapiro d->d_addr.sa.sa_family); 145771345Sgshapiro break; 145871345Sgshapiro } 145971345Sgshapiro } 146038032Speter} 146138032Speter/* 146264562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 146338032Speter** 146438032Speter** Parameters: 146564562Sgshapiro** p -- the options line. 146664562Sgshapiro** 146764562Sgshapiro** Returns: 146864562Sgshapiro** TRUE if successful, FALSE otherwise. 146964562Sgshapiro*/ 147064562Sgshapiro 147164562Sgshapirobool 147264562Sgshapirosetdaemonoptions(p) 147364562Sgshapiro register char *p; 147464562Sgshapiro{ 147564562Sgshapiro if (ndaemons >= MAXDAEMONS) 147664562Sgshapiro return FALSE; 147764562Sgshapiro Daemons[ndaemons].d_socket = -1; 147864562Sgshapiro Daemons[ndaemons].d_listenqueue = 10; 147964562Sgshapiro clrbitmap(Daemons[ndaemons].d_flags); 148064562Sgshapiro setsockaddroptions(p, &Daemons[ndaemons]); 148164562Sgshapiro 148264562Sgshapiro if (Daemons[ndaemons].d_name != NULL) 148364562Sgshapiro Daemons[ndaemons].d_name = newstr(Daemons[ndaemons].d_name); 148464562Sgshapiro else 148564562Sgshapiro { 148664562Sgshapiro char num[30]; 148764562Sgshapiro 148864562Sgshapiro snprintf(num, sizeof num, "Daemon%d", ndaemons); 148964562Sgshapiro Daemons[ndaemons].d_name = newstr(num); 149064562Sgshapiro } 149164562Sgshapiro 149264562Sgshapiro if (tTd(37, 1)) 149364562Sgshapiro { 149464562Sgshapiro dprintf("Daemon %s flags: ", Daemons[ndaemons].d_name); 149564562Sgshapiro if (bitnset(D_ETRNONLY, Daemons[ndaemons].d_flags)) 149664562Sgshapiro dprintf("ETRNONLY "); 149764562Sgshapiro if (bitnset(D_NOETRN, Daemons[ndaemons].d_flags)) 149864562Sgshapiro dprintf("NOETRN "); 149964562Sgshapiro dprintf("\n"); 150064562Sgshapiro } 150164562Sgshapiro ++ndaemons; 150264562Sgshapiro return TRUE; 150364562Sgshapiro} 150464562Sgshapiro/* 150564562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 150664562Sgshapiro** 150764562Sgshapiro** Parameters: 150864562Sgshapiro** none 150964562Sgshapiro** 151064562Sgshapiro** Returns: 151164562Sgshapiro** none 151264562Sgshapiro** 151364562Sgshapiro** Side Effects: 151464562Sgshapiro** initializes structure for one daemon. 151564562Sgshapiro*/ 151664562Sgshapirovoid 151764562Sgshapiroinitdaemon() 151864562Sgshapiro{ 151964562Sgshapiro if (ndaemons == 0) 152064562Sgshapiro { 152164562Sgshapiro Daemons[ndaemons].d_socket = -1; 152264562Sgshapiro Daemons[ndaemons].d_listenqueue = 10; 152364562Sgshapiro Daemons[ndaemons].d_name = "Daemon0"; 152464562Sgshapiro ndaemons = 1; 152564562Sgshapiro } 152664562Sgshapiro} 152764562Sgshapiro/* 152864562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 152964562Sgshapiro** 153064562Sgshapiro** Parameters: 153164562Sgshapiro** p -- the options line. 153264562Sgshapiro** 153364562Sgshapiro** Returns: 153464562Sgshapiro** none. 153564562Sgshapiro*/ 153664562Sgshapiro 153764562Sgshapirostatic SOCKADDR ClientAddr; /* address for client */ 153864562Sgshapiro 153964562Sgshapirovoid 154064562Sgshapirosetclientoptions(p) 154164562Sgshapiro register char *p; 154264562Sgshapiro{ 154364562Sgshapiro struct daemon d; 154464562Sgshapiro extern ENVELOPE BlankEnvelope; 154564562Sgshapiro 154664562Sgshapiro memset(&d, '\0', sizeof d); 154764562Sgshapiro setsockaddroptions(p, &d); 154864562Sgshapiro 154964562Sgshapiro /* grab what we need */ 155064562Sgshapiro memcpy(&ClientAddr, &d.d_addr, sizeof ClientAddr); 155164562Sgshapiro TcpSndBufferSize = d.d_tcpsndbufsize; 155264562Sgshapiro TcpRcvBufferSize = d.d_tcprcvbufsize; 155364562Sgshapiro if (d.d_mflags != NULL) 155464562Sgshapiro define(macid("{client_flags}", NULL), d.d_mflags, 155564562Sgshapiro &BlankEnvelope); 155664562Sgshapiro else 155764562Sgshapiro define(macid("{client_flags}", NULL), "", &BlankEnvelope); 155864562Sgshapiro} 155964562Sgshapiro/* 156064562Sgshapiro** ADDR_FAMILY -- determine address family from address 156164562Sgshapiro** 156264562Sgshapiro** Parameters: 156364562Sgshapiro** addr -- the string representation of the address 156464562Sgshapiro** 156564562Sgshapiro** Returns: 156664562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 156764562Sgshapiro** 156864562Sgshapiro** Side Effects: 156964562Sgshapiro** none. 157064562Sgshapiro*/ 157164562Sgshapiro 157264562Sgshapirostatic int 157364562Sgshapiroaddr_family(addr) 157464562Sgshapiro char *addr; 157564562Sgshapiro{ 157664562Sgshapiro# if NETINET6 157764562Sgshapiro SOCKADDR clt_addr; 157864562Sgshapiro# endif /* NETINET6 */ 157964562Sgshapiro 158064562Sgshapiro# if NETINET 158164562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 158264562Sgshapiro { 158364562Sgshapiro if (tTd(16, 9)) 158464562Sgshapiro printf("addr_family(%s): INET\n", addr); 158564562Sgshapiro return AF_INET; 158664562Sgshapiro } 158764562Sgshapiro# endif /* NETINET */ 158864562Sgshapiro# if NETINET6 158964562Sgshapiro if (inet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 159064562Sgshapiro { 159164562Sgshapiro if (tTd(16, 9)) 159264562Sgshapiro printf("addr_family(%s): INET6\n", addr); 159364562Sgshapiro return AF_INET6; 159464562Sgshapiro } 159564562Sgshapiro# endif /* NETINET6 */ 159664562Sgshapiro if (tTd(16, 9)) 159764562Sgshapiro printf("addr_family(%s): UNSPEC\n", addr); 159864562Sgshapiro return AF_UNSPEC; 159964562Sgshapiro} 160064562Sgshapiro/* 160164562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 160264562Sgshapiro** 160364562Sgshapiro** Parameters: 160438032Speter** host -- the name of the host. 160538032Speter** port -- the port number to connect to. 160638032Speter** mci -- a pointer to the mail connection information 160738032Speter** structure to be filled in. 160838032Speter** e -- the current envelope. 160938032Speter** 161038032Speter** Returns: 161138032Speter** An exit code telling whether the connection could be 161238032Speter** made and if not why not. 161338032Speter** 161438032Speter** Side Effects: 161538032Speter** none. 161638032Speter*/ 161738032Speter 161838032Speterstatic jmp_buf CtxConnectTimeout; 161938032Speter 162038032SpeterSOCKADDR CurHostAddr; /* address of current host */ 162138032Speter 162238032Speterint 162338032Spetermakeconnection(host, port, mci, e) 162438032Speter char *host; 162564562Sgshapiro volatile u_int port; 162638032Speter register MCI *mci; 162738032Speter ENVELOPE *e; 162838032Speter{ 162938032Speter register volatile int addrno = 0; 163038032Speter register volatile int s; 163138032Speter register struct hostent *volatile hp = (struct hostent *)NULL; 163238032Speter SOCKADDR addr; 163364562Sgshapiro SOCKADDR clt_addr; 163464562Sgshapiro int save_errno = 0; 163564562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 163638032Speter volatile bool firstconnect; 163738032Speter EVENT *volatile ev = NULL; 163864562Sgshapiro# if NETINET6 163964562Sgshapiro volatile bool v6found = FALSE; 164064562Sgshapiro# endif /* NETINET6 */ 164164562Sgshapiro volatile int family = InetMode; 164264562Sgshapiro SOCKADDR_LEN_T len; 164364562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 164464562Sgshapiro volatile bool clt_bind; 164564562Sgshapiro BITMAP256 d_flags; 164664562Sgshapiro char *p; 164764562Sgshapiro extern ENVELOPE BlankEnvelope; 164838032Speter 164964562Sgshapiro /* retranslate ${daemon_flags} into bitmap */ 165064562Sgshapiro clrbitmap(d_flags); 165164562Sgshapiro if ((p = macvalue(macid("{daemon_flags}", NULL), e)) != NULL) 165264562Sgshapiro { 165364562Sgshapiro for (; *p != '\0'; p++) 165464562Sgshapiro { 165564562Sgshapiro if (!(isascii(*p) && isspace(*p))) 165671345Sgshapiro setbitn(bitidx(*p), d_flags); 165764562Sgshapiro } 165864562Sgshapiro } 165964562Sgshapiro 166064562Sgshapiro /* "add" ${client_flags} to bitmap */ 166164562Sgshapiro if ((p = macvalue(macid("{client_flags}", NULL), e)) != NULL) 166264562Sgshapiro { 166364562Sgshapiro for (; *p != '\0'; p++) 166464562Sgshapiro { 166564562Sgshapiro /* look for just this one flag */ 166664562Sgshapiro if (*p == D_IFNHELO) 166764562Sgshapiro { 166871345Sgshapiro setbitn(bitidx(*p), d_flags); 166964562Sgshapiro break; 167064562Sgshapiro } 167164562Sgshapiro } 167264562Sgshapiro } 167364562Sgshapiro 167464562Sgshapiro# if NETINET6 167564562Sgshapiro v4retry: 167664562Sgshapiro# endif /* NETINET6 */ 167764562Sgshapiro clt_bind = FALSE; 167864562Sgshapiro 167964562Sgshapiro /* Set up the address for outgoing connection. */ 168064562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 168173188Sgshapiro (p = macvalue(macid("{if_addr}", NULL), e)) != NULL && 168273188Sgshapiro *p != '\0') 168364562Sgshapiro { 168464562Sgshapiro# if NETINET6 168564562Sgshapiro char p6[INET6_ADDRSTRLEN]; 168664562Sgshapiro# endif /* NETINET6 */ 168764562Sgshapiro 168864562Sgshapiro memset(&clt_addr, '\0', sizeof clt_addr); 168964562Sgshapiro 169064562Sgshapiro /* infer the address family from the address itself */ 169164562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 169264562Sgshapiro switch (clt_addr.sa.sa_family) 169364562Sgshapiro { 169464562Sgshapiro# if NETINET 169564562Sgshapiro case AF_INET: 169673188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 169773188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 169873188Sgshapiro clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK) 169964562Sgshapiro { 170064562Sgshapiro clt_bind = TRUE; 170164562Sgshapiro socksize = sizeof (struct sockaddr_in); 170264562Sgshapiro } 170364562Sgshapiro break; 170464562Sgshapiro# endif /* NETINET */ 170564562Sgshapiro 170664562Sgshapiro# if NETINET6 170764562Sgshapiro case AF_INET6: 170864562Sgshapiro if (inet_addr(p) != INADDR_NONE) 170964562Sgshapiro snprintf(p6, sizeof p6, "::ffff:%s", p); 171064562Sgshapiro else 171164562Sgshapiro strlcpy(p6, p, sizeof p6); 171264562Sgshapiro if (inet_pton(AF_INET6, p6, 171373188Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 171473188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 171564562Sgshapiro { 171664562Sgshapiro clt_bind = TRUE; 171764562Sgshapiro socksize = sizeof (struct sockaddr_in6); 171864562Sgshapiro } 171964562Sgshapiro break; 172064562Sgshapiro# endif /* NETINET6 */ 172164562Sgshapiro 172264562Sgshapiro# if 0 172364562Sgshapiro default: 172464562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 172564562Sgshapiro clt_addr.sa.sa_family); 172664562Sgshapiro break; 172764562Sgshapiro# endif /* 0 */ 172864562Sgshapiro } 172964562Sgshapiro if (clt_bind) 173064562Sgshapiro family = clt_addr.sa.sa_family; 173164562Sgshapiro } 173264562Sgshapiro else 173364562Sgshapiro { 173464562Sgshapiro STRUCTCOPY(ClientAddr, clt_addr); 173564562Sgshapiro if (clt_addr.sa.sa_family == AF_UNSPEC) 173677349Sgshapiro clt_addr.sa.sa_family = family; 173764562Sgshapiro switch (clt_addr.sa.sa_family) 173864562Sgshapiro { 173964562Sgshapiro# if NETINET 174064562Sgshapiro case AF_INET: 174164562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 174264562Sgshapiro clt_addr.sin.sin_addr.s_addr = INADDR_ANY; 174364562Sgshapiro else 174464562Sgshapiro clt_bind = TRUE; 174564562Sgshapiro if (clt_addr.sin.sin_port != 0) 174664562Sgshapiro clt_bind = TRUE; 174764562Sgshapiro socksize = sizeof (struct sockaddr_in); 174864562Sgshapiro break; 174964562Sgshapiro# endif /* NETINET */ 175064562Sgshapiro# if NETINET6 175164562Sgshapiro case AF_INET6: 175264562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 175364562Sgshapiro clt_addr.sin6.sin6_addr = in6addr_any; 175464562Sgshapiro else 175564562Sgshapiro clt_bind = TRUE; 175664562Sgshapiro socksize = sizeof (struct sockaddr_in6); 175764562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 175864562Sgshapiro clt_bind = TRUE; 175964562Sgshapiro break; 176064562Sgshapiro# endif /* NETINET6 */ 176164562Sgshapiro# if NETISO 176264562Sgshapiro case AF_ISO: 176364562Sgshapiro socksize = sizeof clt_addr.siso; 176464562Sgshapiro clt_bind = TRUE; 176564562Sgshapiro break; 176664562Sgshapiro# endif /* NETISO */ 176764562Sgshapiro default: 176864562Sgshapiro break; 176964562Sgshapiro } 177064562Sgshapiro } 177164562Sgshapiro 177238032Speter /* 177338032Speter ** Set up the address for the mailer. 177438032Speter ** Accept "[a.b.c.d]" syntax for host name. 177538032Speter */ 177638032Speter 177764562Sgshapiro# if NAMED_BIND 177873188Sgshapiro SM_SET_H_ERRNO(0); 177964562Sgshapiro# endif /* NAMED_BIND */ 178038032Speter errno = 0; 178164562Sgshapiro memset(&CurHostAddr, '\0', sizeof CurHostAddr); 178264562Sgshapiro memset(&addr, '\0', sizeof addr); 178338032Speter SmtpPhase = mci->mci_phase = "initial connection"; 178438032Speter CurHostName = host; 178538032Speter 178638032Speter if (host[0] == '[') 178738032Speter { 178864562Sgshapiro p = strchr(host, ']'); 178938032Speter if (p != NULL) 179038032Speter { 179164562Sgshapiro# if NETINET 179264562Sgshapiro unsigned long hid = INADDR_NONE; 179364562Sgshapiro# endif /* NETINET */ 179464562Sgshapiro# if NETINET6 179564562Sgshapiro struct sockaddr_in6 hid6; 179664562Sgshapiro# endif /* NETINET6 */ 179764562Sgshapiro 179838032Speter *p = '\0'; 179964562Sgshapiro# if NETINET6 180064562Sgshapiro memset(&hid6, '\0', sizeof hid6); 180164562Sgshapiro# endif /* NETINET6 */ 180264562Sgshapiro# if NETINET 180364562Sgshapiro if (family == AF_INET && 180464562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 180538032Speter { 180664562Sgshapiro addr.sin.sin_family = AF_INET; 180764562Sgshapiro addr.sin.sin_addr.s_addr = hid; 180864562Sgshapiro } 180964562Sgshapiro else 181064562Sgshapiro# endif /* NETINET */ 181164562Sgshapiro# if NETINET6 181264562Sgshapiro if (family == AF_INET6 && 181364562Sgshapiro inet_pton(AF_INET6, &host[1], 181464562Sgshapiro &hid6.sin6_addr) == 1) 181564562Sgshapiro { 181664562Sgshapiro addr.sin6.sin6_family = AF_INET6; 181764562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 181864562Sgshapiro } 181964562Sgshapiro else 182064562Sgshapiro# endif /* NETINET6 */ 182164562Sgshapiro { 182238032Speter /* try it as a host name (avoid MX lookup) */ 182364562Sgshapiro hp = sm_gethostbyname(&host[1], family); 182438032Speter if (hp == NULL && p[-1] == '.') 182538032Speter { 182664562Sgshapiro# if NAMED_BIND 182738032Speter int oldopts = _res.options; 182838032Speter 182938032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 183064562Sgshapiro# endif /* NAMED_BIND */ 183138032Speter p[-1] = '\0'; 183264562Sgshapiro hp = sm_gethostbyname(&host[1], 183364562Sgshapiro family); 183438032Speter p[-1] = '.'; 183564562Sgshapiro# if NAMED_BIND 183638032Speter _res.options = oldopts; 183764562Sgshapiro# endif /* NAMED_BIND */ 183838032Speter } 183938032Speter *p = ']'; 184038032Speter goto gothostent; 184138032Speter } 184238032Speter *p = ']'; 184338032Speter } 184438032Speter if (p == NULL) 184538032Speter { 184638032Speter extern char MsgBuf[]; 184738032Speter 184864562Sgshapiro usrerrenh("5.1.2", 184964562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 185064562Sgshapiro host); 185138032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 185264562Sgshapiro errno = EINVAL; 185338032Speter return EX_NOHOST; 185438032Speter } 185538032Speter } 185638032Speter else 185738032Speter { 185838032Speter /* contortion to get around SGI cc complaints */ 185938032Speter { 186064562Sgshapiro p = &host[strlen(host) - 1]; 186164562Sgshapiro hp = sm_gethostbyname(host, family); 186238032Speter if (hp == NULL && *p == '.') 186338032Speter { 186464562Sgshapiro# if NAMED_BIND 186538032Speter int oldopts = _res.options; 186638032Speter 186738032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 186864562Sgshapiro# endif /* NAMED_BIND */ 186938032Speter *p = '\0'; 187064562Sgshapiro hp = sm_gethostbyname(host, family); 187138032Speter *p = '.'; 187264562Sgshapiro# if NAMED_BIND 187338032Speter _res.options = oldopts; 187464562Sgshapiro# endif /* NAMED_BIND */ 187538032Speter } 187638032Speter } 187738032Spetergothostent: 187838032Speter if (hp == NULL) 187938032Speter { 188064562Sgshapiro# if NAMED_BIND 188138032Speter /* check for name server timeouts */ 188238032Speter if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 188338032Speter (errno == ECONNREFUSED && UseNameServer)) 188438032Speter { 188564562Sgshapiro save_errno = errno; 188638032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL); 188764562Sgshapiro errno = save_errno; 188838032Speter return EX_TEMPFAIL; 188938032Speter } 189064562Sgshapiro# endif /* NAMED_BIND */ 189164562Sgshapiro# if NETINET6 189264562Sgshapiro /* 189364562Sgshapiro ** Try v6 first, then fall back to v4. 189464562Sgshapiro ** If we found a v6 address, but no v4 189564562Sgshapiro ** addresses, then TEMPFAIL. 189664562Sgshapiro */ 189764562Sgshapiro 189864562Sgshapiro if (family == AF_INET6) 189964562Sgshapiro { 190064562Sgshapiro family = AF_INET; 190164562Sgshapiro goto v4retry; 190264562Sgshapiro } 190364562Sgshapiro if (v6found) 190464562Sgshapiro goto v6tempfail; 190564562Sgshapiro# endif /* NETINET6 */ 190664562Sgshapiro save_errno = errno; 190738032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 190864562Sgshapiro errno = save_errno; 190964562Sgshapiro return EX_NOHOST; 191038032Speter } 191138032Speter addr.sa.sa_family = hp->h_addrtype; 191238032Speter switch (hp->h_addrtype) 191338032Speter { 191464562Sgshapiro# if NETINET 191538032Speter case AF_INET: 191664562Sgshapiro memmove(&addr.sin.sin_addr, 191764562Sgshapiro hp->h_addr, 191838032Speter INADDRSZ); 191938032Speter break; 192064562Sgshapiro# endif /* NETINET */ 192138032Speter 192264562Sgshapiro# if NETINET6 192364562Sgshapiro case AF_INET6: 192464562Sgshapiro memmove(&addr.sin6.sin6_addr, 192564562Sgshapiro hp->h_addr, 192664562Sgshapiro IN6ADDRSZ); 192764562Sgshapiro break; 192864562Sgshapiro# endif /* NETINET6 */ 192964562Sgshapiro 193038032Speter default: 193138032Speter if (hp->h_length > sizeof addr.sa.sa_data) 193238032Speter { 193338032Speter syserr("makeconnection: long sa_data: family %d len %d", 193438032Speter hp->h_addrtype, hp->h_length); 193538032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 193664562Sgshapiro errno = EINVAL; 193738032Speter return EX_NOHOST; 193838032Speter } 193964562Sgshapiro memmove(addr.sa.sa_data, 194064562Sgshapiro hp->h_addr, 194138032Speter hp->h_length); 194238032Speter break; 194338032Speter } 194438032Speter addrno = 1; 194538032Speter } 194638032Speter 194738032Speter /* 194838032Speter ** Determine the port number. 194938032Speter */ 195038032Speter 195138032Speter if (port == 0) 195238032Speter { 195364562Sgshapiro# ifdef NO_GETSERVBYNAME 195464562Sgshapiro port = htons(25); 195564562Sgshapiro# else /* NO_GETSERVBYNAME */ 195638032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 195738032Speter 195838032Speter if (sp == NULL) 195938032Speter { 196038032Speter if (LogLevel > 2) 196138032Speter sm_syslog(LOG_ERR, NOQID, 196264562Sgshapiro "makeconnection: service \"smtp\" unknown"); 196338032Speter port = htons(25); 196438032Speter } 196538032Speter else 196638032Speter port = sp->s_port; 196764562Sgshapiro# endif /* NO_GETSERVBYNAME */ 196838032Speter } 196938032Speter 197038032Speter switch (addr.sa.sa_family) 197138032Speter { 197264562Sgshapiro# if NETINET 197338032Speter case AF_INET: 197438032Speter addr.sin.sin_port = port; 197538032Speter addrlen = sizeof (struct sockaddr_in); 197638032Speter break; 197764562Sgshapiro# endif /* NETINET */ 197838032Speter 197964562Sgshapiro# if NETINET6 198064562Sgshapiro case AF_INET6: 198164562Sgshapiro addr.sin6.sin6_port = port; 198264562Sgshapiro addrlen = sizeof (struct sockaddr_in6); 198364562Sgshapiro break; 198464562Sgshapiro# endif /* NETINET6 */ 198564562Sgshapiro 198664562Sgshapiro# if NETISO 198738032Speter case AF_ISO: 198838032Speter /* assume two byte transport selector */ 198964562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 199038032Speter addrlen = sizeof (struct sockaddr_iso); 199138032Speter break; 199264562Sgshapiro# endif /* NETISO */ 199338032Speter 199438032Speter default: 199538032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 199638032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 199764562Sgshapiro errno = EINVAL; 199871345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 199971345Sgshapiro if (hp != NULL) 200071345Sgshapiro freehostent(hp); 200171345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 200264562Sgshapiro return EX_NOHOST; 200338032Speter } 200438032Speter 200538032Speter /* 200638032Speter ** Try to actually open the connection. 200738032Speter */ 200838032Speter 200964562Sgshapiro# ifdef XLA 201038032Speter /* if too many connections, don't bother trying */ 201138032Speter if (!xla_noqueue_ok(host)) 201271345Sgshapiro { 201371345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 201471345Sgshapiro if (hp != NULL) 201571345Sgshapiro freehostent(hp); 201671345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 201738032Speter return EX_TEMPFAIL; 201871345Sgshapiro } 201964562Sgshapiro# endif /* XLA */ 202038032Speter 202138032Speter firstconnect = TRUE; 202238032Speter for (;;) 202338032Speter { 202438032Speter if (tTd(16, 1)) 202577349Sgshapiro dprintf("makeconnection (%s [%s].%d (%d))\n", 202677349Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 202777349Sgshapiro addr.sa.sa_family); 202838032Speter 202938032Speter /* save for logging */ 203038032Speter CurHostAddr = addr; 203138032Speter 203238032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 203338032Speter { 203438032Speter int rport = IPPORT_RESERVED - 1; 203538032Speter 203638032Speter s = rresvport(&rport); 203738032Speter } 203838032Speter else 203938032Speter { 204077349Sgshapiro s = socket(clt_addr.sa.sa_family, SOCK_STREAM, 0); 204138032Speter } 204238032Speter if (s < 0) 204338032Speter { 204464562Sgshapiro save_errno = errno; 204538032Speter syserr("makeconnection: cannot create socket"); 204664562Sgshapiro# ifdef XLA 204738032Speter xla_host_end(host); 204864562Sgshapiro# endif /* XLA */ 204938032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 205071345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 205171345Sgshapiro if (hp != NULL) 205271345Sgshapiro freehostent(hp); 205371345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 205464562Sgshapiro errno = save_errno; 205538032Speter return EX_TEMPFAIL; 205638032Speter } 205738032Speter 205864562Sgshapiro# ifdef SO_SNDBUF 205938032Speter if (TcpSndBufferSize > 0) 206038032Speter { 206138032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 206238032Speter (char *) &TcpSndBufferSize, 206338032Speter sizeof(TcpSndBufferSize)) < 0) 206438032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 206538032Speter } 206664562Sgshapiro# endif /* SO_SNDBUF */ 206764562Sgshapiro# ifdef SO_RCVBUF 206864562Sgshapiro if (TcpRcvBufferSize > 0) 206964562Sgshapiro { 207064562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 207164562Sgshapiro (char *) &TcpRcvBufferSize, 207264562Sgshapiro sizeof(TcpRcvBufferSize)) < 0) 207364562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 207464562Sgshapiro } 207564562Sgshapiro# endif /* SO_RCVBUF */ 207638032Speter 207764562Sgshapiro 207838032Speter if (tTd(16, 1)) 207964562Sgshapiro dprintf("makeconnection: fd=%d\n", s); 208038032Speter 208138032Speter /* turn on network debugging? */ 208238032Speter if (tTd(16, 101)) 208338032Speter { 208438032Speter int on = 1; 208564562Sgshapiro 208638032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 208738032Speter (char *)&on, sizeof on); 208838032Speter } 208938032Speter if (e->e_xfp != NULL) 209064562Sgshapiro (void) fflush(e->e_xfp); /* for debugging */ 209164562Sgshapiro errno = 0; /* for debugging */ 209238032Speter 209364562Sgshapiro if (clt_bind) 209464562Sgshapiro { 209564562Sgshapiro int on = 1; 209664562Sgshapiro 209764562Sgshapiro switch (clt_addr.sa.sa_family) 209864562Sgshapiro { 209964562Sgshapiro# if NETINET 210064562Sgshapiro case AF_INET: 210164562Sgshapiro if (clt_addr.sin.sin_port != 0) 210264562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 210364562Sgshapiro SO_REUSEADDR, 210464562Sgshapiro (char *) &on, 210564562Sgshapiro sizeof on); 210664562Sgshapiro break; 210764562Sgshapiro# endif /* NETINET */ 210864562Sgshapiro 210964562Sgshapiro# if NETINET6 211064562Sgshapiro case AF_INET6: 211164562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 211264562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 211364562Sgshapiro SO_REUSEADDR, 211464562Sgshapiro (char *) &on, 211564562Sgshapiro sizeof on); 211664562Sgshapiro break; 211764562Sgshapiro# endif /* NETINET6 */ 211864562Sgshapiro } 211964562Sgshapiro 212064562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 212164562Sgshapiro { 212264562Sgshapiro save_errno = errno; 212364562Sgshapiro (void) close(s); 212464562Sgshapiro errno = save_errno; 212564562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 212664562Sgshapiro anynet_ntoa(&clt_addr)); 212771345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 212871345Sgshapiro if (hp != NULL) 212971345Sgshapiro freehostent(hp); 213071345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 213164562Sgshapiro errno = save_errno; 213264562Sgshapiro return EX_TEMPFAIL; 213364562Sgshapiro } 213464562Sgshapiro } 213564562Sgshapiro 213638032Speter /* 213738032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 213838032Speter ** Time out the connect to avoid this problem. 213938032Speter */ 214038032Speter 214138032Speter if (setjmp(CtxConnectTimeout) == 0) 214238032Speter { 214338032Speter int i; 214438032Speter 214538032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 214677349Sgshapiro ev = setevent(TimeOuts.to_iconnect, 214777349Sgshapiro connecttimeout, 0); 214838032Speter else if (TimeOuts.to_connect != 0) 214977349Sgshapiro ev = setevent(TimeOuts.to_connect, 215077349Sgshapiro connecttimeout, 0); 215138032Speter else 215238032Speter ev = NULL; 215338032Speter 215464562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 215564562Sgshapiro { 215664562Sgshapiro# if NETINET 215764562Sgshapiro case AF_INET: 215864562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 215964562Sgshapiro break; 216064562Sgshapiro# endif /* NETINET */ 216164562Sgshapiro 216264562Sgshapiro# if NETINET6 216364562Sgshapiro case AF_INET6: 216464562Sgshapiro memmove(&addr.sin6.sin6_addr, 216564562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 216664562Sgshapiro IN6ADDRSZ); 216764562Sgshapiro break; 216864562Sgshapiro# endif /* NETINET6 */ 216964562Sgshapiro } 217038032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 217164562Sgshapiro save_errno = errno; 217238032Speter if (ev != NULL) 217338032Speter clrevent(ev); 217438032Speter if (i >= 0) 217538032Speter break; 217638032Speter } 217738032Speter else 217864562Sgshapiro save_errno = errno; 217938032Speter 218038032Speter /* if running demand-dialed connection, try again */ 218138032Speter if (DialDelay > 0 && firstconnect) 218238032Speter { 218338032Speter if (tTd(16, 1)) 218464562Sgshapiro dprintf("Connect failed (%s); trying again...\n", 218564562Sgshapiro errstring(save_errno)); 218638032Speter firstconnect = FALSE; 218764562Sgshapiro (void) sleep(DialDelay); 218838032Speter continue; 218938032Speter } 219038032Speter 219138032Speter /* couldn't connect.... figure out why */ 219238032Speter (void) close(s); 219338032Speter 219438032Speter if (LogLevel >= 14) 219538032Speter sm_syslog(LOG_INFO, e->e_id, 219638032Speter "makeconnection (%s [%s]) failed: %s", 219738032Speter host, anynet_ntoa(&addr), 219864562Sgshapiro errstring(save_errno)); 219938032Speter 220038032Speter if (hp != NULL && hp->h_addr_list[addrno] != NULL) 220138032Speter { 220238032Speter if (tTd(16, 1)) 220364562Sgshapiro dprintf("Connect failed (%s); trying new address....\n", 220464562Sgshapiro errstring(save_errno)); 220538032Speter switch (addr.sa.sa_family) 220638032Speter { 220764562Sgshapiro# if NETINET 220838032Speter case AF_INET: 220964562Sgshapiro memmove(&addr.sin.sin_addr, 221064562Sgshapiro hp->h_addr_list[addrno++], 221164562Sgshapiro INADDRSZ); 221238032Speter break; 221364562Sgshapiro# endif /* NETINET */ 221438032Speter 221564562Sgshapiro# if NETINET6 221664562Sgshapiro case AF_INET6: 221764562Sgshapiro memmove(&addr.sin6.sin6_addr, 221864562Sgshapiro hp->h_addr_list[addrno++], 221964562Sgshapiro IN6ADDRSZ); 222064562Sgshapiro break; 222164562Sgshapiro# endif /* NETINET6 */ 222264562Sgshapiro 222338032Speter default: 222464562Sgshapiro memmove(addr.sa.sa_data, 222564562Sgshapiro hp->h_addr_list[addrno++], 222638032Speter hp->h_length); 222738032Speter break; 222838032Speter } 222938032Speter continue; 223038032Speter } 223164562Sgshapiro errno = save_errno; 223238032Speter 223364562Sgshapiro# if NETINET6 223464562Sgshapiro if (family == AF_INET6) 223564562Sgshapiro { 223664562Sgshapiro if (tTd(16, 1)) 223764562Sgshapiro dprintf("Connect failed (%s); retrying with AF_INET....\n", 223864562Sgshapiro errstring(save_errno)); 223964562Sgshapiro v6found = TRUE; 224064562Sgshapiro family = AF_INET; 224171345Sgshapiro# if _FFR_FREEHOSTENT 224271345Sgshapiro if (hp != NULL) 224371345Sgshapiro { 224471345Sgshapiro freehostent(hp); 224571345Sgshapiro hp = NULL; 224671345Sgshapiro } 224771345Sgshapiro# endif /* _FFR_FREEHOSTENT */ 224864562Sgshapiro goto v4retry; 224964562Sgshapiro } 225064562Sgshapiro v6tempfail: 225164562Sgshapiro# endif /* NETINET6 */ 225238032Speter /* couldn't open connection */ 225364562Sgshapiro# if NETINET6 225464562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 225564562Sgshapiro if (errno > 0) 225664562Sgshapiro# endif /* NETINET6 */ 225764562Sgshapiro save_errno = errno; 225864562Sgshapiro if (tTd(16, 1)) 225964562Sgshapiro dprintf("Connect failed (%s)\n", errstring(save_errno)); 226064562Sgshapiro# ifdef XLA 226138032Speter xla_host_end(host); 226264562Sgshapiro# endif /* XLA */ 226338032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 226471345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 226571345Sgshapiro if (hp != NULL) 226671345Sgshapiro freehostent(hp); 226771345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 226864562Sgshapiro errno = save_errno; 226938032Speter return EX_TEMPFAIL; 227038032Speter } 227138032Speter 227271345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 227371345Sgshapiro if (hp != NULL) 227471345Sgshapiro { 227571345Sgshapiro freehostent(hp); 227671345Sgshapiro hp = NULL; 227771345Sgshapiro } 227871345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 227971345Sgshapiro 228038032Speter /* connection ok, put it into canonical form */ 228164562Sgshapiro mci->mci_out = NULL; 228238032Speter if ((mci->mci_out = fdopen(s, "w")) == NULL || 228338032Speter (s = dup(s)) < 0 || 228438032Speter (mci->mci_in = fdopen(s, "r")) == NULL) 228538032Speter { 228664562Sgshapiro save_errno = errno; 228738032Speter syserr("cannot open SMTP client channel, fd=%d", s); 228838032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 228964562Sgshapiro if (mci->mci_out != NULL) 229064562Sgshapiro (void) fclose(mci->mci_out); 229164562Sgshapiro (void) close(s); 229264562Sgshapiro errno = save_errno; 229338032Speter return EX_TEMPFAIL; 229438032Speter } 229538032Speter 229664562Sgshapiro /* find out name for Interface through which we connect */ 229764562Sgshapiro len = sizeof addr; 229864562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 229964562Sgshapiro { 230064562Sgshapiro char *name; 230164562Sgshapiro char *p; 230264562Sgshapiro 230364562Sgshapiro define(macid("{if_addr}", NULL), newstr(anynet_ntoa(&addr)), 230464562Sgshapiro &BlankEnvelope); 230564562Sgshapiro p = xalloc(5); 230664562Sgshapiro snprintf(p, 4, "%d", addr.sa.sa_family); 230764562Sgshapiro define(macid("{if_family}", NULL), p, &BlankEnvelope); 230864562Sgshapiro 230964562Sgshapiro name = hostnamebyanyaddr(&addr); 231064562Sgshapiro define(macid("{if_name}", NULL), newstr(name), &BlankEnvelope); 231164562Sgshapiro if (LogLevel > 11) 231264562Sgshapiro { 231364562Sgshapiro /* log connection information */ 231464562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 231564562Sgshapiro "SMTP outgoing connect on %.40s", name); 231664562Sgshapiro } 231764562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 231864562Sgshapiro { 231964562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 232064562Sgshapiro mci->mci_heloname = newstr(name); 232164562Sgshapiro } 232264562Sgshapiro } 232364562Sgshapiro else 232464562Sgshapiro { 232564562Sgshapiro define(macid("{if_name}", NULL), NULL, &BlankEnvelope); 232664562Sgshapiro define(macid("{if_addr}", NULL), NULL, &BlankEnvelope); 232764562Sgshapiro define(macid("{if_family}", NULL), NULL, &BlankEnvelope); 232864562Sgshapiro } 232938032Speter mci_setstat(mci, EX_OK, NULL, NULL); 233064562Sgshapiro return EX_OK; 233138032Speter} 233264562Sgshapiro 233364562Sgshapirostatic void 233464562Sgshapiroconnecttimeout() 233564562Sgshapiro{ 233677349Sgshapiro /* 233777349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 233877349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 233977349Sgshapiro ** DOING. 234077349Sgshapiro */ 234177349Sgshapiro 234264562Sgshapiro errno = ETIMEDOUT; 234364562Sgshapiro longjmp(CtxConnectTimeout, 1); 234464562Sgshapiro} 234538032Speter/* 234664562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 234764562Sgshapiro** 234864562Sgshapiro** Parameters: 234964562Sgshapiro** mux_path -- the path of the socket to connect to. 235064562Sgshapiro** mci -- a pointer to the mail connection information 235164562Sgshapiro** structure to be filled in. 235264562Sgshapiro** 235364562Sgshapiro** Returns: 235464562Sgshapiro** An exit code telling whether the connection could be 235564562Sgshapiro** made and if not why not. 235664562Sgshapiro** 235764562Sgshapiro** Side Effects: 235864562Sgshapiro** none. 235964562Sgshapiro*/ 236064562Sgshapiro 236164562Sgshapiro# if NETUNIX 236264562Sgshapiroint makeconnection_ds(mux_path, mci) 236364562Sgshapiro char *mux_path; 236464562Sgshapiro register MCI *mci; 236564562Sgshapiro{ 236664562Sgshapiro int sock; 236764562Sgshapiro int rval, save_errno; 236864562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 236964562Sgshapiro struct sockaddr_un unix_addr; 237064562Sgshapiro 237164562Sgshapiro /* if not safe, don't connect */ 237264562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 237364562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 237464562Sgshapiro 237564562Sgshapiro if (rval != 0) 237664562Sgshapiro { 237764562Sgshapiro syserr("makeconnection_ds: unsafe domain socket"); 237864562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 237964562Sgshapiro errno = rval; 238064562Sgshapiro return EX_TEMPFAIL; 238164562Sgshapiro } 238264562Sgshapiro 238364562Sgshapiro /* prepare address structure */ 238464562Sgshapiro memset(&unix_addr, '\0', sizeof unix_addr); 238564562Sgshapiro unix_addr.sun_family = AF_UNIX; 238664562Sgshapiro 238764562Sgshapiro if (strlen(mux_path) >= sizeof unix_addr.sun_path) 238864562Sgshapiro { 238964562Sgshapiro syserr("makeconnection_ds: domain socket name too long"); 239064562Sgshapiro /* XXX why TEMPFAIL ? */ 239164562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 239264562Sgshapiro errno = ENAMETOOLONG; 239364562Sgshapiro return EX_UNAVAILABLE; 239464562Sgshapiro } 239564562Sgshapiro (void) strlcpy(unix_addr.sun_path, mux_path, sizeof unix_addr.sun_path); 239664562Sgshapiro 239764562Sgshapiro /* initialize domain socket */ 239864562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 239964562Sgshapiro if (sock == -1) 240064562Sgshapiro { 240164562Sgshapiro save_errno = errno; 240264562Sgshapiro syserr("makeconnection_ds: could not create domain socket"); 240364562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 240464562Sgshapiro errno = save_errno; 240564562Sgshapiro return EX_TEMPFAIL; 240664562Sgshapiro } 240764562Sgshapiro 240864562Sgshapiro /* connect to server */ 240964562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 241064562Sgshapiro sizeof(unix_addr)) == -1) 241164562Sgshapiro { 241264562Sgshapiro save_errno = errno; 241364562Sgshapiro syserr("Could not connect to socket %s", mux_path); 241464562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 241564562Sgshapiro (void) close(sock); 241664562Sgshapiro errno = save_errno; 241764562Sgshapiro return EX_TEMPFAIL; 241864562Sgshapiro } 241964562Sgshapiro 242064562Sgshapiro /* connection ok, put it into canonical form */ 242164562Sgshapiro mci->mci_out = NULL; 242264562Sgshapiro if ((mci->mci_out = fdopen(sock, "w")) == NULL || 242364562Sgshapiro (sock = dup(sock)) < 0 || 242464562Sgshapiro (mci->mci_in = fdopen(sock, "r")) == NULL) 242564562Sgshapiro { 242664562Sgshapiro save_errno = errno; 242764562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 242864562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 242964562Sgshapiro if (mci->mci_out != NULL) 243064562Sgshapiro (void) fclose(mci->mci_out); 243164562Sgshapiro (void) close(sock); 243264562Sgshapiro errno = save_errno; 243364562Sgshapiro return EX_TEMPFAIL; 243464562Sgshapiro } 243564562Sgshapiro 243664562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 243764562Sgshapiro errno = 0; 243864562Sgshapiro return EX_OK; 243964562Sgshapiro} 244064562Sgshapiro# endif /* NETUNIX */ 244164562Sgshapiro/* 244277349Sgshapiro** SIGHUP -- handle a SIGHUP signal 244377349Sgshapiro** 244477349Sgshapiro** Parameters: 244577349Sgshapiro** sig -- incoming signal. 244677349Sgshapiro** 244777349Sgshapiro** Returns: 244877349Sgshapiro** none. 244977349Sgshapiro** 245077349Sgshapiro** Side Effects: 245177349Sgshapiro** Sets RestartRequest which should cause the daemon 245277349Sgshapiro** to restart. 245377349Sgshapiro** 245477349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 245577349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 245677349Sgshapiro** DOING. 245777349Sgshapiro*/ 245877349Sgshapiro 245977349Sgshapiro/* ARGSUSED */ 246077349Sgshapirostatic SIGFUNC_DECL 246177349Sgshapirosighup(sig) 246277349Sgshapiro int sig; 246377349Sgshapiro{ 246477349Sgshapiro int save_errno = errno; 246577349Sgshapiro 246677349Sgshapiro FIX_SYSV_SIGNAL(sig, sighup); 246777349Sgshapiro RestartRequest = "signal"; 246877349Sgshapiro errno = save_errno; 246977349Sgshapiro return SIGFUNC_RETURN; 247077349Sgshapiro} 247177349Sgshapiro/* 247277349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 247377349Sgshapiro** 247477349Sgshapiro** Parameters: 247577349Sgshapiro** none. 247677349Sgshapiro** 247777349Sgshapiro** Returns: 247877349Sgshapiro** none. 247977349Sgshapiro** 248077349Sgshapiro** Side Effects: 248177349Sgshapiro** restarts the daemon or exits if restart fails. 248277349Sgshapiro*/ 248377349Sgshapiro 248480785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 248580785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 248680785Sgshapirodo \ 248780785Sgshapiro{ \ 248880785Sgshapiro (old) = setsignal((sig), sm_signal_noop); \ 248980785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 249080785Sgshapiro (void) setsignal((sig), (old)); \ 249180785Sgshapiro} while (0) 249280785Sgshapiro 249377349Sgshapirostatic void 249477349Sgshapirorestart_daemon() 249577349Sgshapiro{ 249677349Sgshapiro int i; 249777349Sgshapiro int save_errno; 249877349Sgshapiro char *reason; 249980785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 250077349Sgshapiro extern int DtableSize; 250177349Sgshapiro 250280785Sgshapiro /* clear the events to turn off SIGALRMs */ 250380785Sgshapiro clear_events(); 250477349Sgshapiro allsignals(TRUE); 250577349Sgshapiro 250677349Sgshapiro reason = RestartRequest; 250777349Sgshapiro RestartRequest = NULL; 250877349Sgshapiro PendingSignal = 0; 250977349Sgshapiro 251077349Sgshapiro if (SaveArgv[0][0] != '/') 251177349Sgshapiro { 251277349Sgshapiro if (LogLevel > 3) 251377349Sgshapiro sm_syslog(LOG_INFO, NOQID, 251477349Sgshapiro "could not restart: need full path"); 251577349Sgshapiro finis(FALSE, EX_OSFILE); 251677349Sgshapiro } 251777349Sgshapiro if (LogLevel > 3) 251877349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 251977349Sgshapiro SaveArgv[0], 252077349Sgshapiro reason == NULL ? "implicit call" : reason); 252177349Sgshapiro 252277349Sgshapiro closecontrolsocket(TRUE); 252377349Sgshapiro if (drop_privileges(TRUE) != EX_OK) 252477349Sgshapiro { 252577349Sgshapiro if (LogLevel > 0) 252677349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 252777349Sgshapiro "could not set[ug]id(%d, %d): %m", 252877349Sgshapiro RunAsUid, RunAsGid); 252977349Sgshapiro finis(FALSE, EX_OSERR); 253077349Sgshapiro } 253177349Sgshapiro 253277349Sgshapiro /* arrange for all the files to be closed */ 253377349Sgshapiro for (i = 3; i < DtableSize; i++) 253477349Sgshapiro { 253577349Sgshapiro register int j; 253677349Sgshapiro 253777349Sgshapiro if ((j = fcntl(i, F_GETFD, 0)) != -1) 253877349Sgshapiro (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); 253977349Sgshapiro } 254077349Sgshapiro 254180785Sgshapiro /* 254280785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 254380785Sgshapiro ** However, the default action can be "terminate", so it isn't 254480785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 254580785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 254680785Sgshapiro */ 254780785Sgshapiro 254880785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 254980785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 255080785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 255180785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 255280785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 255380785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 255480785Sgshapiro#ifdef SIGUSR1 255580785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 255680785Sgshapiro#endif /* SIGUSR1 */ 255777349Sgshapiro allsignals(FALSE); 255877349Sgshapiro 255977349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 256077349Sgshapiro save_errno = errno; 256177349Sgshapiro 256280785Sgshapiro /* block signals again and restore needed signals */ 256377349Sgshapiro allsignals(TRUE); 256480785Sgshapiro 256580785Sgshapiro /* For finis() events */ 256677349Sgshapiro (void) setsignal(SIGALRM, oalrm); 256780785Sgshapiro 256880785Sgshapiro#ifdef SIGUSR1 256980785Sgshapiro /* For debugging finis() */ 257077349Sgshapiro (void) setsignal(SIGUSR1, ousr1); 257180785Sgshapiro#endif /* SIGUSR1 */ 257277349Sgshapiro 257377349Sgshapiro errno = save_errno; 257477349Sgshapiro if (LogLevel > 0) 257577349Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", 257677349Sgshapiro SaveArgv[0]); 257777349Sgshapiro finis(FALSE, EX_OSFILE); 257877349Sgshapiro} 257977349Sgshapiro/* 258038032Speter** MYHOSTNAME -- return the name of this host. 258138032Speter** 258238032Speter** Parameters: 258338032Speter** hostbuf -- a place to return the name of this host. 258438032Speter** size -- the size of hostbuf. 258538032Speter** 258638032Speter** Returns: 258738032Speter** A list of aliases for this host. 258838032Speter** 258938032Speter** Side Effects: 259038032Speter** Adds numeric codes to $=w. 259138032Speter*/ 259238032Speter 259338032Speterstruct hostent * 259438032Spetermyhostname(hostbuf, size) 259538032Speter char hostbuf[]; 259638032Speter int size; 259738032Speter{ 259838032Speter register struct hostent *hp; 259938032Speter 260073188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 260164562Sgshapiro (void) strlcpy(hostbuf, "localhost", size); 260264562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 260380785Sgshapiro# if NETINET && NETINET6 260480785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 260580785Sgshapiro { 260680785Sgshapiro /* 260780785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 260880785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 260980785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 261080785Sgshapiro */ 261180785Sgshapiro 261280785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 261380785Sgshapiro } 261480785Sgshapiro# endif /* NETINET && NETINET6 */ 261580785Sgshapiro 261638032Speter if (hp == NULL) 261738032Speter return NULL; 261838032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 261964562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 262064562Sgshapiro 262164562Sgshapiro# if NETINFO 262264562Sgshapiro if (strchr(hostbuf, '.') == NULL) 262338032Speter { 262464562Sgshapiro char *domainname; 262564562Sgshapiro 262664562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 262764562Sgshapiro "domain", '\0'); 262864562Sgshapiro if (domainname != NULL && 262964562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 263064562Sgshapiro { 263164562Sgshapiro (void) strlcat(hostbuf, ".", size); 263264562Sgshapiro (void) strlcat(hostbuf, domainname, size); 263364562Sgshapiro } 263438032Speter } 263564562Sgshapiro# endif /* NETINFO */ 263638032Speter 263738032Speter /* 263838032Speter ** If there is still no dot in the name, try looking for a 263938032Speter ** dotted alias. 264038032Speter */ 264138032Speter 264238032Speter if (strchr(hostbuf, '.') == NULL) 264338032Speter { 264438032Speter char **ha; 264538032Speter 264664562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 264738032Speter { 264838032Speter if (strchr(*ha, '.') != NULL) 264938032Speter { 265064562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 265138032Speter hostbuf[size - 1] = '\0'; 265238032Speter break; 265338032Speter } 265438032Speter } 265538032Speter } 265638032Speter 265738032Speter /* 265838032Speter ** If _still_ no dot, wait for a while and try again -- it is 265938032Speter ** possible that some service is starting up. This can result 266038032Speter ** in excessive delays if the system is badly configured, but 266138032Speter ** there really isn't a way around that, particularly given that 266238032Speter ** the config file hasn't been read at this point. 266338032Speter ** All in all, a bit of a mess. 266438032Speter */ 266538032Speter 266638032Speter if (strchr(hostbuf, '.') == NULL && 266738032Speter !getcanonname(hostbuf, size, TRUE)) 266838032Speter { 266938032Speter sm_syslog(LOG_CRIT, NOQID, 267064562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 267164562Sgshapiro hostbuf); 267238032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 267338032Speter hostbuf); 267464562Sgshapiro (void) sleep(60); 267538032Speter if (!getcanonname(hostbuf, size, TRUE)) 267638032Speter { 267738032Speter sm_syslog(LOG_ALERT, NOQID, 267864562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 267964562Sgshapiro hostbuf); 268038032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 268138032Speter hostbuf); 268238032Speter } 268338032Speter } 268464562Sgshapiro return hp; 268538032Speter} 268638032Speter/* 268738032Speter** ADDRCMP -- compare two host addresses 268838032Speter** 268938032Speter** Parameters: 269038032Speter** hp -- hostent structure for the first address 269138032Speter** ha -- actual first address 269238032Speter** sa -- second address 269338032Speter** 269438032Speter** Returns: 269538032Speter** 0 -- if ha and sa match 269638032Speter** else -- they don't match 269738032Speter*/ 269838032Speter 269964562Sgshapirostatic int 270038032Speteraddrcmp(hp, ha, sa) 270138032Speter struct hostent *hp; 270238032Speter char *ha; 270338032Speter SOCKADDR *sa; 270438032Speter{ 270564562Sgshapiro# if NETINET6 270664562Sgshapiro u_char *a; 270764562Sgshapiro# endif /* NETINET6 */ 270864562Sgshapiro 270938032Speter switch (sa->sa.sa_family) 271038032Speter { 271164562Sgshapiro# if NETINET 271238032Speter case AF_INET: 271338032Speter if (hp->h_addrtype == AF_INET) 271464562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 271538032Speter break; 271664562Sgshapiro# endif /* NETINET */ 271738032Speter 271864562Sgshapiro# if NETINET6 271964562Sgshapiro case AF_INET6: 272064562Sgshapiro a = (u_char *) &sa->sin6.sin6_addr; 272164562Sgshapiro 272264562Sgshapiro /* Straight binary comparison */ 272364562Sgshapiro if (hp->h_addrtype == AF_INET6) 272464562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 272564562Sgshapiro 272664562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 272764562Sgshapiro if (hp->h_addrtype == AF_INET && 272864562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 272964562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 273064562Sgshapiro break; 273164562Sgshapiro# endif /* NETINET6 */ 273238032Speter } 273338032Speter return -1; 273438032Speter} 273538032Speter/* 273664562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 273738032Speter** 273838032Speter** Uses RFC1413 protocol to try to get info from the other end. 273938032Speter** 274038032Speter** Parameters: 274138032Speter** fd -- the descriptor 274238032Speter** may_be_forged -- an outage that is set to TRUE if the 274338032Speter** forward lookup of RealHostName does not match 274438032Speter** RealHostAddr; set to FALSE if they do match. 274538032Speter** 274638032Speter** Returns: 274738032Speter** The user@host information associated with this descriptor. 274838032Speter*/ 274938032Speter 275038032Speterstatic jmp_buf CtxAuthTimeout; 275138032Speter 275238032Speterstatic void 275338032Speterauthtimeout() 275438032Speter{ 275577349Sgshapiro /* 275677349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 275777349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 275877349Sgshapiro ** DOING. 275977349Sgshapiro */ 276077349Sgshapiro 276177349Sgshapiro errno = ETIMEDOUT; 276238032Speter longjmp(CtxAuthTimeout, 1); 276338032Speter} 276438032Speter 276538032Speterchar * 276638032Spetergetauthinfo(fd, may_be_forged) 276738032Speter int fd; 276838032Speter bool *may_be_forged; 276938032Speter{ 277066494Sgshapiro volatile u_short port = 0; 277138032Speter SOCKADDR_LEN_T falen; 277238032Speter register char *volatile p = NULL; 277338032Speter SOCKADDR la; 277438032Speter SOCKADDR_LEN_T lalen; 277538032Speter register struct servent *sp; 277638032Speter volatile int s; 277738032Speter int i = 0; 277838032Speter EVENT *ev; 277938032Speter int nleft; 278038032Speter struct hostent *hp; 278138032Speter char *ostype = NULL; 278238032Speter char **ha; 278338032Speter char ibuf[MAXNAME + 1]; 278438032Speter static char hbuf[MAXNAME * 2 + 11]; 278538032Speter 278638032Speter *may_be_forged = FALSE; 278738032Speter falen = sizeof RealHostAddr; 278838032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 278938032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 279038032Speter { 279164562Sgshapiro if (i < 0) 279264562Sgshapiro { 279364562Sgshapiro /* 279464562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 279564562Sgshapiro ** errno in this case, so a mis-report doesn't 279664562Sgshapiro ** happen later. 279764562Sgshapiro */ 279864562Sgshapiro if (errno != ENOTSOCK) 279964562Sgshapiro return NULL; 280064562Sgshapiro errno = 0; 280164562Sgshapiro } 280238032Speter (void) snprintf(hbuf, sizeof hbuf, "%s@localhost", 280371345Sgshapiro RealUserName); 280438032Speter if (tTd(9, 1)) 280564562Sgshapiro dprintf("getauthinfo: %s\n", hbuf); 280638032Speter return hbuf; 280738032Speter } 280838032Speter 280938032Speter if (RealHostName == NULL) 281038032Speter { 281138032Speter /* translate that to a host name */ 281238032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 281338032Speter if (strlen(RealHostName) > MAXNAME) 281442575Speter RealHostName[MAXNAME] = '\0'; 281538032Speter } 281638032Speter 281738032Speter /* cross check RealHostName with forward DNS lookup */ 281838032Speter if (anynet_ntoa(&RealHostAddr)[0] == '[' || 281938032Speter RealHostName[0] == '[') 282038032Speter { 282138032Speter /* 282242575Speter ** address is not a socket or have an 282342575Speter ** IP address with no forward lookup 282438032Speter */ 282538032Speter *may_be_forged = FALSE; 282638032Speter } 282738032Speter else 282838032Speter { 282980785Sgshapiro int family; 283080785Sgshapiro 283180785Sgshapiro family = RealHostAddr.sa.sa_family; 283280785Sgshapiro# if NETINET6 && NEEDSGETIPNODE 283380785Sgshapiro /* 283480785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 283580785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 283680785Sgshapiro ** address(es) for addrcmp() to compare against 283780785Sgshapiro ** RealHostAddr. 283880785Sgshapiro ** 283980785Sgshapiro ** Actually, we only need to do this for systems 284080785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 284180785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 284280785Sgshapiro ** flag. A better fix to this problem is to add this 284380785Sgshapiro ** functionality to our stub getipnodebyname(). 284480785Sgshapiro */ 284580785Sgshapiro 284680785Sgshapiro if (family == AF_INET6 && 284780785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 284880785Sgshapiro family = AF_INET; 284980785Sgshapiro# endif /* NETINET6 && NEEDSGETIPNODE */ 285080785Sgshapiro 285138032Speter /* try to match the reverse against the forward lookup */ 285280785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 285338032Speter if (hp == NULL) 285438032Speter *may_be_forged = TRUE; 285538032Speter else 285638032Speter { 285738032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 285838032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 285938032Speter break; 286038032Speter *may_be_forged = *ha == NULL; 286171345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 286271345Sgshapiro freehostent(hp); 286371345Sgshapiro hp = NULL; 286471345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 286538032Speter } 286638032Speter } 286738032Speter 286838032Speter if (TimeOuts.to_ident == 0) 286938032Speter goto noident; 287038032Speter 287138032Speter lalen = sizeof la; 287264562Sgshapiro switch (RealHostAddr.sa.sa_family) 287338032Speter { 287464562Sgshapiro# if NETINET 287564562Sgshapiro case AF_INET: 287664562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 287764562Sgshapiro lalen <= 0 || 287864562Sgshapiro la.sa.sa_family != AF_INET) 287964562Sgshapiro { 288064562Sgshapiro /* no ident info */ 288164562Sgshapiro goto noident; 288264562Sgshapiro } 288364562Sgshapiro port = RealHostAddr.sin.sin_port; 288438032Speter 288564562Sgshapiro /* create ident query */ 288664562Sgshapiro (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 288764562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 288864562Sgshapiro ntohs(la.sin.sin_port)); 288938032Speter 289064562Sgshapiro /* create local address */ 289164562Sgshapiro la.sin.sin_port = 0; 289238032Speter 289364562Sgshapiro /* create foreign address */ 289464562Sgshapiro# ifdef NO_GETSERVBYNAME 289538032Speter RealHostAddr.sin.sin_port = htons(113); 289664562Sgshapiro# else /* NO_GETSERVBYNAME */ 289764562Sgshapiro sp = getservbyname("auth", "tcp"); 289864562Sgshapiro if (sp != NULL) 289964562Sgshapiro RealHostAddr.sin.sin_port = sp->s_port; 290064562Sgshapiro else 290164562Sgshapiro RealHostAddr.sin.sin_port = htons(113); 290264562Sgshapiro break; 290364562Sgshapiro# endif /* NO_GETSERVBYNAME */ 290464562Sgshapiro# endif /* NETINET */ 290538032Speter 290664562Sgshapiro# if NETINET6 290764562Sgshapiro case AF_INET6: 290864562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 290964562Sgshapiro lalen <= 0 || 291064562Sgshapiro la.sa.sa_family != AF_INET6) 291164562Sgshapiro { 291264562Sgshapiro /* no ident info */ 291364562Sgshapiro goto noident; 291464562Sgshapiro } 291564562Sgshapiro port = RealHostAddr.sin6.sin6_port; 291664562Sgshapiro 291764562Sgshapiro /* create ident query */ 291864562Sgshapiro (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 291964562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 292064562Sgshapiro ntohs(la.sin6.sin6_port)); 292164562Sgshapiro 292264562Sgshapiro /* create local address */ 292364562Sgshapiro la.sin6.sin6_port = 0; 292464562Sgshapiro 292564562Sgshapiro /* create foreign address */ 292664562Sgshapiro# ifdef NO_GETSERVBYNAME 292764562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 292864562Sgshapiro# else /* NO_GETSERVBYNAME */ 292964562Sgshapiro sp = getservbyname("auth", "tcp"); 293064562Sgshapiro if (sp != NULL) 293164562Sgshapiro RealHostAddr.sin6.sin6_port = sp->s_port; 293264562Sgshapiro else 293364562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 293464562Sgshapiro break; 293564562Sgshapiro# endif /* NO_GETSERVBYNAME */ 293664562Sgshapiro# endif /* NETINET6 */ 293764562Sgshapiro default: 293864562Sgshapiro /* no ident info */ 293964562Sgshapiro goto noident; 294064562Sgshapiro } 294164562Sgshapiro 294238032Speter s = -1; 294338032Speter if (setjmp(CtxAuthTimeout) != 0) 294438032Speter { 294538032Speter if (s >= 0) 294638032Speter (void) close(s); 294738032Speter goto noident; 294838032Speter } 294938032Speter 295038032Speter /* put a timeout around the whole thing */ 295138032Speter ev = setevent(TimeOuts.to_ident, authtimeout, 0); 295238032Speter 295364562Sgshapiro 295438032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 295564562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 295638032Speter if (s < 0) 295738032Speter { 295838032Speter clrevent(ev); 295938032Speter goto noident; 296038032Speter } 296164562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 296264562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 296338032Speter { 296438032Speter goto closeident; 296538032Speter } 296638032Speter 296738032Speter if (tTd(9, 10)) 296864562Sgshapiro dprintf("getauthinfo: sent %s", ibuf); 296938032Speter 297038032Speter /* send query */ 297138032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 297238032Speter goto closeident; 297338032Speter 297438032Speter /* get result */ 297538032Speter p = &ibuf[0]; 297638032Speter nleft = sizeof ibuf - 1; 297738032Speter while ((i = read(s, p, nleft)) > 0) 297838032Speter { 297938032Speter p += i; 298038032Speter nleft -= i; 298138032Speter *p = '\0'; 298238032Speter if (strchr(ibuf, '\n') != NULL) 298338032Speter break; 298438032Speter } 298538032Speter (void) close(s); 298638032Speter clrevent(ev); 298738032Speter if (i < 0 || p == &ibuf[0]) 298838032Speter goto noident; 298938032Speter 299038032Speter if (*--p == '\n' && *--p == '\r') 299138032Speter p--; 299238032Speter *++p = '\0'; 299338032Speter 299438032Speter if (tTd(9, 3)) 299564562Sgshapiro dprintf("getauthinfo: got %s\n", ibuf); 299638032Speter 299738032Speter /* parse result */ 299838032Speter p = strchr(ibuf, ':'); 299938032Speter if (p == NULL) 300038032Speter { 300138032Speter /* malformed response */ 300238032Speter goto noident; 300338032Speter } 300438032Speter while (isascii(*++p) && isspace(*p)) 300538032Speter continue; 300638032Speter if (strncasecmp(p, "userid", 6) != 0) 300738032Speter { 300838032Speter /* presumably an error string */ 300938032Speter goto noident; 301038032Speter } 301138032Speter p += 6; 301238032Speter while (isascii(*p) && isspace(*p)) 301338032Speter p++; 301438032Speter if (*p++ != ':') 301538032Speter { 301638032Speter /* either useridxx or malformed response */ 301738032Speter goto noident; 301838032Speter } 301938032Speter 302038032Speter /* p now points to the OSTYPE field */ 302138032Speter while (isascii(*p) && isspace(*p)) 302238032Speter p++; 302338032Speter ostype = p; 302438032Speter p = strchr(p, ':'); 302538032Speter if (p == NULL) 302638032Speter { 302738032Speter /* malformed response */ 302838032Speter goto noident; 302938032Speter } 303038032Speter else 303138032Speter { 303238032Speter char *charset; 303338032Speter 303438032Speter *p = '\0'; 303538032Speter charset = strchr(ostype, ','); 303638032Speter if (charset != NULL) 303738032Speter *charset = '\0'; 303838032Speter } 303938032Speter 304038032Speter /* 1413 says don't do this -- but it's broken otherwise */ 304138032Speter while (isascii(*++p) && isspace(*p)) 304238032Speter continue; 304338032Speter 304438032Speter /* p now points to the authenticated name -- copy carefully */ 304538032Speter if (strncasecmp(ostype, "other", 5) == 0 && 304638032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 304738032Speter { 304838032Speter snprintf(hbuf, sizeof hbuf, "IDENT:"); 304938032Speter cleanstrcpy(&hbuf[6], p, MAXNAME); 305038032Speter } 305138032Speter else 305238032Speter cleanstrcpy(hbuf, p, MAXNAME); 305338032Speter i = strlen(hbuf); 305438032Speter snprintf(&hbuf[i], sizeof hbuf - i, "@%s", 305538032Speter RealHostName == NULL ? "localhost" : RealHostName); 305638032Speter goto postident; 305738032Speter 305838032Spetercloseident: 305938032Speter (void) close(s); 306038032Speter clrevent(ev); 306138032Speter 306238032Speternoident: 306364562Sgshapiro /* put back the original incoming port */ 306464562Sgshapiro switch (RealHostAddr.sa.sa_family) 306564562Sgshapiro { 306664562Sgshapiro# if NETINET 306764562Sgshapiro case AF_INET: 306864562Sgshapiro if (port > 0) 306964562Sgshapiro RealHostAddr.sin.sin_port = port; 307064562Sgshapiro break; 307164562Sgshapiro# endif /* NETINET */ 307264562Sgshapiro 307364562Sgshapiro# if NETINET6 307464562Sgshapiro case AF_INET6: 307564562Sgshapiro if (port > 0) 307664562Sgshapiro RealHostAddr.sin6.sin6_port = port; 307764562Sgshapiro break; 307864562Sgshapiro# endif /* NETINET6 */ 307964562Sgshapiro } 308064562Sgshapiro 308138032Speter if (RealHostName == NULL) 308238032Speter { 308338032Speter if (tTd(9, 1)) 308464562Sgshapiro dprintf("getauthinfo: NULL\n"); 308538032Speter return NULL; 308638032Speter } 308738032Speter snprintf(hbuf, sizeof hbuf, "%s", RealHostName); 308838032Speter 308938032Speterpostident: 309064562Sgshapiro# if IP_SRCROUTE 309164562Sgshapiro# ifndef GET_IPOPT_DST 309264562Sgshapiro# define GET_IPOPT_DST(dst) (dst) 309364562Sgshapiro# endif /* ! GET_IPOPT_DST */ 309438032Speter /* 309538032Speter ** Extract IP source routing information. 309638032Speter ** 309738032Speter ** Format of output for a connection from site a through b 309838032Speter ** through c to d: 309938032Speter ** loose: @site-c@site-b:site-a 310038032Speter ** strict: !@site-c@site-b:site-a 310138032Speter ** 310238032Speter ** o - pointer within ipopt_list structure. 310338032Speter ** q - pointer within ls/ss rr route data 310438032Speter ** p - pointer to hbuf 310538032Speter */ 310638032Speter 310738032Speter if (RealHostAddr.sa.sa_family == AF_INET) 310838032Speter { 310938032Speter SOCKOPT_LEN_T ipoptlen; 311038032Speter int j; 311138032Speter u_char *q; 311238032Speter u_char *o; 311338032Speter int l; 311464562Sgshapiro struct IPOPTION ipopt; 311538032Speter 311638032Speter ipoptlen = sizeof ipopt; 311738032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 311838032Speter (char *) &ipopt, &ipoptlen) < 0) 311938032Speter goto noipsr; 312038032Speter if (ipoptlen == 0) 312138032Speter goto noipsr; 312264562Sgshapiro o = (u_char *) ipopt.IP_LIST; 312338032Speter while (o != NULL && o < (u_char *) &ipopt + ipoptlen) 312438032Speter { 312538032Speter switch (*o) 312638032Speter { 312764562Sgshapiro case IPOPT_EOL: 312838032Speter o = NULL; 312938032Speter break; 313038032Speter 313138032Speter case IPOPT_NOP: 313238032Speter o++; 313338032Speter break; 313438032Speter 313538032Speter case IPOPT_SSRR: 313638032Speter case IPOPT_LSRR: 313738032Speter /* 313838032Speter ** Source routing. 313938032Speter ** o[0] is the option type (loose/strict). 314038032Speter ** o[1] is the length of this option, 314138032Speter ** including option type and 314238032Speter ** length. 314338032Speter ** o[2] is the pointer into the route 314438032Speter ** data. 314538032Speter ** o[3] begins the route data. 314638032Speter */ 314738032Speter 314838032Speter p = &hbuf[strlen(hbuf)]; 314938032Speter l = sizeof hbuf - (hbuf - p) - 6; 315038032Speter snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s", 315138032Speter *o == IPOPT_SSRR ? "!" : "", 315238032Speter l > 240 ? 120 : l / 2, 315364562Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 315438032Speter i = strlen(p); 315538032Speter p += i; 315638032Speter l -= strlen(p); 315738032Speter 315838032Speter j = o[1] / sizeof(struct in_addr) - 1; 315938032Speter 316038032Speter /* q skips length and router pointer to data */ 316138032Speter q = &o[3]; 316238032Speter for ( ; j >= 0; j--) 316338032Speter { 316464562Sgshapiro struct in_addr addr; 316564562Sgshapiro 316638032Speter memcpy(&addr, q, sizeof(addr)); 316738032Speter snprintf(p, SPACELEFT(hbuf, p), 316864562Sgshapiro "%c%.*s", 316964562Sgshapiro j != 0 ? '@' : ':', 317064562Sgshapiro l > 240 ? 120 : 317164562Sgshapiro j == 0 ? l : l / 2, 317264562Sgshapiro inet_ntoa(addr)); 317338032Speter i = strlen(p); 317438032Speter p += i; 317538032Speter l -= i + 1; 317664562Sgshapiro q += sizeof(struct in_addr); 317738032Speter } 317838032Speter o += o[1]; 317938032Speter break; 318038032Speter 318138032Speter default: 318238032Speter /* Skip over option */ 318338032Speter o += o[1]; 318438032Speter break; 318538032Speter } 318638032Speter } 318738032Speter snprintf(p, SPACELEFT(hbuf, p), "]"); 318838032Speter goto postipsr; 318938032Speter } 319038032Speter 319138032Speternoipsr: 319264562Sgshapiro# endif /* IP_SRCROUTE */ 319338032Speter if (RealHostName != NULL && RealHostName[0] != '[') 319438032Speter { 319538032Speter p = &hbuf[strlen(hbuf)]; 319638032Speter (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 319738032Speter anynet_ntoa(&RealHostAddr)); 319838032Speter } 319938032Speter if (*may_be_forged) 320038032Speter { 320138032Speter p = &hbuf[strlen(hbuf)]; 320238032Speter (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)"); 320338032Speter } 320438032Speter 320564562Sgshapiro# if IP_SRCROUTE 320638032Speterpostipsr: 320764562Sgshapiro# endif /* IP_SRCROUTE */ 320838032Speter if (tTd(9, 1)) 320964562Sgshapiro dprintf("getauthinfo: %s\n", hbuf); 321064562Sgshapiro 321164562Sgshapiro /* put back the original incoming port */ 321264562Sgshapiro switch (RealHostAddr.sa.sa_family) 321364562Sgshapiro { 321464562Sgshapiro# if NETINET 321564562Sgshapiro case AF_INET: 321664562Sgshapiro if (port > 0) 321764562Sgshapiro RealHostAddr.sin.sin_port = port; 321864562Sgshapiro break; 321964562Sgshapiro# endif /* NETINET */ 322064562Sgshapiro 322164562Sgshapiro# if NETINET6 322264562Sgshapiro case AF_INET6: 322364562Sgshapiro if (port > 0) 322464562Sgshapiro RealHostAddr.sin6.sin6_port = port; 322564562Sgshapiro break; 322664562Sgshapiro# endif /* NETINET6 */ 322764562Sgshapiro } 322864562Sgshapiro 322938032Speter return hbuf; 323038032Speter} 323138032Speter/* 323238032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 323338032Speter** 323438032Speter** Parameters: 323538032Speter** map -- a pointer to this map. 323638032Speter** name -- the (presumably unqualified) hostname. 323738032Speter** av -- unused -- for compatibility with other mapping 323838032Speter** functions. 323938032Speter** statp -- an exit status (out parameter) -- set to 324038032Speter** EX_TEMPFAIL if the name server is unavailable. 324138032Speter** 324238032Speter** Returns: 324338032Speter** The mapping, if found. 324438032Speter** NULL if no mapping found. 324538032Speter** 324638032Speter** Side Effects: 324738032Speter** Looks up the host specified in hbuf. If it is not 324838032Speter** the canonical name for that host, return the canonical 324938032Speter** name (unless MF_MATCHONLY is set, which will cause the 325038032Speter** status only to be returned). 325138032Speter*/ 325238032Speter 325338032Speterchar * 325438032Speterhost_map_lookup(map, name, av, statp) 325538032Speter MAP *map; 325638032Speter char *name; 325738032Speter char **av; 325838032Speter int *statp; 325938032Speter{ 326038032Speter register struct hostent *hp; 326164562Sgshapiro# if NETINET 326238032Speter struct in_addr in_addr; 326364562Sgshapiro# endif /* NETINET */ 326464562Sgshapiro# if NETINET6 326564562Sgshapiro struct in6_addr in6_addr; 326664562Sgshapiro# endif /* NETINET6 */ 326764562Sgshapiro char *cp, *ans = NULL; 326838032Speter register STAB *s; 326938032Speter char hbuf[MAXNAME + 1]; 327038032Speter 327138032Speter /* 327238032Speter ** See if we have already looked up this name. If so, just 327338032Speter ** return it. 327438032Speter */ 327538032Speter 327638032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 327738032Speter if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 327838032Speter { 327938032Speter if (tTd(9, 1)) 328064562Sgshapiro dprintf("host_map_lookup(%s) => CACHE %s\n", 328164562Sgshapiro name, 328264562Sgshapiro s->s_namecanon.nc_cname == NULL 328338032Speter ? "NULL" 328438032Speter : s->s_namecanon.nc_cname); 328538032Speter errno = s->s_namecanon.nc_errno; 328664562Sgshapiro# if NAMED_BIND 328773188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 328864562Sgshapiro# endif /* NAMED_BIND */ 328938032Speter *statp = s->s_namecanon.nc_stat; 329038032Speter if (*statp == EX_TEMPFAIL) 329138032Speter { 329238032Speter CurEnv->e_status = "4.4.3"; 329338032Speter message("851 %s: Name server timeout", 329438032Speter shortenstring(name, 33)); 329538032Speter } 329638032Speter if (*statp != EX_OK) 329738032Speter return NULL; 329838032Speter if (s->s_namecanon.nc_cname == NULL) 329938032Speter { 330038032Speter syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", 330164562Sgshapiro name, 330264562Sgshapiro s->s_namecanon.nc_errno, 330364562Sgshapiro s->s_namecanon.nc_herrno); 330438032Speter return NULL; 330538032Speter } 330638032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 330738032Speter cp = map_rewrite(map, name, strlen(name), NULL); 330838032Speter else 330938032Speter cp = map_rewrite(map, 331038032Speter s->s_namecanon.nc_cname, 331138032Speter strlen(s->s_namecanon.nc_cname), 331238032Speter av); 331338032Speter return cp; 331438032Speter } 331538032Speter 331638032Speter /* 331738032Speter ** If we are running without a regular network connection (usually 331838032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 331938032Speter ** lookups because those could try to connect to a server. 332038032Speter */ 332138032Speter 332264562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 332364562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 332438032Speter { 332538032Speter if (tTd(9, 1)) 332664562Sgshapiro dprintf("host_map_lookup(%s) => DEFERRED\n", name); 332738032Speter *statp = EX_TEMPFAIL; 332838032Speter return NULL; 332938032Speter } 333038032Speter 333138032Speter /* 333238032Speter ** If first character is a bracket, then it is an address 333338032Speter ** lookup. Address is copied into a temporary buffer to 333438032Speter ** strip the brackets and to preserve name if address is 333538032Speter ** unknown. 333638032Speter */ 333738032Speter 333864562Sgshapiro if (tTd(9, 1)) 333964562Sgshapiro dprintf("host_map_lookup(%s) => ", name); 334038032Speter if (*name != '[') 334138032Speter { 334238032Speter snprintf(hbuf, sizeof hbuf, "%s", name); 334338032Speter if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX)) 334464562Sgshapiro ans = hbuf; 334564562Sgshapiro } 334664562Sgshapiro else 334764562Sgshapiro { 334864562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 334971345Sgshapiro { 335071345Sgshapiro if (tTd(9, 1)) 335171345Sgshapiro dprintf("FAILED\n"); 335264562Sgshapiro return NULL; 335371345Sgshapiro } 335464562Sgshapiro *cp = '\0'; 335564562Sgshapiro 335664562Sgshapiro hp = NULL; 335764562Sgshapiro# if NETINET 335864562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 335964562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 336064562Sgshapiro INADDRSZ, AF_INET); 336164562Sgshapiro# endif /* NETINET */ 336264562Sgshapiro# if NETINET6 336364562Sgshapiro if (hp == NULL && 336464562Sgshapiro inet_pton(AF_INET6, &name[1], &in6_addr) == 1) 336564562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 336664562Sgshapiro IN6ADDRSZ, AF_INET6); 336764562Sgshapiro# endif /* NETINET6 */ 336864562Sgshapiro *cp = ']'; 336964562Sgshapiro 337064562Sgshapiro if (hp != NULL) 337138032Speter { 337264562Sgshapiro /* found a match -- copy out */ 337364562Sgshapiro ans = denlstring((char *) hp->h_name, TRUE, TRUE); 337471345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 337571345Sgshapiro freehostent(hp); 337671345Sgshapiro hp = NULL; 337771345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 337838032Speter } 337964562Sgshapiro } 338038032Speter 338164562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 338238032Speter 338364562Sgshapiro /* Found an answer */ 338464562Sgshapiro if (ans != NULL) 338564562Sgshapiro { 338664562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 338764562Sgshapiro s->s_namecanon.nc_cname = newstr(ans); 338864562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 338964562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 339064562Sgshapiro else 339164562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 339271345Sgshapiro if (tTd(9, 1)) 339371345Sgshapiro dprintf("FOUND %s\n", ans); 339464562Sgshapiro return cp; 339538032Speter } 339638032Speter 339764562Sgshapiro 339864562Sgshapiro /* No match found */ 339938032Speter s->s_namecanon.nc_errno = errno; 340064562Sgshapiro# if NAMED_BIND 340138032Speter s->s_namecanon.nc_herrno = h_errno; 340264562Sgshapiro if (tTd(9, 1)) 340364562Sgshapiro dprintf("FAIL (%d)\n", h_errno); 340464562Sgshapiro switch (h_errno) 340538032Speter { 340664562Sgshapiro case TRY_AGAIN: 340764562Sgshapiro if (UseNameServer) 340864562Sgshapiro { 340964562Sgshapiro CurEnv->e_status = "4.4.3"; 341064562Sgshapiro message("851 %s: Name server timeout", 341164562Sgshapiro shortenstring(name, 33)); 341264562Sgshapiro } 341364562Sgshapiro *statp = EX_TEMPFAIL; 341464562Sgshapiro break; 341564562Sgshapiro 341664562Sgshapiro case HOST_NOT_FOUND: 341764562Sgshapiro case NO_DATA: 341864562Sgshapiro *statp = EX_NOHOST; 341964562Sgshapiro break; 342064562Sgshapiro 342164562Sgshapiro case NO_RECOVERY: 342264562Sgshapiro *statp = EX_SOFTWARE; 342364562Sgshapiro break; 342464562Sgshapiro 342564562Sgshapiro default: 342664562Sgshapiro *statp = EX_UNAVAILABLE; 342764562Sgshapiro break; 342838032Speter } 342964562Sgshapiro# else /* NAMED_BIND */ 343064562Sgshapiro if (tTd(9, 1)) 343164562Sgshapiro dprintf("FAIL\n"); 343264562Sgshapiro *statp = EX_NOHOST; 343364562Sgshapiro# endif /* NAMED_BIND */ 343464562Sgshapiro s->s_namecanon.nc_stat = *statp; 343564562Sgshapiro return NULL; 343638032Speter} 343764562Sgshapiro#else /* DAEMON */ 343838032Speter/* code for systems without sophisticated networking */ 343938032Speter 344038032Speter/* 344138032Speter** MYHOSTNAME -- stub version for case of no daemon code. 344238032Speter** 344338032Speter** Can't convert to upper case here because might be a UUCP name. 344438032Speter** 344538032Speter** Mark, you can change this to be anything you want...... 344638032Speter*/ 344738032Speter 344838032Speterchar ** 344938032Spetermyhostname(hostbuf, size) 345038032Speter char hostbuf[]; 345138032Speter int size; 345238032Speter{ 345338032Speter register FILE *f; 345438032Speter 345538032Speter hostbuf[0] = '\0'; 345638032Speter f = fopen("/usr/include/whoami", "r"); 345738032Speter if (f != NULL) 345838032Speter { 345938032Speter (void) fgets(hostbuf, size, f); 346038032Speter fixcrlf(hostbuf, TRUE); 346138032Speter (void) fclose(f); 346238032Speter } 346373188Sgshapiro if (hostbuf[0] == '\0') 346473188Sgshapiro (void) strlcpy(hostbuf, "localhost", size); 346564562Sgshapiro return NULL; 346638032Speter} 346738032Speter/* 346864562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 346938032Speter** 347038032Speter** Parameters: 347138032Speter** fd -- the descriptor 347238032Speter** may_be_forged -- an outage that is set to TRUE if the 347338032Speter** forward lookup of RealHostName does not match 347438032Speter** RealHostAddr; set to FALSE if they do match. 347538032Speter** 347638032Speter** Returns: 347738032Speter** The host name associated with this descriptor, if it can 347838032Speter** be determined. 347938032Speter** NULL otherwise. 348038032Speter** 348138032Speter** Side Effects: 348238032Speter** none 348338032Speter*/ 348438032Speter 348538032Speterchar * 348638032Spetergetauthinfo(fd, may_be_forged) 348738032Speter int fd; 348838032Speter bool *may_be_forged; 348938032Speter{ 349038032Speter *may_be_forged = FALSE; 349138032Speter return NULL; 349238032Speter} 349338032Speter/* 349464562Sgshapiro** HOST_MAP_LOOKUP -- turn a hostname into canonical form 349538032Speter** 349638032Speter** Parameters: 349738032Speter** map -- a pointer to the database map. 349838032Speter** name -- a buffer containing a hostname. 349938032Speter** avp -- a pointer to a (cf file defined) argument vector. 350038032Speter** statp -- an exit status (out parameter). 350138032Speter** 350238032Speter** Returns: 350338032Speter** mapped host name 350438032Speter** FALSE otherwise. 350538032Speter** 350638032Speter** Side Effects: 350738032Speter** Looks up the host specified in name. If it is not 350838032Speter** the canonical name for that host, replace it with 350938032Speter** the canonical name. If the name is unknown, or it 351038032Speter** is already the canonical name, leave it unchanged. 351138032Speter*/ 351238032Speter 351338032Speter/*ARGSUSED*/ 351438032Speterchar * 351538032Speterhost_map_lookup(map, name, avp, statp) 351638032Speter MAP *map; 351738032Speter char *name; 351838032Speter char **avp; 351938032Speter char *statp; 352038032Speter{ 352164562Sgshapiro register struct hostent *hp = NULL; 352238032Speter char *cp; 352338032Speter 352464562Sgshapiro hp = sm_gethostbyname(name, InetMode); 352564562Sgshapiro if (hp == NULL && InetMode != AF_INET) 352664562Sgshapiro hp = sm_gethostbyname(name, AF_INET); 352738032Speter if (hp == NULL) 352838032Speter { 352964562Sgshapiro# if NAMED_BIND 353064562Sgshapiro if (tTd(9, 1)) 353164562Sgshapiro dprintf("FAIL (%d)\n", h_errno); 353264562Sgshapiro switch (h_errno) 353364562Sgshapiro { 353464562Sgshapiro case TRY_AGAIN: 353564562Sgshapiro if (UseNameServer) 353664562Sgshapiro { 353764562Sgshapiro CurEnv->e_status = "4.4.3"; 353864562Sgshapiro message("851 %s: Name server timeout", 353964562Sgshapiro shortenstring(name, 33)); 354064562Sgshapiro } 354164562Sgshapiro *statp = EX_TEMPFAIL; 354264562Sgshapiro break; 354364562Sgshapiro 354464562Sgshapiro case HOST_NOT_FOUND: 354564562Sgshapiro case NO_DATA: 354664562Sgshapiro *statp = EX_NOHOST; 354764562Sgshapiro break; 354864562Sgshapiro 354964562Sgshapiro case NO_RECOVERY: 355064562Sgshapiro *statp = EX_SOFTWARE; 355164562Sgshapiro break; 355264562Sgshapiro 355364562Sgshapiro default: 355464562Sgshapiro *statp = EX_UNAVAILABLE; 355564562Sgshapiro break; 355664562Sgshapiro } 355764562Sgshapiro#else /* NAMED_BIND */ 355838032Speter *statp = EX_NOHOST; 355964562Sgshapiro#endif /* NAMED_BIND */ 356038032Speter return NULL; 356138032Speter } 356238032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 356338032Speter cp = map_rewrite(map, name, strlen(name), NULL); 356438032Speter else 356538032Speter cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp); 356671345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 356771345Sgshapiro freehostent(hp); 356871345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 356938032Speter return cp; 357038032Speter} 357138032Speter 357238032Speter#endif /* DAEMON */ 357338032Speter/* 357438032Speter** HOST_MAP_INIT -- initialize host class structures 357538032Speter*/ 357638032Speter 357738032Speterbool 357838032Speterhost_map_init(map, args) 357938032Speter MAP *map; 358038032Speter char *args; 358138032Speter{ 358238032Speter register char *p = args; 358338032Speter 358438032Speter for (;;) 358538032Speter { 358638032Speter while (isascii(*p) && isspace(*p)) 358738032Speter p++; 358838032Speter if (*p != '-') 358938032Speter break; 359038032Speter switch (*++p) 359138032Speter { 359238032Speter case 'a': 359338032Speter map->map_app = ++p; 359438032Speter break; 359538032Speter 359638032Speter case 'T': 359738032Speter map->map_tapp = ++p; 359838032Speter break; 359938032Speter 360038032Speter case 'm': 360138032Speter map->map_mflags |= MF_MATCHONLY; 360238032Speter break; 360338032Speter 360438032Speter case 't': 360538032Speter map->map_mflags |= MF_NODEFER; 360638032Speter break; 360764562Sgshapiro 360864562Sgshapiro case 'S': /* only for consistency */ 360964562Sgshapiro map->map_spacesub = *++p; 361064562Sgshapiro break; 361164562Sgshapiro 361264562Sgshapiro case 'D': 361364562Sgshapiro map->map_mflags |= MF_DEFER; 361464562Sgshapiro break; 361538032Speter } 361638032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 361738032Speter p++; 361838032Speter if (*p != '\0') 361938032Speter *p++ = '\0'; 362038032Speter } 362138032Speter if (map->map_app != NULL) 362238032Speter map->map_app = newstr(map->map_app); 362338032Speter if (map->map_tapp != NULL) 362438032Speter map->map_tapp = newstr(map->map_tapp); 362538032Speter return TRUE; 362638032Speter} 362764562Sgshapiro 362864562Sgshapiro#if NETINET6 362964562Sgshapiro/* 363064562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 363164562Sgshapiro** 363264562Sgshapiro** Parameters: 363364562Sgshapiro** s6a -- a pointer to an in6_addr structure. 363464562Sgshapiro** dst -- buffer to store result in 363564562Sgshapiro** dst_len -- size of dst buffer 363664562Sgshapiro** 363764562Sgshapiro** Returns: 363864562Sgshapiro** A printable version of that structure. 363964562Sgshapiro*/ 364064562Sgshapirochar * 364164562Sgshapiroanynet_ntop(s6a, dst, dst_len) 364264562Sgshapiro struct in6_addr *s6a; 364364562Sgshapiro char *dst; 364464562Sgshapiro size_t dst_len; 364564562Sgshapiro{ 364664562Sgshapiro register char *ap; 364764562Sgshapiro 364864562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 364964562Sgshapiro ap = (char *) inet_ntop(AF_INET, 365064562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 365164562Sgshapiro dst, dst_len); 365264562Sgshapiro else 365364562Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 365464562Sgshapiro return ap; 365564562Sgshapiro} 365664562Sgshapiro#endif /* NETINET6 */ 365738032Speter/* 365838032Speter** ANYNET_NTOA -- convert a network address to printable form. 365938032Speter** 366038032Speter** Parameters: 366138032Speter** sap -- a pointer to a sockaddr structure. 366238032Speter** 366338032Speter** Returns: 366438032Speter** A printable version of that sockaddr. 366538032Speter*/ 366638032Speter 366738032Speter#ifdef USE_SOCK_STREAM 366838032Speter 366964562Sgshapiro# if NETLINK 367064562Sgshapiro# include <net/if_dl.h> 367164562Sgshapiro# endif /* NETLINK */ 367238032Speter 367338032Speterchar * 367438032Speteranynet_ntoa(sap) 367538032Speter register SOCKADDR *sap; 367638032Speter{ 367738032Speter register char *bp; 367838032Speter register char *ap; 367938032Speter int l; 368038032Speter static char buf[100]; 368138032Speter 368238032Speter /* check for null/zero family */ 368338032Speter if (sap == NULL) 368438032Speter return "NULLADDR"; 368538032Speter if (sap->sa.sa_family == 0) 368638032Speter return "0"; 368738032Speter 368838032Speter switch (sap->sa.sa_family) 368938032Speter { 369064562Sgshapiro# if NETUNIX 369138032Speter case AF_UNIX: 369264562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 369364562Sgshapiro snprintf(buf, sizeof buf, "[UNIX: %.64s]", 369438032Speter sap->sunix.sun_path); 369564562Sgshapiro else 369664562Sgshapiro snprintf(buf, sizeof buf, "[UNIX: localhost]"); 369738032Speter return buf; 369864562Sgshapiro# endif /* NETUNIX */ 369938032Speter 370064562Sgshapiro# if NETINET 370138032Speter case AF_INET: 370264562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 370364562Sgshapiro# endif /* NETINET */ 370438032Speter 370564562Sgshapiro# if NETINET6 370664562Sgshapiro case AF_INET6: 370764562Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf); 370864562Sgshapiro if (ap != NULL) 370964562Sgshapiro return ap; 371064562Sgshapiro break; 371164562Sgshapiro# endif /* NETINET6 */ 371264562Sgshapiro 371364562Sgshapiro# if NETLINK 371438032Speter case AF_LINK: 371538032Speter snprintf(buf, sizeof buf, "[LINK: %s]", 371638032Speter link_ntoa((struct sockaddr_dl *) &sap->sa)); 371738032Speter return buf; 371864562Sgshapiro# endif /* NETLINK */ 371938032Speter default: 372038032Speter /* this case is needed when nothing is #defined */ 372138032Speter /* in order to keep the switch syntactically correct */ 372238032Speter break; 372338032Speter } 372438032Speter 372538032Speter /* unknown family -- just dump bytes */ 372638032Speter (void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family); 372738032Speter bp = &buf[strlen(buf)]; 372838032Speter ap = sap->sa.sa_data; 372938032Speter for (l = sizeof sap->sa.sa_data; --l >= 0; ) 373038032Speter { 373138032Speter (void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377); 373238032Speter bp += 3; 373338032Speter } 373438032Speter *--bp = '\0'; 373538032Speter return buf; 373638032Speter} 373738032Speter/* 373838032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 373938032Speter** 374038032Speter** Parameters: 374138032Speter** sap -- SOCKADDR pointer 374238032Speter** 374338032Speter** Returns: 374438032Speter** text representation of host name. 374538032Speter** 374638032Speter** Side Effects: 374738032Speter** none. 374838032Speter*/ 374938032Speter 375038032Speterchar * 375138032Speterhostnamebyanyaddr(sap) 375238032Speter register SOCKADDR *sap; 375338032Speter{ 375438032Speter register struct hostent *hp; 375564562Sgshapiro# if NAMED_BIND 375638032Speter int saveretry; 375764562Sgshapiro# endif /* NAMED_BIND */ 375864562Sgshapiro# if NETINET6 375964562Sgshapiro struct in6_addr in6_addr; 376064562Sgshapiro# endif /* NETINET6 */ 376138032Speter 376264562Sgshapiro# if NAMED_BIND 376338032Speter /* shorten name server timeout to avoid higher level timeouts */ 376438032Speter saveretry = _res.retry; 376564562Sgshapiro if (_res.retry * _res.retrans > 20) 376664562Sgshapiro _res.retry = 20 / _res.retrans; 376764562Sgshapiro# endif /* NAMED_BIND */ 376838032Speter 376938032Speter switch (sap->sa.sa_family) 377038032Speter { 377164562Sgshapiro# if NETINET 377238032Speter case AF_INET: 377338032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 377438032Speter INADDRSZ, 377538032Speter AF_INET); 377638032Speter break; 377764562Sgshapiro# endif /* NETINET */ 377838032Speter 377964562Sgshapiro# if NETINET6 378064562Sgshapiro case AF_INET6: 378164562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 378264562Sgshapiro IN6ADDRSZ, 378364562Sgshapiro AF_INET6); 378464562Sgshapiro break; 378564562Sgshapiro# endif /* NETINET6 */ 378664562Sgshapiro 378764562Sgshapiro# if NETISO 378838032Speter case AF_ISO: 378938032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 379038032Speter sizeof sap->siso.siso_addr, 379138032Speter AF_ISO); 379238032Speter break; 379364562Sgshapiro# endif /* NETISO */ 379438032Speter 379564562Sgshapiro# if NETUNIX 379638032Speter case AF_UNIX: 379738032Speter hp = NULL; 379838032Speter break; 379964562Sgshapiro# endif /* NETUNIX */ 380038032Speter 380138032Speter default: 380238032Speter hp = sm_gethostbyaddr(sap->sa.sa_data, 380338032Speter sizeof sap->sa.sa_data, 380438032Speter sap->sa.sa_family); 380538032Speter break; 380638032Speter } 380738032Speter 380864562Sgshapiro# if NAMED_BIND 380938032Speter _res.retry = saveretry; 381064562Sgshapiro# endif /* NAMED_BIND */ 381138032Speter 381264562Sgshapiro# if NETINET || NETINET6 381364562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 381464562Sgshapiro# if NETINET6 381564562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 381664562Sgshapiro# endif /* NETINET6 */ 381764562Sgshapiro# if NETINET 381864562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 381964562Sgshapiro# endif /* NETINET */ 382064562Sgshapiro ) 382171345Sgshapiro { 382271345Sgshapiro char *name; 382371345Sgshapiro 382471345Sgshapiro name = denlstring((char *) hp->h_name, TRUE, TRUE); 382571345Sgshapiro 382671345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 382771345Sgshapiro if (name == hp->h_name) 382871345Sgshapiro { 382971345Sgshapiro static char n[MAXNAME + 1]; 383071345Sgshapiro 383171345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 383271345Sgshapiro strlcpy(n, name, sizeof n); 383371345Sgshapiro name = n; 383471345Sgshapiro } 383571345Sgshapiro 383671345Sgshapiro freehostent(hp); 383771345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 383871345Sgshapiro return name; 383971345Sgshapiro } 384064562Sgshapiro# endif /* NETINET || NETINET6 */ 384171345Sgshapiro 384271345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6 384371345Sgshapiro if (hp != NULL) 384471345Sgshapiro { 384571345Sgshapiro freehostent(hp); 384671345Sgshapiro hp = NULL; 384771345Sgshapiro } 384871345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */ 384971345Sgshapiro 385064562Sgshapiro# if NETUNIX 385164562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 385238032Speter return "localhost"; 385364562Sgshapiro# endif /* NETUNIX */ 385438032Speter { 385538032Speter static char buf[203]; 385638032Speter 385738032Speter (void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap)); 385838032Speter return buf; 385938032Speter } 386038032Speter} 386164562Sgshapiro#endif /* USE_SOCK_STREAM */ 3862