diff options
Diffstat (limited to 'src/daemon.c')
-rw-r--r-- | src/daemon.c | 320 |
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 */ |