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

📄 usersmtp.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		**  file.
		*/
		sff |= SFF_MUSTOWN;
#else /* _FFR_ALLOW_SASLINFO */
		if (safe)
			sff |= SFF_OPENASROOT;
#endif /* _FFR_ALLOW_SASLINFO */

		f = safefopen(filename, O_RDONLY, 0, sff);
	}
	if (f == NULL)
	{
		syserr("readauth: cannot open %s", filename);
		return "";
	}

	lc = 0;
	while (lc < l && fgets(buf, sizeof buf, f) != NULL)
	{
		if (buf[0] != '#')
			lc++;
	}

	(void) fclose(f);
	if (pid > 0)
		(void) waitfor(pid);
	if (lc < l)
	{
		if (LogLevel >= 9)
			sm_syslog(LOG_WARNING, NOQID, "SASL: error: can't read %s from %s",
			  sasl_info_name[l], filename);
		return "";
	}
	lc = strlen(buf) - 1;
	if (lc >= 0)
		buf[lc] = '\0';
	if (tTd(95, 6))
		dprintf("readauth(%s, %d) = '%s'\n", filename, l, buf);
	return buf;
}

#  ifndef __attribute__
#   define __attribute__(x)
#  endif /* ! __attribute__ */

static int getsimple	__P((void *, int, const char **, unsigned *));
static int getsecret	__P((sasl_conn_t *, void *, int, sasl_secret_t **));
static int saslgetrealm	__P((void *, int, const char **, const char **));

static sasl_callback_t callbacks[] =
{
	{	SASL_CB_GETREALM,	&saslgetrealm,	NULL	},
# define CB_GETREALM_IDX	0
	{	SASL_CB_PASS,		&getsecret,	NULL	},
# define CB_PASS_IDX	1
	{	SASL_CB_USER,		&getsimple,	NULL	},
# define CB_USER_IDX	2
	{	SASL_CB_AUTHNAME,	&getsimple,	NULL	},
# define CB_AUTHNAME_IDX	3
	{	SASL_CB_VERIFYFILE,	&safesaslfile,	NULL	},
	{	SASL_CB_LIST_END,	NULL,		NULL	}
};

/*
**  GETSIMPLE -- callback to get userid or authid
**
**	Parameters:
**		context -- unused
**		id -- what to do
**		result -- (pointer to) result
**		len -- (pointer to) length of result
**
**	Returns:
**		OK/failure values
*/

static int
getsimple(context, id, result, len)
	void *context __attribute__((unused));
	int id;
	const char **result;
	unsigned *len;
{
	char *h;
#  if SASL > 10509
	int addrealm;
	static int addedrealm = FALSE;
#  endif /* SASL > 10509 */
	static char *user = NULL;
	static char *authid = NULL;

	if (result == NULL)
		return SASL_BADPARAM;

	switch (id)
	{
	  case SASL_CB_USER:
		if (user == NULL)
		{
			h = readauth(SASL_USER, SASLInfo, TRUE);
			user = newstr(h);
		}
		*result = user;
		if (tTd(95, 5))
			dprintf("AUTH username '%s'\n", *result);
		if (len != NULL)
			*len = user ? strlen(user) : 0;
		break;

	  case SASL_CB_AUTHNAME:
#  if SASL > 10509
		/* XXX maybe other mechanisms too?! */
		addrealm = context != NULL &&
			   strcasecmp(context, "CRAM-MD5") == 0;
		if (addedrealm != addrealm && authid != NULL)
		{
#  if SASL > 10522
			/*
			**  digest-md5 prior to 1.5.23 doesn't copy the
			**  value it gets from the callback, but free()s
			**  it later on
			**  workaround: don't free() it here
			**  this can cause a memory leak!
			*/
			free(authid);
#  endif /* SASL > 10522 */
			authid = NULL;
			addedrealm = addrealm;
		}
#  endif /* SASL > 10509 */
		if (authid == NULL)
		{
			h = readauth(SASL_AUTHID, SASLInfo, TRUE);
#  if SASL > 10509
			if (addrealm && strchr(h, '@') == NULL)
			{
				size_t l;
				char *realm;

				realm = callbacks[CB_GETREALM_IDX].context;
				l = strlen(h) + strlen(realm) + 2;
				authid = xalloc(l);
				snprintf(authid, l, "%s@%s", h, realm);
			}
			else
#  endif /* SASL > 10509 */
				authid = newstr(h);
		}
		*result = authid;
		if (tTd(95, 5))
			dprintf("AUTH authid '%s'\n", *result);
		if (len != NULL)
			*len = authid ? strlen(authid) : 0;
		break;

	  case SASL_CB_LANGUAGE:
		*result = NULL;
		if (len != NULL)
			*len = 0;
		break;

	  default:
		return SASL_BADPARAM;
	}
	return SASL_OK;
}

