📄 daemon.c
字号:
if (pid == 0)
{
char *p;
FILE *inchannel, *outchannel = NULL;
/*
** CHILD -- return to caller.
** Collect verified idea of sending host.
** Verify calling user id if possible here.
*/
if (!control)
{
define(macid("{daemon_addr}", NULL),
newstr(anynet_ntoa(&Daemons[curdaemon].d_addr)),
&BlankEnvelope);
(void) snprintf(status, sizeof status, "%d",
ntohs(Daemons[curdaemon].d_port));
define(macid("{daemon_port}", NULL),
newstr(status), &BlankEnvelope);
}
(void) releasesignal(SIGALRM);
(void) releasesignal(SIGCHLD);
(void) setsignal(SIGCHLD, SIG_DFL);
(void) setsignal(SIGHUP, intsig);
for (idx = 0; idx < ndaemons; idx++)
{
if (Daemons[idx].d_socket >= 0)
(void) close(Daemons[idx].d_socket);
}
clrcontrol();
/* Avoid SMTP daemon actions if control command */
if (control)
{
/* Add control socket process */
proc_list_add(getpid(), "console socket child",
PROC_CONTROL_CHILD);
}
else
{
proc_list_clear();
/* Add parent process as first child item */
proc_list_add(getpid(), "daemon child",
PROC_DAEMON_CHILD);
/* don't schedule queue runs if ETRN */
QueueIntvl = 0;
sm_setproctitle(TRUE, e, "startup with %s",
anynet_ntoa(&RealHostAddr));
}
if (pipefd[0] != -1)
{
auto char c;
/*
** Wait for the parent to close the write end
** of the pipe, which we will see as an EOF.
** This guarantees that we won't write to the
** socket until after the parent has closed
** the pipe.
*/
/* close the write end of the pipe */
(void) close(pipefd[1]);
/* we shouldn't be interrupted, but ... */
while (read(pipefd[0], &c, 1) < 0 &&
errno == EINTR)
continue;
(void) close(pipefd[0]);
}
/* control socket processing */
if (control)
{
control_command(t, e);
/* NOTREACHED */
exit(EX_SOFTWARE);
}
/* determine host name */
p = hostnamebyanyaddr(&RealHostAddr);
if (strlen(p) > (SIZE_T) MAXNAME)
p[MAXNAME] = '\0';
RealHostName = newstr(p);
if (RealHostName[0] == '[')
{
/* TEMP, FAIL: which one? */
define(macid("{client_resolve}", NULL),
(h_errno == TRY_AGAIN) ? "TEMP" : "FAIL",
&BlankEnvelope);
}
else
define(macid("{client_resolve}", NULL), "OK",
&BlankEnvelope);
sm_setproctitle(TRUE, e, "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);
finis(FALSE, EX_OK);
}
InChannel = inchannel;
OutChannel = outchannel;
DisConnected = FALSE;
# ifdef XLA
if (!xla_host_ok(RealHostName))
{
message("421 4.4.5 Too many SMTP sessions for this host");
finis(FALSE, EX_OK);
}
# endif /* XLA */
/* find out name for interface of connection */
if (getsockname(fileno(InChannel), &sa.sa,
&len) == 0)
{
p = hostnamebyanyaddr(&sa);
if (tTd(15, 9))
dprintf("getreq: got name %s\n", p);
define(macid("{if_name}", NULL),
newstr(p), &BlankEnvelope);
/* do this only if it is not the loopback */
/* interface: how to figure out? XXX */
if (!isloopback(sa))
{
define(macid("{if_addr}", NULL),
newstr(anynet_ntoa(&sa)),
&BlankEnvelope);
p = xalloc(5);
snprintf(p, 4, "%d", sa.sa.sa_family);
define(macid("{if_family}", NULL), p,
&BlankEnvelope);
if (tTd(15, 7))
dprintf("getreq: got addr %s and family %s\n",
macvalue(macid("{if_addr}", NULL),
&BlankEnvelope),
macvalue(macid("{if_addr}", NULL),
&BlankEnvelope));
}
else
{
define(macid("{if_addr}", NULL), NULL,
&BlankEnvelope);
define(macid("{if_family}", NULL), NULL,
&BlankEnvelope);
}
}
else
{
if (tTd(15, 7))
dprintf("getreq: getsockname failed\n");
define(macid("{if_name}", NULL), NULL,
&BlankEnvelope);
define(macid("{if_addr}", NULL), NULL,
&BlankEnvelope);
define(macid("{if_family}", NULL), NULL,
&BlankEnvelope);
}
break;
}
/* parent -- keep track of children */
if (control)
{
snprintf(status, sizeof status, "control socket server child");
proc_list_add(pid, status, PROC_CONTROL);
}
else
{
snprintf(status, sizeof status,
"SMTP server child for %s",
anynet_ntoa(&RealHostAddr));
proc_list_add(pid, status, PROC_DAEMON);
}
(void) releasesignal(SIGCHLD);
/* close the read end of the synchronization pipe */
if (pipefd[0] != -1)
{
(void) close(pipefd[0]);
pipefd[0] = -1;
}
/* close the port so that others will hang (for a while) */
(void) close(t);
/* release the child by closing the read end of the sync pipe */
if (pipefd[1] != -1)
{
(void) close(pipefd[1]);
pipefd[1] = -1;
}
}
if (tTd(15, 2))
dprintf("getreq: returning\n");
return &Daemons[curdaemon].d_flags;
}
/*
** OPENDAEMONSOCKET -- open SMTP socket
**
** Deals with setting all appropriate options.
**
** Parameters:
** d -- the structure for the daemon to open.
** firsttime -- set if this is the initial open.
**
** Returns:
** Size in bytes of the daemon socket addr.
**
** Side Effects:
** Leaves DaemonSocket set to the open socket.
** Exits if the socket cannot be created.
*/
# define MAXOPENTRIES 10 /* maximum number of tries to open connection */
static int
opendaemonsocket(d, firsttime)
struct daemon *d;
bool firsttime;
{
int on = 1;
int fdflags;
SOCKADDR_LEN_T socksize = 0;
int ntries = 0;
int save_errno;
if (tTd(15, 2))
dprintf("opendaemonsocket(%s)\n", d->d_name);
do
{
if (ntries > 0)
(void) sleep(5);
if (firsttime || d->d_socket < 0)
{
d->d_socket = socket(d->d_addr.sa.sa_family,
SOCK_STREAM, 0);
if (d->d_socket < 0)
{
save_errno = errno;
syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", d->d_name);
severe:
if (LogLevel > 0)
sm_syslog(LOG_ALERT, NOQID,
"daemon %s: problem creating SMTP socket", d->d_name);
d->d_socket = -1;
continue;
}
/* turn on network debugging? */
if (tTd(15, 101))
(void) setsockopt(d->d_socket, SOL_SOCKET,
SO_DEBUG, (char *)&on,
sizeof on);
(void) setsockopt(d->d_socket, SOL_SOCKET,
SO_REUSEADDR, (char *)&on, sizeof on);
(void) setsockopt(d->d_socket, SOL_SOCKET,
SO_KEEPALIVE, (char *)&on, sizeof on);
# ifdef SO_RCVBUF
if (d->d_tcprcvbufsize > 0)
{
if (setsockopt(d->d_socket, SOL_SOCKET,
SO_RCVBUF,
(char *) &d->d_tcprcvbufsize,
sizeof(d->d_tcprcvbufsize)) < 0)
syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
}
# endif /* SO_RCVBUF */
# ifdef SO_SNDBUF
if (d->d_tcpsndbufsize > 0)
{
if (setsockopt(d->d_socket, SOL_SOCKET,
SO_SNDBUF,
(char *) &d->d_tcpsndbufsize,
sizeof(d->d_tcpsndbufsize)) < 0)
syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
}
# endif /* SO_SNDBUF */
if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
fcntl(d->d_socket, F_SETFD,
fdflags | FD_CLOEXEC) == -1)
{
save_errno = errno;
syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
d->d_name,
fdflags == -1 ? "get" : "set",
errstring(save_errno));
(void) close(d->d_socket);
goto severe;
}
switch (d->d_addr.sa.sa_family)
{
# if NETINET
case AF_INET:
socksize = sizeof d->d_addr.sin;
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
socksize = sizeof d->d_addr.sin6;
break;
# endif /* NETINET6 */
# if NETISO
case AF_ISO:
socksize = sizeof d->d_addr.siso;
break;
# endif /* NETISO */
default:
socksize = sizeof d->d_addr;
break;
}
if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0)
{
/* probably another daemon already */
save_errno = errno;
syserr("opendaemonsocket: daemon %s: cannot bind",
d->d_name);
(void) close(d->d_socket);
goto severe;
}
}
if (!firsttime &&
listen(d->d_socket, d->d_listenqueue) < 0)
{
save_errno = errno;
syserr("opendaemonsocket: daemon %s: cannot listen",
d->d_name);
(void) close(d->d_socket);
goto severe;
}
return socksize;
} while (ntries++ < MAXOPENTRIES && transienterror(save_errno));
syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting",
d->d_name);
/* NOTREACHED */
return -1; /* avoid compiler warning on IRIX */
}
/*
** SETUPDAEMON -- setup socket for daemon
**
** Parameters:
** daemonaddr -- socket for daemon
** daemon -- number of daemon
**
** Returns:
** port number on which daemon should run
**
*/
static u_short
setupdaemon(daemonaddr)
SOCKADDR *daemonaddr;
{
u_short port;
/*
** Set up the address for the mailer.
*/
if (daemonaddr->sa.sa_family == AF_UNSPEC)
{
memset(daemonaddr, '\0', sizeof *daemonaddr);
# if NETINET
daemonaddr->sa.sa_family = AF_INET;
# endif /* NETINET */
}
switch (daemonaddr->sa.sa_family)
{
# if NETINET
case AF_INET:
if (daemonaddr->sin.sin_addr.s_addr == 0)
daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
port = daemonaddr->sin.sin_port;
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
daemonaddr->sin6.sin6_addr = in6addr_any;
port = daemonaddr->sin6.sin6_port;
break;
# endif /* NETINET6 */
default:
/* unknown protocol */
port = 0;
break;
}
if (port == 0)
{
# ifdef NO_GETSERVBYNAME
port = htons(25);
# else /* NO_GETSERVBYNAME */
{
register struct servent *sp;
sp = getservbyname("smtp", "tcp");
if (sp == NULL)
{
syserr("554 5.3.5 service \"smtp\" unknown");
port = htons(25);
}
else
port = sp->s_port;
}
# endif /* NO_GETSERVBYNAME */
}
switch (daemonaddr->sa.sa_family)
{
# if NETINET
case AF_INET:
daemonaddr->sin.sin_port = port;
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
daemonaddr->sin6.sin6_port = port;
break;
# endif /* NETINET6 */
default:
/* unknown protocol */
break;
}
return(port);
}
/*
** CLRDAEMON -- reset the daemon connection
**
** Parameters:
** none.
**
** Returns:
** none.
**
** Side Effects:
** releases any resources used by the passive daemon.
*/
void
clrdaemon()
{
int i;
for (i = 0; i < ndaemons; i++)
{
if (Daemons[i].d_socket >= 0)
(void) close(Daemons[i].d_socket);
Daemons[i].d_socket = -1;
}
}
/*
** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
**
** Parameters:
** p -- the options line.
** d -- the daemon structure to fill in.
**
** Returns:
** none.
*/
static void
setsockaddroptions(p, d)
register char *p;
struct daemon *d;
{
# if NETISO
short port;
# endif /* NETISO */
int l;
char *h, *flags;
# if NETINET
if (d->d_addr.sa.sa_family == AF_UNSPEC)
d->d_addr.sa.sa_family = AF_INET;
# endif /* NETINET */
while (p != NULL)
{
register char *f;
register char *v;
while (isascii(*p) && isspace(*p))
p++;
if (*p == '\0')
break;
f = p;
p = strchr(p, ',');
if (p != NULL)
*p++ = '\0';
v = strchr(f, '=');
if (v == NULL)
continue;
while (isascii(*++v) && isspace(*v))
continue;
if (isascii(*f) && islower(*f))
*f = toupper(*f);
switch (*f)
{
case 'F': /* address family */
if (isascii(*v) && isdigit(*v))
d->d_addr.sa.sa_family = atoi(v);
# if NETINET
else if (strcasecmp(v, "inet") == 0)
d->d_addr.sa.sa_family = AF_INET;
# endif /* NETINET */
# if NETINET6
else if (strcasecmp(v, "inet6") == 0)
d->d_addr.sa.sa_family = AF_INET6;
# endif /* NETINET6 */
# if NETISO
else if (strcasecmp(v, "iso") == 0)
d->d_addr.sa.sa_family = AF_ISO;
# endif /* NETISO */
# if NETNS
else if (strcasecmp(v, "ns") == 0)
d->d_addr.sa.sa_family = AF_NS;
# endif /* NETNS */
# if NETX25
else if (strcasecmp(v, "x.25") == 0)
d->d_addr.sa.sa_family = AF_CCITT;
# endif /* NETX25 */
else
syserr("554 5.3.5 Unknown address family %s in Family=option",
v);
break;
case 'A': /* address */
switch (d->d_addr.sa.sa_family)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -