⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 milter.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		}
		*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 + -