/*
**  GETSECRET -- callback to get password
**
**	Parameters:
**		conn -- connection information
**		context -- unused
**		id -- what to do
**		psecret -- (pointer to) result
**
**	Returns:
**		OK/failure values
*/

static int
getsecret(conn, context, id, psecret)
	sasl_conn_t *conn;
	void *context __attribute__((unused));
	int id;
	sasl_secret_t **psecret;
{
	char *h;
	int len;
	static char *authpass = NULL;

	if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
		return SASL_BADPARAM;

	if (authpass == NULL)
	{
		h = readauth(SASL_PASSWORD, SASLInfo, TRUE);
		authpass = newstr(h);
	}
	len = strlen(authpass);
	*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len + 1);
	if (*psecret == NULL)
		return SASL_FAIL;
	(void) strlcpy((*psecret)->data, authpass, len + 1);
	(*psecret)->len = len;
	return SASL_OK;
}

/*
**  SAFESASLFILE -- callback for sasl: is file safe?
**
**	Parameters:
**		context -- pointer to context between invocations (unused)
**		file -- name of file to check
**		type -- type of file to check
**
**	Returns:
**		SASL_OK: file can be used
**		SASL_CONTINUE: don't use file
**		SASL_FAIL: failure (not used here)
**
*/
int
# if SASL > 10515
safesaslfile(context, file, type)
# else /* SASL > 10515 */
safesaslfile(context, file)
# endif /* SASL > 10515 */
	void *context;
	char *file;
# if SASL > 10515
	int type;
# endif /* SASL > 10515 */
{
	long sff;
	int r;
	char *p;

	if (file == NULL || *file == '\0')
		return SASL_OK;
	sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOGWFILES|SFF_NOWWFILES|SFF_ROOTOK;
	if ((p = strrchr(file, '/')) == NULL)
		p = file;
	else
		++p;

# if SASL <= 10515
	/* everything beside libs and .conf files must not be readable */
	r = strlen(p);
	if ((r <= 3 || strncmp(p, "lib", 3) != 0) &&
	    (r <= 5 || strncmp(p + r - 5, ".conf", 5) != 0)
#  if _FFR_UNSAFE_SASL
	    && !bitnset(DBS_GROUPREADABLESASLFILE, DontBlameSendmail)
#  endif /* _FFR_UNSAFE_SASL */
	   )
		sff |= SFF_NORFILES;
# else /* SASL > 10515 */
	/* files containing passwords should be not readable */
	if (type == SASL_VRFY_PASSWD)
	{
#  if _FFR_UNSAFE_SASL
		if (bitnset(DBS_GROUPREADABLESASLFILE, DontBlameSendmail))
			sff |= SFF_NOWRFILES;
		else
#  endif /* _FFR_UNSAFE_SASL */
			sff |= SFF_NORFILES;
	}
# endif /* SASL <= 10515 */

	if ((r = safefile(file, RunAsUid, RunAsGid, RunAsUserName, sff,
			  S_IRUSR, NULL)) == 0)
		return SASL_OK;
	if (LogLevel >= 11 || (r != ENOENT && LogLevel >= 9))
		sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
			  file, errstring(r));
	return SASL_CONTINUE;
}

