📄 milter.c
字号:
}
*colon++ = ':';
}
else
{
/* default to AF_UNIX */
addr.sa.sa_family = AF_UNIX;
colon = p;
}
# if NETUNIX
if (addr.sa.sa_family == AF_UNIX)
{
long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
at = colon;
if (strlen(colon) >= sizeof addr.sunix.sun_path)
{
if (tTd(64, 5))
dprintf("X%s: local socket name %s too long\n",
m->mf_name, colon);
errno = EINVAL;
if (parseonly)
syserr("X%s: local socket name %s too long",
m->mf_name, colon);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: local socket name %s too long",
m->mf_name, colon);
milter_error(m);
return -1;
}
errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
S_IRUSR|S_IWUSR, NULL);
/* if just parsing .cf file, socket doesn't need to exist */
if (parseonly && errno == ENOENT)
{
if (OpMode == MD_DAEMON ||
OpMode == MD_FGDAEMON)
fprintf(stderr,
"WARNING: X%s: local socket name %s missing\n",
m->mf_name, colon);
}
else if (errno != 0)
{
/* if not safe, don't create */
save_errno = errno;
if (tTd(64, 5))
dprintf("X%s: local socket name %s unsafe\n",
m->mf_name, colon);
errno = save_errno;
if (parseonly)
{
if (OpMode == MD_DAEMON ||
OpMode == MD_FGDAEMON ||
OpMode == MD_SMTP)
syserr("X%s: local socket name %s unsafe",
m->mf_name, colon);
}
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: local socket name %s unsafe",
m->mf_name, colon);
milter_error(m);
return -1;
}
(void) strlcpy(addr.sunix.sun_path, colon,
sizeof addr.sunix.sun_path);
addrlen = sizeof (struct sockaddr_un);
}
else
# endif /* NETUNIX */
# if NETINET || NETINET6
if (FALSE
# if NETINET
|| addr.sa.sa_family == AF_INET
# endif /* NETINET */
# if NETINET6
|| addr.sa.sa_family == AF_INET6
# endif /* NETINET6 */
)
{
u_short port;
/* Parse port@host */
at = strchr(colon, '@');
if (at == NULL)
{
if (tTd(64, 5))
dprintf("X%s: bad address %s (expected port@host)\n",
m->mf_name, colon);
if (parseonly)
syserr("X%s: bad address %s (expected port@host)",
m->mf_name, colon);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: bad address %s (expected port@host)",
m->mf_name, colon);
milter_error(m);
return -1;
}
*at = '\0';
if (isascii(*colon) && isdigit(*colon))
port = htons((u_short) atoi(colon));
else
{
# ifdef NO_GETSERVBYNAME
if (tTd(64, 5))
dprintf("X%s: invalid port number %s\n",
m->mf_name, colon);
if (parseonly)
syserr("X%s: invalid port number %s",
m->mf_name, colon);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: invalid port number %s",
m->mf_name, colon);
milter_error(m);
return -1;
# else /* NO_GETSERVBYNAME */
register struct servent *sp;
sp = getservbyname(colon, "tcp");
if (sp == NULL)
{
save_errno = errno;
if (tTd(64, 5))
dprintf("X%s: unknown port name %s\n",
m->mf_name, colon);
errno = save_errno;
if (parseonly)
syserr("X%s: unknown port name %s",
m->mf_name, colon);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: unknown port name %s",
m->mf_name, colon);
milter_error(m);
return -1;
}
port = sp->s_port;
# endif /* NO_GETSERVBYNAME */
}
*at++ = '@';
if (*at == '[')
{
char *end;
end = strchr(at, ']');
if (end != NULL)
{
bool found = FALSE;
# if NETINET
unsigned long hid = INADDR_NONE;
# endif /* NETINET */
# if NETINET6
struct sockaddr_in6 hid6;
# endif /* NETINET6 */
*end = '\0';
# if NETINET
if (addr.sa.sa_family == AF_INET &&
(hid = inet_addr(&at[1])) != INADDR_NONE)
{
addr.sin.sin_addr.s_addr = hid;
addr.sin.sin_port = port;
found = TRUE;
}
# endif /* NETINET */
# if NETINET6
(void) memset(&hid6, '\0', sizeof hid6);
if (addr.sa.sa_family == AF_INET6 &&
inet_pton(AF_INET6, &at[1],
&hid6.sin6_addr) == 1)
{
addr.sin6.sin6_addr = hid6.sin6_addr;
addr.sin6.sin6_port = port;
found = TRUE;
}
# endif /* NETINET6 */
*end = ']';
if (!found)
{
if (tTd(64, 5))
dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
m->mf_name, at);
if (parseonly)
syserr("X%s: Invalid numeric domain spec \"%s\"",
m->mf_name, at);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: Invalid numeric domain spec \"%s\"",
m->mf_name, at);
milter_error(m);
return -1;
}
}
else
{
if (tTd(64, 5))
dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
m->mf_name, at);
if (parseonly)
syserr("X%s: Invalid numeric domain spec \"%s\"",
m->mf_name, at);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: Invalid numeric domain spec \"%s\"",
m->mf_name, at);
milter_error(m);
return -1;
}
}
else
{
hp = sm_gethostbyname(at, addr.sa.sa_family);
if (hp == NULL)
{
save_errno = errno;
if (tTd(64, 5))
dprintf("X%s: Unknown host name %s\n",
m->mf_name, at);
errno = save_errno;
if (parseonly)
syserr("X%s: Unknown host name %s",
m->mf_name, at);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: Unknown host name %s",
m->mf_name, at);
milter_error(m);
return -1;
}
addr.sa.sa_family = hp->h_addrtype;
switch (hp->h_addrtype)
{
# if NETINET
case AF_INET:
memmove(&addr.sin.sin_addr,
hp->h_addr,
INADDRSZ);
addr.sin.sin_port = port;
addrlen = sizeof (struct sockaddr_in);
addrno = 1;
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
hp->h_addr,
IN6ADDRSZ);
addr.sin6.sin6_port = port;
addrlen = sizeof (struct sockaddr_in6);
addrno = 1;
break;
# endif /* NETINET6 */
default:
if (tTd(64, 5))
dprintf("X%s: Unknown protocol for %s (%d)\n",
m->mf_name, at,
hp->h_addrtype);
if (parseonly)
syserr("X%s: Unknown protocol for %s (%d)",
m->mf_name, at, hp->h_addrtype);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: Unknown protocol for %s (%d)",
m->mf_name, at,
hp->h_addrtype);
milter_error(m);
return -1;
}
}
}
else
# endif /* NETINET || NETINET6 */
{
if (tTd(64, 5))
dprintf("X%s: unknown socket protocol\n", m->mf_name);
if (parseonly)
syserr("X%s: unknown socket protocol", m->mf_name);
else if (LogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
"X%s: unknown socket protocol", m->mf_name);
milter_error(m);
return -1;
}
/* just parsing through? */
if (parseonly)
{
m->mf_state = SMFS_READY;
return 0;
}
/* sanity check */
if (m->mf_state != SMFS_READY &&
m->mf_state != SMFS_CLOSED)
{
/* shouldn't happen */
if (tTd(64, 1))
dprintf("milter_open(%s): Trying to open filter in state %c\n",
m->mf_name, (char) m->mf_state);
milter_error(m);
return -1;
}
/* nope, actually connecting */
for (;;)
{
sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
if (sock < 0)
{
save_errno = errno;
if (tTd(64, 5))
dprintf("X%s: error creating socket: %s\n",
m->mf_name, errstring(save_errno));
if (LogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
"X%s: error creating socket: %s",
m->mf_name, errstring(save_errno));
milter_error(m);
return -1;
}
if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
break;
/* couldn't connect.... try next address */
save_errno = errno;
p = CurHostName;
CurHostName = at;
if (tTd(64, 5))
dprintf("milter_open(%s): %s failed: %s\n",
m->mf_name, at, errstring(save_errno));
if (LogLevel >= 14)
sm_syslog(LOG_INFO, e->e_id,
"milter_open(%s): %s failed: %s",
m->mf_name, at, errstring(save_errno));
CurHostName = p;
(void) close(sock);
/* try next address */
if (hp != NULL && hp->h_addr_list[addrno] != NULL)
{
switch (addr.sa.sa_family)
{
# if NETINET
case AF_INET:
memmove(&addr.sin.sin_addr,
hp->h_addr_list[addrno++],
INADDRSZ);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
hp->h_addr_list[addrno++],
IN6ADDRSZ);
break;
# endif /* NETINET6 */
default:
if (tTd(64, 5))
dprintf("X%s: Unknown protocol for %s (%d)\n",
m->mf_name, at,
hp->h_addrtype);
if (LogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
"X%s: Unknown protocol for %s (%d)",
m->mf_name, at,
hp->h_addrtype);
milter_error(m);
return -1;
}
continue;
}
if (tTd(64, 5))
dprintf("X%s: error connecting to filter\n",
m->mf_name);
if (LogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
"X%s: error connecting to filter",
m->mf_name);
milter_error(m);
return -1;
}
m->mf_state = SMFS_OPEN;
return sock;
}
/*
** MILTER_SETUP -- setup structure for a mail filter
**
** Parameters:
** line -- the options line.
**
** Returns:
** none
*/
void
milter_setup(line)
char *line;
{
char fcode;
register char *p;
register struct milter *m;
STAB *s;
/* collect the filter name */
for (p = line;
*p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
p++)
continue;
if (*p != '\0')
*p++ = '\0';
if (line[0] == '\0')
{
syserr("name required for mail filter");
return;
}
m = (struct milter *)xalloc(sizeof *m);
memset((char *) m, '\0', sizeof *m);
m->mf_name = newstr(line);
m->mf_state = SMFS_READY;
m->mf_sock = -1;
m->mf_timeout[SMFTO_WRITE] = (time_t) 10;
m->mf_timeout[SMFTO_READ] = (time_t) 10;
m->mf_timeout[SMFTO_EOM] = (time_t) 300;
/* now scan through and assign info from the fields */
while (*p != '\0')
{
char *delimptr;
while (*p != '\0' &&
(*p == ',' || (isascii(*p) && isspace(*p))))
p++;
/* p now points to field code */
fcode = *p;
while (*p != '\0' && *p != '=' && *p != ',')
p++;
if (*p++ != '=')
{
syserr("X%s: `=' expected", m->mf_name);
return;
}
while (isascii(*p) && isspace(*p))
p++;
/* p now points to the field body */
p = munchstring(p, &delimptr, ',');
/* install the field into the filter struct */
switch (fcode)
{
case 'S': /* socket */
if (p == NULL)
m->mf_conn = NULL;
else
m->mf_conn = newstr(p);
break;
case 'F': /* Milter flags configured on MTA */
for (; *p != '\0'; p++)
{
if (!(isascii(*p) && isspace(*p)))
setbitn(*p, m->mf_flags);
}
break;
case 'T': /* timeouts */
milter_parse_timeouts(p, m);
break;
default:
syserr("X%s: unknown filter equate %c=",
m->mf_name, fcode);
break;
}
p = delimptr;
}
/* early check for errors */
(void) milter_open(m, TRUE, CurEnv);
/* enter the filter into the symbol table */
s = stab(m->mf_name, ST_MILTER, ST_ENTER);
if (s->s_milter != NULL)
syserr("X%s: duplicate filter definition", m->mf_name);
else
s->s_milter = m;
}
/*
** MILTER_PARSE_LIST -- parse option list into an array
**
** Called when reading configuration file.
**
** Parameters:
** spec -- the filter list.
** list -- the array to fill in.
** max -- the maximum number of entries in list.
**
** Returns:
** none
*/
void
milter_parse_list(spec, list, max)
char *spec;
struct milter **list;
int max;
{
int numitems = 0;
register char *p;
/* leave one for the NULL signifying the end of the list */
max--;
for (p = spec; p != NULL; )
{
STAB *s;
while (isascii(*p) && isspace(*p))
p++;
if (*p == '\0')
break;
spec = p;
if (numitems >= max)
{
syserr("Too many filters defined, %d max", max);
if (max > 0)
list[0] = NULL;
return;
}
p = strpbrk(p, ",");
if (p != NULL)
*p++ = '\0';
s = stab(spec, ST_MILTER, ST_FIND);
if (s == NULL)
{
syserr("InputFilter %s not defined", spec);
ExitStat = EX_CONFIG;
return;
}
list[numitems++] = s->s_milter;
}
list[numitems] = NULL;
}
/*
** MILTER_PARSE_TIMEOUTS -- parse timeout list
**
** Called when reading configuration file.
**
** Parameters:
** spec -- the timeout list.
** m -- milter to set.
**
** Returns:
** none
*/
static void
milter_parse_timeouts(spec, m)
char *spec;
struct milter *m;
{
char fcode;
register char *p;
p = spec;
/* now scan through and assign info from the fields */
while (*p != '\0')
{
char *delimptr;
while (*p != '\0' &&
(*p == ';' || (isascii(*p) && isspace(*p))))
p++;
/* p now points to field code */
fcode = *p;
while (*p != '\0' && *p != ':')
p++;
if (*p++ != ':')
{
syserr("X%s, T=: `:' expected", m->mf_name);
return;
}
while (isascii(*p) && isspace(*p))
p++;
/* p now points to the field body */
p = munchstring(p, &delimptr, ';');
/* install the field into the filter struct */
switch (fcode)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -