summaryrefslogtreecommitdiff
path: root/src/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon.c')
-rw-r--r--src/daemon.c320
1 files changed, 221 insertions, 99 deletions
diff --git a/src/daemon.c b/src/daemon.c
index e62aaf1..ae6b004 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -1,35 +1,13 @@
/*
- * Copyright (c) 1983, 1995-1997 Eric P. Allman
+ * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
*/
#include <errno.h>
@@ -37,9 +15,9 @@
#ifndef lint
#ifdef DAEMON
-static char sccsid[] = "@(#)daemon.c 8.195 (Berkeley) 10/23/97 (with daemon mode)";
+static char sccsid[] = "@(#)daemon.c 8.236 (Berkeley) 1/25/1999 (with daemon mode)";
#else
-static char sccsid[] = "@(#)daemon.c 8.195 (Berkeley) 10/23/97 (without daemon mode)";
+static char sccsid[] = "@(#)daemon.c 8.236 (Berkeley) 1/25/1999 (without daemon mode)";
#endif
#endif /* not lint */
@@ -125,15 +103,22 @@ getrequests(e)
ENVELOPE *e;
{
int t;
- bool refusingconnections = TRUE;
+ time_t refuse_connections_until = 0;
+ bool firsttime = TRUE;
FILE *pidf;
+ int sff;
int socksize;
u_short port;
#if XDEBUG
bool j_has_dot;
#endif
- extern void reapchild();
+ char status[MAXLINE];
+ extern void reapchild __P((int));
+#ifdef NETUNIX
+ extern int ControlSocket;
+#endif
extern int opendaemonsocket __P((bool));
+ extern int opencontrolsocket __P((void));
/*
** Set up the address for the mailer.
@@ -191,11 +176,18 @@ getrequests(e)
/* get a socket for the SMTP connection */
socksize = opendaemonsocket(TRUE);
+ if (opencontrolsocket() < 0)
+ sm_syslog(LOG_WARNING, NOQID,
+ "daemon could not open control socket %s: %s",
+ ControlSocketName, errstring(errno));
+
(void) setsignal(SIGCHLD, reapchild);
/* write the pid to the log file for posterity */
- pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644,
- SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT);
+ sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
+ if (TrustedUid != 0 && RealUid == TrustedUid)
+ sff |= SFF_OPENASROOT;
+ pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644, sff);
if (pidf == NULL)
{
sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile);
@@ -223,6 +215,9 @@ getrequests(e)
}
#endif
+ /* Add parent process as first item */
+ proc_list_add(getpid(), "Sendmail daemon");
+
if (tTd(15, 1))
printf("getrequests: %d\n", DaemonSocket);
@@ -230,30 +225,34 @@ getrequests(e)
{
register pid_t pid;
auto SOCKADDR_LEN_T lotherend;
+ bool timedout = FALSE;
+ bool control = FALSE;
int savederrno;
int pipefd[2];
- extern bool refuseconnections();
+ extern bool refuseconnections __P((int));
/* see if we are rejecting connections */
(void) blocksignal(SIGALRM);
- if (refuseconnections(ntohs(port)))
+ if (curtime() >= refuse_connections_until)
{
- if (DaemonSocket >= 0)
+ if (refuseconnections(ntohs(port)))
{
- /* close socket so peer will fail quickly */
- (void) close(DaemonSocket);
- DaemonSocket = -1;
- }
- refusingconnections = TRUE;
- sleep(15);
- continue;
- }
+ if (DaemonSocket >= 0)
+ {
+ /* close socket so peer fails quickly */
+ (void) close(DaemonSocket);
+ DaemonSocket = -1;
+ }
- /* arrange to (re)open the socket if necessary */
- if (refusingconnections)
- {
- (void) opendaemonsocket(FALSE);
- refusingconnections = FALSE;
+ /* refuse connections for next 15 seconds */
+ refuse_connections_until = curtime() + 15;
+ }
+ else if (DaemonSocket < 0 || firsttime)
+ {
+ /* arrange to (re)open the socket if needed */
+ (void) opendaemonsocket(FALSE);
+ firsttime = FALSE;
+ }
}
#if XDEBUG
@@ -280,9 +279,6 @@ getrequests(e)
}
#endif
- /* wait for a connection */
- setproctitle("accepting connections on port %d",
- ntohs(port));
#if 0
/*
** Andrew Sun <asun@ieps-sun.ml.com> claims that this will
@@ -290,34 +286,97 @@ getrequests(e)
** so is it worth doing this?
*/
- if (SetNonBlocking(DaemonSocket, FALSE) < 0)
+ if (DaemonSocket >= 0 &&
+ SetNonBlocking(DaemonSocket, FALSE) < 0)
log an error here;
#endif
(void) releasesignal(SIGALRM);
for (;;)
{
+ int highest = -1;
fd_set readfds;
struct timeval timeout;
FD_ZERO(&readfds);
- FD_SET(DaemonSocket, &readfds);
- timeout.tv_sec = 60;
+
+ /* wait for a connection */
+ if (DaemonSocket >= 0)
+ {
+ sm_setproctitle(TRUE,
+ "accepting connections on port %d",
+ ntohs(port));
+ if (DaemonSocket > highest)
+ highest = DaemonSocket;
+ FD_SET(DaemonSocket, &readfds);
+ }
+#ifdef NETUNIX
+ if (ControlSocket >= 0)
+ {
+ if (ControlSocket > highest)
+ highest = ControlSocket;
+ FD_SET(ControlSocket, &readfds);
+ }
+#endif
+ if (DaemonSocket >= 0)
+ timeout.tv_sec = 60;
+ else
+ timeout.tv_sec = 5;
timeout.tv_usec = 0;
- t = select(DaemonSocket + 1, FDSET_CAST &readfds,
- NULL, NULL, &timeout);
+ t = select(highest + 1, FDSET_CAST &readfds,
+ NULL, NULL, &timeout);
+
if (DoQueueRun)
(void) runqueue(TRUE, FALSE);
- if (t <= 0 || !FD_ISSET(DaemonSocket, &readfds))
- continue;
+ if (t <= 0)
+ {
+ timedout = TRUE;
+ break;
+ }
+ control = FALSE;
errno = 0;
- lotherend = socksize;
- t = accept(DaemonSocket,
- (struct sockaddr *)&RealHostAddr, &lotherend);
+ if (DaemonSocket >= 0 &&
+ FD_ISSET(DaemonSocket, &readfds))
+ {
+ lotherend = socksize;
+ t = accept(DaemonSocket,
+ (struct sockaddr *)&RealHostAddr,
+ &lotherend);
+ }
+#ifdef NETUNIX
+ else if (ControlSocket >= 0 &&
+ FD_ISSET(ControlSocket, &readfds))
+ {
+ struct sockaddr_un sa_un;
+
+ lotherend = sizeof sa_un;
+ t = accept(ControlSocket,
+ (struct sockaddr *)&sa_un,
+ &lotherend);
+ control = TRUE;
+ }
+#endif
if (t >= 0 || errno != EINTR)
break;
}
+ if (timedout)
+ {
+ timedout = FALSE;
+ continue;
+ }
+ if (control)
+ {
+ if (t >= 0)
+ {
+ extern void control_command __P((int, ENVELOPE *));
+
+ control_command(t, e);
+ }
+ else
+ syserr("getrequests: control accept");
+ continue;
+ }
savederrno = errno;
(void) blocksignal(SIGALRM);
if (t < 0)
@@ -328,8 +387,6 @@ getrequests(e)
/* arrange to re-open the socket next time around */
(void) close(DaemonSocket);
DaemonSocket = -1;
- refusingconnections = TRUE;
- sleep(5);
continue;
}
@@ -382,12 +439,16 @@ getrequests(e)
(void) setsignal(SIGCHLD, SIG_DFL);
(void) setsignal(SIGHUP, intsig);
(void) close(DaemonSocket);
+ clrcontrol();
proc_list_clear();
+ /* Add parent process as first child item */
+ proc_list_add(getpid(), "daemon child");
+
/* don't schedule queue runs if we are told to ETRN */
QueueIntvl = 0;
- setproctitle("startup with %s",
+ sm_setproctitle(TRUE, "startup with %s",
anynet_ntoa(&RealHostAddr));
if (pipefd[0] != -1)
@@ -417,36 +478,34 @@ getrequests(e)
if (strlen(p) > (SIZE_T) MAXNAME)
p[MAXNAME] = '\0';
RealHostName = newstr(p);
- setproctitle("startup with %s", p);
+ sm_setproctitle(TRUE, "startup with %s", p);
if ((inchannel = fdopen(t, "r")) == NULL ||
(t = dup(t)) < 0 ||
(outchannel = fdopen(t, "w")) == NULL)
{
syserr("cannot open SMTP server channel, fd=%d", t);
- exit(0);
+ finis(FALSE, EX_OK);
}
InChannel = inchannel;
OutChannel = outchannel;
DisConnected = FALSE;
- /* open maps for check_relay ruleset */
- initmaps(FALSE, e);
-
#ifdef XLA
if (!xla_host_ok(RealHostName))
{
message("421 Too many SMTP sessions for this host");
- exit(0);
+ finis(FALSE, EX_OK);
}
#endif
-
break;
}
/* parent -- keep track of children */
- proc_list_add(pid);
+ snprintf(status, sizeof status, "SMTP server child for %s",
+ anynet_ntoa(&RealHostAddr));
+ proc_list_add(pid, status);
(void) releasesignal(SIGCHLD);
/* close the read end of the synchronization pipe */
@@ -574,7 +633,7 @@ opendaemonsocket(firsttime)
return socksize;
} while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
- finis();
+ /*NOTREACHED*/
return -1; /* avoid compiler warning on IRIX */
}
/*
@@ -814,7 +873,9 @@ makeconnection(host, port, mci, e)
if (host[0] == '[')
{
- long hid;
+#if NETINET
+ unsigned long hid = INADDR_NONE;
+#endif
register char *p = strchr(host, ']');
if (p != NULL)
@@ -908,6 +969,13 @@ gothostent:
#endif
default:
+ if (hp->h_length > sizeof addr.sa.sa_data)
+ {
+ syserr("makeconnection: long sa_data: family %d len %d",
+ hp->h_addrtype, hp->h_length);
+ mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
+ return EX_NOHOST;
+ }
bcopy(hp->h_addr,
addr.sa.sa_data,
hp->h_length);
@@ -1038,6 +1106,12 @@ gothostent:
ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
else
ev = NULL;
+
+#if _FFR_CONNECTONLYTO_OPTION
+ /* for testing */
+ if (ConnectOnlyTo != 0)
+ addr.sin.sin_addr.s_addr = ConnectOnlyTo;
+#endif
i = connect(s, (struct sockaddr *) &addr, addrlen);
sav_errno = errno;
if (ev != NULL)
@@ -1061,7 +1135,14 @@ gothostent:
/* couldn't connect.... figure out why */
(void) close(s);
- if (hp != NULL && hp->h_addr_list[addrno])
+
+ if (LogLevel >= 14)
+ sm_syslog(LOG_INFO, e->e_id,
+ "makeconnection (%s [%s]) failed: %s",
+ host, anynet_ntoa(&addr),
+ errstring(sav_errno));
+
+ if (hp != NULL && hp->h_addr_list[addrno] != NULL)
{
if (tTd(16, 1))
printf("Connect failed (%s); trying new address....\n",
@@ -1225,6 +1306,9 @@ addrcmp(hp, ha, sa)
**
** Parameters:
** fd -- the descriptor
+** may_be_forged -- an outage that is set to TRUE if the
+** forward lookup of RealHostName does not match
+** RealHostAddr; set to FALSE if they do match.
**
** Returns:
** The user@host information associated with this descriptor.
@@ -1239,8 +1323,9 @@ authtimeout()
}
char *
-getauthinfo(fd)
+getauthinfo(fd, may_be_forged)
int fd;
+ bool *may_be_forged;
{
SOCKADDR_LEN_T falen;
register char *volatile p = NULL;
@@ -1248,19 +1333,22 @@ getauthinfo(fd)
SOCKADDR_LEN_T lalen;
register struct servent *sp;
volatile int s;
- int i;
+ int i = 0;
EVENT *ev;
int nleft;
struct hostent *hp;
+ char *ostype = NULL;
char **ha;
- volatile bool may_be_forged;
char ibuf[MAXNAME + 1];
- static char hbuf[MAXNAME * 2 + 2];
+ static char hbuf[MAXNAME * 2 + 11];
+ *may_be_forged = FALSE;
falen = sizeof RealHostAddr;
- if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 ||
+ if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
falen <= 0 || RealHostAddr.sa.sa_family == 0)
{
+ if (i < 0 && errno != ENOTSOCK)
+ return NULL;
(void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
RealUserName);
if (tTd(9, 1))
@@ -1273,19 +1361,18 @@ getauthinfo(fd)
/* translate that to a host name */
RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
if (strlen(RealHostName) > MAXNAME)
- RealHostName[MAXNAME - 1] = '\0';
+ RealHostName[MAXNAME] = '\0';
}
/* cross check RealHostName with forward DNS lookup */
- if (anynet_ntoa(&RealHostAddr)[0] == '[')
+ if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
+ RealHostName[0] == '[')
{
- /* address is not a socket */
- may_be_forged = FALSE;
- }
- else if (RealHostName[0] == '[')
- {
- /* have IP address with no forward lookup */
- may_be_forged = FALSE;
+ /*
+ ** address is not a socket or have an
+ ** IP address with no forward lookup
+ */
+ *may_be_forged = FALSE;
}
else
{
@@ -1293,13 +1380,13 @@ getauthinfo(fd)
hp = sm_gethostbyname(RealHostName);
if (hp == NULL)
- may_be_forged = TRUE;
+ *may_be_forged = TRUE;
else
{
for (ha = hp->h_addr_list; *ha != NULL; ha++)
if (addrcmp(hp, *ha, &RealHostAddr) == 0)
break;
- may_be_forged = *ha == NULL;
+ *may_be_forged = *ha == NULL;
}
}
@@ -1407,22 +1494,41 @@ getauthinfo(fd)
}
/* p now points to the OSTYPE field */
+ while (isascii(*p) && isspace(*p))
+ p++;
+ ostype = p;
p = strchr(p, ':');
if (p == NULL)
{
/* malformed response */
goto noident;
}
+ else
+ {
+ char *charset;
+
+ *p = '\0';
+ charset = strchr(ostype, ',');
+ if (charset != NULL)
+ *charset = '\0';
+ }
/* 1413 says don't do this -- but it's broken otherwise */
while (isascii(*++p) && isspace(*p))
continue;
/* p now points to the authenticated name -- copy carefully */
- cleanstrcpy(hbuf, p, MAXNAME);
+ if (strncasecmp(ostype, "other", 5) == 0 &&
+ (ostype[5] == ' ' || ostype[5] == '\0'))
+ {
+ snprintf(hbuf, sizeof hbuf, "IDENT:");
+ cleanstrcpy(&hbuf[6], p, MAXNAME);
+ }
+ else
+ cleanstrcpy(hbuf, p, MAXNAME);
i = strlen(hbuf);
snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
- RealHostName == NULL ? "localhost" : RealHostName);
+ RealHostName == NULL ? "localhost" : RealHostName);
goto postident;
closeident:
@@ -1538,22 +1644,24 @@ postident:
snprintf(p, SPACELEFT(hbuf, p), "]");
goto postipsr;
}
-#endif
noipsr:
+#endif
if (RealHostName != NULL && RealHostName[0] != '[')
{
p = &hbuf[strlen(hbuf)];
(void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
anynet_ntoa(&RealHostAddr));
}
- if (may_be_forged)
+ if (*may_be_forged)
{
p = &hbuf[strlen(hbuf)];
(void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
}
+#if IP_SRCROUTE
postipsr:
+#endif
if (tTd(9, 1))
printf("getauthinfo: %s\n", hbuf);
return hbuf;
@@ -1781,6 +1889,9 @@ myhostname(hostbuf, size)
**
** Parameters:
** fd -- the descriptor
+** may_be_forged -- an outage that is set to TRUE if the
+** forward lookup of RealHostName does not match
+** RealHostAddr; set to FALSE if they do match.
**
** Returns:
** The host name associated with this descriptor, if it can
@@ -1792,9 +1903,11 @@ myhostname(hostbuf, size)
*/
char *
-getauthinfo(fd)
+getauthinfo(fd, may_be_forged)
int fd;
+ bool *may_be_forged;
{
+ *may_be_forged = FALSE;
return NULL;
}
/*
@@ -1837,7 +1950,7 @@ host_map_lookup(map, name, avp, statp)
if (bitset(MF_MATCHONLY, map->map_mflags))
cp = map_rewrite(map, name, strlen(name), NULL);
else
- cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
+ cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
return cp;
}
@@ -1865,6 +1978,10 @@ host_map_init(map, args)
map->map_app = ++p;
break;
+ case 'T':
+ map->map_tapp = ++p;
+ break;
+
case 'm':
map->map_mflags |= MF_MATCHONLY;
break;
@@ -1880,6 +1997,8 @@ host_map_init(map, args)
}
if (map->map_app != NULL)
map->map_app = newstr(map->map_app);
+ if (map->map_tapp != NULL)
+ map->map_tapp = newstr(map->map_tapp);
return TRUE;
}
/*
@@ -2015,10 +2134,13 @@ hostnamebyanyaddr(sap)
_res.retry = saveretry;
#endif /* NAMED_BIND */
- if (hp != NULL && hp->h_name[0] != '[')
+ if (hp != NULL && hp->h_name[0] != '[' &&
+ inet_addr(hp->h_name) == INADDR_NONE)
return denlstring((char *) hp->h_name, TRUE, TRUE);
+#if NETUNIX
else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
return "localhost";
+#endif
else
{
/* produce a dotted quad */