/*
**  SASLGETREALM -- return the realm for SASL
**
**	return the realm for the client
**
**	Parameters:
**		context -- context shared between invocations
**			here: realm to return
**		availrealms -- list of available realms
**			{realm, realm, ...}
**		result -- pointer to result
**
**	Returns:
**		failure/success
*/
static int
saslgetrealm(context, id, availrealms, result)
	void *context;
	int id;
	const char **availrealms;
	const char **result;
{
	if (LogLevel > 12)
		sm_syslog(LOG_INFO, NOQID, "saslgetrealm: realm %s available realms %s",
			  context == NULL ? "<No Context>" : (char *) context,
			  (availrealms == NULL || *availrealms == NULL) ? "<No Realms>" : *availrealms);
	if (context == NULL)
		return SASL_FAIL;

	/* check whether context is in list? */
	if (availrealms != NULL && *availrealms != NULL)
	{
		if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
		    NULL)
		{
			if (LogLevel > 8)
				sm_syslog(LOG_ERR, NOQID,
					  "saslgetrealm: realm %s not in list %s",
					  context, *availrealms);
			return SASL_FAIL;
		}
	}
	*result = (char *)context;
	return SASL_OK;
}
/*
**  ITEMINLIST -- does item appear in list?
**
**	Check whether item appears in list (which must be separated by a
**	character in delim) as a "word", i.e. it must appear at the begin
**	of the list or after a space, and it must end with a space or the
**	end of the list.
**
**	Parameters:
**		item -- item to search.
**		list -- list of items.
**		delim -- list of delimiters.
**
**	Returns:
**		pointer to occurrence (NULL if not found).
*/

char *
iteminlist(item, list, delim)
	char *item;
	char *list;
	char *delim;
{
	char *s;
	int len;

	if (list == NULL || *list == '\0')
		return NULL;
	if (item == NULL || *item == '\0')
		return NULL;
	s = list;
	len = strlen(item);
	while (s != NULL && *s != '\0')
	{
		if (strncasecmp(s, item, len) == 0 &&
		    (s[len] == '\0' || strchr(delim, s[len]) != NULL))
			return s;
		s = strpbrk(s, delim);
		if (s != NULL)
			while (*++s == ' ')
				continue;
	}
	return NULL;
}
/*
**  REMOVEMECH -- remove item [rem] from list [list]
**
**	Parameters:
**		rem -- item to remove
**		list -- list of items
**
**	Returns:
**		pointer to new list (NULL in case of error).
*/

char *
removemech(rem, list)
	char *rem;
	char *list;
{
	char *ret;
	char *needle;
	int len;

	if (list == NULL)
		return NULL;
	if (rem == NULL || *rem == '\0')
	{
		/* take out what? */
		return NULL;
	}

	/* find the item in the list */
	if ((needle = iteminlist(rem, list, " ")) == NULL)
	{
		/* not in there: return original */
		return list;
	}

	/* length of string without rem */
	len = strlen(list) - strlen(rem);
	if (len == 0)
	{
		ret = xalloc(1);  /* XXX leaked */
		*ret = '\0';
		return ret;
	}
	ret = xalloc(len);  /* XXX leaked */
	memset(ret, '\0', len);

	/* copy from start to removed item */
	memcpy(ret, list, needle - list);

	/* length of rest of string past removed item */
	len = strlen(needle) - strlen(rem) - 1;
	if (len > 0)
	{
		/* not last item -- copy into string */
		memcpy(ret + (needle - list),
		       list + (needle - list) + strlen(rem) + 1,
		       len);
	}
	else
		ret[(needle - list) - 1] = '\0';
	return ret;
}
/*
**  INTERSECT -- create the intersection between two lists
**
**	Parameters:
**		s1, s2 -- lists of items (separated by single blanks).
**
**	Returns:
**		the intersection of both lists.
*/

char *
intersect(s1, s2)
	char *s1, *s2;
{
	char *hr, *h1, *h, *res;
	int l1, l2, rl;

	if (s1 == NULL || s2 == NULL)	/* NULL string(s) -> NULL result */
		return NULL;
	l1 = strlen(s1);
	l2 = strlen(s2);
	rl = min(l1, l2);
	res = (char *)malloc(rl + 1);
	if (res == NULL)
		return NULL;
	*res = '\0';
	if (rl == 0)	/* at least one string empty? */
		return res;
	hr = res;
	h1 = s1;
	h = s1;

	/* walk through s1 */
	while (h != NULL && *h1 != '\0')
	{
		/* is there something after the current word? */
		if ((h = strchr(h1, ' ')) != NULL)
			*h = '\0';
		l1 = strlen(h1);

		/* does the current word appear in s2 ? */
		if (iteminlist(h1, s2, " ") != NULL)
		{
			/* add a blank if not first item */
			if (hr != res)
				*hr++ = ' ';

			/* copy the item */
			memcpy(hr, h1, l1);

			/* advance pointer in result list */
			hr += l1;
			*hr = '\0';
		}
		if (h != NULL)
		{
			/* there are more items */
			*h = ' ';
			h1 = h + 1;
		}
	}
	return res;
}
/*
**  ATTEMPTAUTH -- try to AUTHenticate using one mechanism
**
**	Parameters:
**		m -- the mailer.
**		mci -- the mailer connection structure.
**		e -- the envelope (including the sender to specify).
**		mechused - filled in with mechanism used
**
**	Returns:
**		EX_OK/EX_TEMPFAIL
*/

int
attemptauth(m, mci, e, mechused)
	MAILER *m;
	MCI *mci;
	ENVELOPE *e;
	char **mechused;
{
	int saslresult, smtpresult;
	sasl_external_properties_t ssf;
	sasl_interact_t *client_interact = NULL;
	char *out;
	unsigned int outlen;
	static char *mechusing;
	sasl_security_properties_t ssp;
	char in64[MAXOUTLEN];
# if NETINET
	extern SOCKADDR CurHostAddr;
# endif /* NETINET */

	*mechused = NULL;
	if (mci->mci_conn != NULL)
	{
		sasl_dispose(&(mci->mci_conn));

		/* just in case, sasl_dispose() should take care of it */
		mci->mci_conn = NULL;
	}

	/* make a new client sasl connection */
	saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
								 : "smtp",
				     CurHostName, NULL, 0, &mci->mci_conn);

	/* set properties */
	(void) memset(&ssp, '\0', sizeof ssp);
#  if SFIO
	/* XXX should these be options settable via .cf ? */
	/* ssp.min_ssf = 0; is default due to memset() */
	{
		ssp.max_ssf = INT_MAX;
		ssp.maxbufsize = MAXOUTLEN;
#   if 0
		ssp.security_flags = SASL_SEC_NOPLAINTEXT;
#   endif /* 0 */
	}
#  endif /* SFIO */
	saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
	if (saslresult != SASL_OK)
		return EX_TEMPFAIL;

	/* external security strength factor, authentication id */
	ssf.ssf = 0;
	ssf.auth_id = NULL;
# if _FFR_EXT_MECH
	out = macvalue(macid("{cert_subject}", NULL), e);
	if (out != NULL && *out != '\0')
		ssf.auth_id = out;
	out = macvalue(macid("{cipher_bits}", NULL), e);
	if (out != NULL && *out != '\0')
		ssf.ssf = atoi(out);
# endif /* _FFR_EXT_MECH */
	saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
	if (saslresult != SASL_OK)
		return EX_TEMPFAIL;

# if NETINET
	/* set local/remote ipv4 addresses */
	if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
	{
		SOCKADDR_LEN_T addrsize;
		struct sockaddr_in saddr_l;

		if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE,
				 (struct sockaddr_in *) &CurHostAddr)
		    != SASL_OK)
			return EX_TEMPFAIL;
		addrsize = sizeof(struct sockaddr_in);
		if (getsockname(fileno(mci->mci_out),
				(struct sockaddr *) &saddr_l, &addrsize) != 0)
		{
			if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
					 &saddr_l) != SASL_OK)
				return EX_TEMPFAIL;
		}
	}
# endif /* NETINET */

	/* start client side of sasl */
	saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
				       NULL, &client_interact,
				       &out, &outlen,
				       (const char **)&mechusing);
	callbacks[CB_AUTHNAME_IDX].context = mechusing;

	if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
	{
#  if SFIO
		if (saslresult == SASL_NOMECH && LogLevel > 8)
		{
			sm_syslog(LOG_NOTICE, e->e_id,
				  "available AUTH mechanisms do not fulfill requirements");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -