📄 daemon.c
字号:
errno = save_errno;
return EX_TEMPFAIL;
}
/* connection ok, put it into canonical form */
mci->mci_out = NULL;
if ((mci->mci_out = fdopen(sock, "w")) == NULL ||
(sock = dup(sock)) < 0 ||
(mci->mci_in = fdopen(sock, "r")) == NULL)
{
save_errno = errno;
syserr("cannot open SMTP client channel, fd=%d", sock);
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
if (mci->mci_out != NULL)
(void) fclose(mci->mci_out);
(void) close(sock);
errno = save_errno;
return EX_TEMPFAIL;
}
mci_setstat(mci, EX_OK, NULL, NULL);
errno = 0;
return EX_OK;
}
# endif /* NETUNIX */
/*
** MYHOSTNAME -- return the name of this host.
**
** Parameters:
** hostbuf -- a place to return the name of this host.
** size -- the size of hostbuf.
**
** Returns:
** A list of aliases for this host.
**
** Side Effects:
** Adds numeric codes to $=w.
*/
struct hostent *
myhostname(hostbuf, size)
char hostbuf[];
int size;
{
register struct hostent *hp;
if (gethostname(hostbuf, size) < 0)
{
(void) strlcpy(hostbuf, "localhost", size);
}
hp = sm_gethostbyname(hostbuf, InetMode);
if (hp == NULL)
return NULL;
if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
(void) cleanstrcpy(hostbuf, hp->h_name, size);
# if NETINFO
if (strchr(hostbuf, '.') == NULL)
{
char *domainname;
domainname = ni_propval("/locations", NULL, "resolver",
"domain", '\0');
if (domainname != NULL &&
strlen(domainname) + strlen(hostbuf) + 1 < size)
{
(void) strlcat(hostbuf, ".", size);
(void) strlcat(hostbuf, domainname, size);
}
}
# endif /* NETINFO */
/*
** If there is still no dot in the name, try looking for a
** dotted alias.
*/
if (strchr(hostbuf, '.') == NULL)
{
char **ha;
for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
{
if (strchr(*ha, '.') != NULL)
{
(void) cleanstrcpy(hostbuf, *ha, size - 1);
hostbuf[size - 1] = '\0';
break;
}
}
}
/*
** If _still_ no dot, wait for a while and try again -- it is
** possible that some service is starting up. This can result
** in excessive delays if the system is badly configured, but
** there really isn't a way around that, particularly given that
** the config file hasn't been read at this point.
** All in all, a bit of a mess.
*/
if (strchr(hostbuf, '.') == NULL &&
!getcanonname(hostbuf, size, TRUE))
{
sm_syslog(LOG_CRIT, NOQID,
"My unqualified host name (%s) unknown; sleeping for retry",
hostbuf);
message("My unqualified host name (%s) unknown; sleeping for retry",
hostbuf);
(void) sleep(60);
if (!getcanonname(hostbuf, size, TRUE))
{
sm_syslog(LOG_ALERT, NOQID,
"unable to qualify my own domain name (%s) -- using short name",
hostbuf);
message("WARNING: unable to qualify my own domain name (%s) -- using short name",
hostbuf);
}
}
return hp;
}
/*
** ADDRCMP -- compare two host addresses
**
** Parameters:
** hp -- hostent structure for the first address
** ha -- actual first address
** sa -- second address
**
** Returns:
** 0 -- if ha and sa match
** else -- they don't match
*/
static int
addrcmp(hp, ha, sa)
struct hostent *hp;
char *ha;
SOCKADDR *sa;
{
# if NETINET6
u_char *a;
# endif /* NETINET6 */
switch (sa->sa.sa_family)
{
# if NETINET
case AF_INET:
if (hp->h_addrtype == AF_INET)
return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
a = (u_char *) &sa->sin6.sin6_addr;
/* Straight binary comparison */
if (hp->h_addrtype == AF_INET6)
return memcmp(ha, a, IN6ADDRSZ);
/* If IPv4-mapped IPv6 address, compare the IPv4 section */
if (hp->h_addrtype == AF_INET &&
IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
break;
# endif /* NETINET6 */
}
return -1;
}
/*
** GETAUTHINFO -- get the real host name associated with a file descriptor
**
** Uses RFC1413 protocol to try to get info from the other end.
**
** 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.
*/
static jmp_buf CtxAuthTimeout;
static void
authtimeout()
{
longjmp(CtxAuthTimeout, 1);
}
char *
getauthinfo(fd, may_be_forged)
int fd;
bool *may_be_forged;
{
volatile u_short port = 0;
SOCKADDR_LEN_T falen;
register char *volatile p = NULL;
SOCKADDR la;
SOCKADDR_LEN_T lalen;
register struct servent *sp;
volatile int s;
int i = 0;
EVENT *ev;
int nleft;
struct hostent *hp;
char *ostype = NULL;
char **ha;
char ibuf[MAXNAME + 1];
static char hbuf[MAXNAME * 2 + 11];
*may_be_forged = FALSE;
falen = sizeof RealHostAddr;
if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
falen <= 0 || RealHostAddr.sa.sa_family == 0)
{
if (i < 0)
{
/*
** ENOTSOCK is OK: bail on anything else, but reset
** errno in this case, so a mis-report doesn't
** happen later.
*/
if (errno != ENOTSOCK)
return NULL;
errno = 0;
}
(void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
RealUserName);
if (tTd(9, 1))
dprintf("getauthinfo: %s\n", hbuf);
return hbuf;
}
if (RealHostName == NULL)
{
/* translate that to a host name */
RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
if (strlen(RealHostName) > MAXNAME)
RealHostName[MAXNAME] = '\0';
}
/* cross check RealHostName with forward DNS lookup */
if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
RealHostName[0] == '[')
{
/*
** address is not a socket or have an
** IP address with no forward lookup
*/
*may_be_forged = FALSE;
}
else
{
/* try to match the reverse against the forward lookup */
hp = sm_gethostbyname(RealHostName,
RealHostAddr.sa.sa_family);
if (hp == NULL)
*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;
}
}
if (TimeOuts.to_ident == 0)
goto noident;
lalen = sizeof la;
switch (RealHostAddr.sa.sa_family)
{
# if NETINET
case AF_INET:
if (getsockname(fd, &la.sa, &lalen) < 0 ||
lalen <= 0 ||
la.sa.sa_family != AF_INET)
{
/* no ident info */
goto noident;
}
port = RealHostAddr.sin.sin_port;
/* create ident query */
(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
ntohs(RealHostAddr.sin.sin_port),
ntohs(la.sin.sin_port));
/* create local address */
la.sin.sin_port = 0;
/* create foreign address */
# ifdef NO_GETSERVBYNAME
RealHostAddr.sin.sin_port = htons(113);
# else /* NO_GETSERVBYNAME */
sp = getservbyname("auth", "tcp");
if (sp != NULL)
RealHostAddr.sin.sin_port = sp->s_port;
else
RealHostAddr.sin.sin_port = htons(113);
break;
# endif /* NO_GETSERVBYNAME */
# endif /* NETINET */
# if NETINET6
case AF_INET6:
if (getsockname(fd, &la.sa, &lalen) < 0 ||
lalen <= 0 ||
la.sa.sa_family != AF_INET6)
{
/* no ident info */
goto noident;
}
port = RealHostAddr.sin6.sin6_port;
/* create ident query */
(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
ntohs(RealHostAddr.sin6.sin6_port),
ntohs(la.sin6.sin6_port));
/* create local address */
la.sin6.sin6_port = 0;
/* create foreign address */
# ifdef NO_GETSERVBYNAME
RealHostAddr.sin6.sin6_port = htons(113);
# else /* NO_GETSERVBYNAME */
sp = getservbyname("auth", "tcp");
if (sp != NULL)
RealHostAddr.sin6.sin6_port = sp->s_port;
else
RealHostAddr.sin6.sin6_port = htons(113);
break;
# endif /* NO_GETSERVBYNAME */
# endif /* NETINET6 */
default:
/* no ident info */
goto noident;
}
s = -1;
if (setjmp(CtxAuthTimeout) != 0)
{
if (s >= 0)
(void) close(s);
goto noident;
}
/* put a timeout around the whole thing */
ev = setevent(TimeOuts.to_ident, authtimeout, 0);
/* connect to foreign IDENT server using same address as SMTP socket */
s = socket(la.sa.sa_family, SOCK_STREAM, 0);
if (s < 0)
{
clrevent(ev);
goto noident;
}
if (bind(s, &la.sa, lalen) < 0 ||
connect(s, &RealHostAddr.sa, lalen) < 0)
{
goto closeident;
}
if (tTd(9, 10))
dprintf("getauthinfo: sent %s", ibuf);
/* send query */
if (write(s, ibuf, strlen(ibuf)) < 0)
goto closeident;
/* get result */
p = &ibuf[0];
nleft = sizeof ibuf - 1;
while ((i = read(s, p, nleft)) > 0)
{
p += i;
nleft -= i;
*p = '\0';
if (strchr(ibuf, '\n') != NULL)
break;
}
(void) close(s);
clrevent(ev);
if (i < 0 || p == &ibuf[0])
goto noident;
if (*--p == '\n' && *--p == '\r')
p--;
*++p = '\0';
if (tTd(9, 3))
dprintf("getauthinfo: got %s\n", ibuf);
/* parse result */
p = strchr(ibuf, ':');
if (p == NULL)
{
/* malformed response */
goto noident;
}
while (isascii(*++p) && isspace(*p))
continue;
if (strncasecmp(p, "userid", 6) != 0)
{
/* presumably an error string */
goto noident;
}
p += 6;
while (isascii(*p) && isspace(*p))
p++;
if (*p++ != ':')
{
/* either useridxx or malformed response */
goto noident;
}
/* 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 */
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);
goto postident;
closeident:
(void) close(s);
clrevent(ev);
noident:
/* put back the original incoming port */
switch (RealHostAddr.sa.sa_family)
{
# if NETINET
case AF_INET:
if (port > 0)
RealHostAddr.sin.sin_port = port;
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
if (port > 0)
RealHostAddr.sin6.sin6_port = port;
break;
# endif /* NETINET6 */
}
if (RealHostName == NULL)
{
if (tTd(9, 1))
dprintf("getauthinfo: NULL\n");
return NULL;
}
snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
postident:
# if IP_SRCROUTE
# ifndef GET_IPOPT_DST
# define GET_IPOPT_DST(dst) (dst)
# endif /* ! GET_IPOPT_DST */
/*
** Extract IP source routing information.
**
** Format of output for a connection from site a through b
** through c to d:
** loose: @site-c@site-b:site-a
** strict: !@site-c@site-b:site-a
**
** o - pointer within ipopt_list structure.
** q - pointer within ls/ss rr route data
** p - pointer to hbuf
*/
if (RealHostAddr.sa.sa_family == AF_INET)
{
SOCKOPT_LEN_T ipoptlen;
int j;
u_char *q;
u_char *o;
int l;
struct IPOPTION ipopt;
ipoptlen = sizeof ipopt;
if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
(char *) &ipopt, &ipoptlen) < 0)
goto noipsr;
if (ipoptlen == 0)
goto noipsr;
o = (u_char *) ipopt.IP_LIST;
while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
{
switch (*o)
{
case IPOPT_EOL:
o = NULL;
break;
case IPOPT_NOP:
o++;
break;
case IPOPT_SSRR:
case IPOPT_LSRR:
/*
** Source routing.
** o[0] is the option type (loose/strict).
** o[1] is the length of this option,
** including option type and
** length.
** o[2] is the pointer into the route
** data.
** o[3] begins the route data.
*/
p = &hbuf[strlen(hbuf)];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -