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

📄 recipient.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*
	**  If RunAsUser set, won't be able to run programs as user
	**  so mark them as unsafe unless the administrator knows better.
	*/

	if ((geteuid() != 0 || RunAsUid != 0) &&
	    !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail))
	{
		if (tTd(27, 4))
			dprintf("include: not safe (euid=%d, RunAsUid=%d)\n",
				(int) geteuid(), (int) RunAsUid);
		ctladdr->q_flags |= QUNSAFEADDR;
	}

	ca = getctladdr(ctladdr);
	if (ca == NULL ||
	    (ca->q_uid == DefUid && ca->q_gid == 0))
	{
		uid = DefUid;
		gid = DefGid;
		user = DefUser;
	}
	else
	{
		uid = ca->q_uid;
		gid = ca->q_gid;
		user = ca->q_user;
	}
#if MAILER_SETUID_METHOD != USE_SETUID
	saveduid = geteuid();
	savedgid = getegid();
	if (saveduid == 0)
	{
		if (!DontInitGroups)
		{
			if (initgroups(user, gid) == -1)
			{
				rval = EAGAIN;
				syserr("include: initgroups(%s, %d) failed",
					user, gid);
				goto resetuid;
			}
		}
		else
		{
			GIDSET_T gidset[1];

			gidset[0] = gid;
			if (setgroups(1, gidset) == -1)
			{
				rval = EAGAIN;
				syserr("include: setgroups() failed");
				goto resetuid;
			}
		}

		if (gid != 0 && setgid(gid) < -1)
		{
			rval = EAGAIN;
			syserr("setgid(%d) failure", gid);
			goto resetuid;
		}
		if (uid != 0)
		{
# if MAILER_SETUID_METHOD == USE_SETEUID
			if (seteuid(uid) < 0)
			{
				rval = EAGAIN;
				syserr("seteuid(%d) failure (real=%d, eff=%d)",
					uid, getuid(), geteuid());
				goto resetuid;
			}
# endif /* MAILER_SETUID_METHOD == USE_SETEUID */
# if MAILER_SETUID_METHOD == USE_SETREUID
			if (setreuid(0, uid) < 0)
			{
				rval = EAGAIN;
				syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
					uid, getuid(), geteuid());
				goto resetuid;
			}
# endif /* MAILER_SETUID_METHOD == USE_SETREUID */
		}
	}
#endif /* MAILER_SETUID_METHOD != USE_SETUID */

	if (tTd(27, 9))
		dprintf("include: new uid = %d/%d\n",
			(int) getuid(), (int) geteuid());

	/*
	**  If home directory is remote mounted but server is down,
	**  this can hang or give errors; use a timeout to avoid this
	*/

	if (setjmp(CtxIncludeTimeout) != 0)
	{
		ctladdr->q_state = QS_QUEUEUP;
		errno = 0;

		/* return pseudo-error code */
		rval = E_SM_OPENTIMEOUT;
		goto resetuid;
	}
	if (TimeOuts.to_fileopen > 0)
		ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
	else
		ev = NULL;


	/* check for writable parent directory */
	p = strrchr(fname, '/');
	if (p != NULL)
	{
		int ret;

		*p = '\0';
		ret = safedirpath(fname, uid, gid, user,
				  sfflags|SFF_SAFEDIRPATH, 0, 0);
		if (ret == 0)
		{
			/* in safe directory: relax chown & link rules */
			safedir = TRUE;
			sfflags |= SFF_NOPATHCHECK;
		}
		else
		{
			if (bitnset((forwarding ?
				     DBS_FORWARDFILEINUNSAFEDIRPATH :
				     DBS_INCLUDEFILEINUNSAFEDIRPATH),
				    DontBlameSendmail))
				sfflags |= SFF_NOPATHCHECK;
			else if (bitnset((forwarding ?
					  DBS_FORWARDFILEINGROUPWRITABLEDIRPATH :
					  DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH),
					 DontBlameSendmail) &&
				 ret == E_SM_GWDIR)
			{
				setbitn(DBS_GROUPWRITABLEDIRPATHSAFE,
					DontBlameSendmail);
				ret = safedirpath(fname, uid, gid, user,
						  sfflags|SFF_SAFEDIRPATH,
						  0, 0);
				clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE,
					DontBlameSendmail);
				if (ret == 0)
					sfflags |= SFF_NOPATHCHECK;
				else
					sfflags |= SFF_SAFEDIRPATH;
			}
			else
				sfflags |= SFF_SAFEDIRPATH;
			if (ret > E_PSEUDOBASE &&
			    !bitnset((forwarding ?
				      DBS_FORWARDFILEINUNSAFEDIRPATHSAFE :
				      DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE),
				     DontBlameSendmail))
			{
				if (LogLevel >= 12)
					sm_syslog(LOG_INFO, e->e_id,
						  "%s: unsafe directory path, marked unsafe",
						  shortenstring(fname, MAXSHORTSTR));
				ctladdr->q_flags |= QUNSAFEADDR;
			}
		}
		*p = '/';
	}

	/* allow links only in unwritable directories */
	if (!safedir &&
	    !bitnset((forwarding ?
		      DBS_LINKEDFORWARDFILEINWRITABLEDIR :
		      DBS_LINKEDINCLUDEFILEINWRITABLEDIR),
		     DontBlameSendmail))
		sfflags |= SFF_NOLINK;

	rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st);
	if (rval != 0)
	{
		/* don't use this :include: file */
		if (tTd(27, 4))
			dprintf("include: not safe (uid=%d): %s\n",
				(int) uid, errstring(rval));
	}
	else if ((fp = fopen(fname, "r")) == NULL)
	{
		rval = errno;
		if (tTd(27, 4))
			dprintf("include: open: %s\n", errstring(rval));
	}
	else if (filechanged(fname, fileno(fp), &st))
	{
		rval = E_SM_FILECHANGE;
		if (tTd(27, 4))
			dprintf("include: file changed after open\n");
	}
	if (ev != NULL)
		clrevent(ev);

resetuid:

#if HASSETREUID || USESETEUID
	if (saveduid == 0)
	{
		if (uid != 0)
		{
# if USESETEUID
			if (seteuid(0) < 0)
				syserr("!seteuid(0) failure (real=%d, eff=%d)",
					getuid(), geteuid());
# else /* USESETEUID */
			if (setreuid(-1, 0) < 0)
				syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)",
					getuid(), geteuid());
			if (setreuid(RealUid, 0) < 0)
				syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)",
					RealUid, getuid(), geteuid());
# endif /* USESETEUID */
		}
		if (setgid(savedgid) < 0)
			syserr("!setgid(%d) failure (real=%d eff=%d)",
			       savedgid, getgid(), getegid());
	}
#endif /* HASSETREUID || USESETEUID */

	if (tTd(27, 9))
		dprintf("include: reset uid = %d/%d\n",
			(int) getuid(), (int) geteuid());

	if (rval == E_SM_OPENTIMEOUT)
		usrerr("451 4.4.1 open timeout on %s", fname);

	if (fp == NULL)
		return rval;

	if (fstat(fileno(fp), &st) < 0)
	{
		rval = errno;
		syserr("Cannot fstat %s!", fname);
		(void) fclose(fp);
		return rval;
	}

	/* if path was writable, check to avoid file giveaway tricks */
	safechown = chownsafe(fileno(fp), safedir);
	if (tTd(27, 6))
		dprintf("include: parent of %s is %s, chown is %ssafe\n",
			fname,
			safedir ? "safe" : "dangerous",
			safechown ? "" : "un");

	/* if no controlling user or coming from an alias delivery */
	if (safechown &&
	    (ca == NULL ||
	     (ca->q_uid == DefUid && ca->q_gid == 0)))
	{
		ctladdr->q_uid = st.st_uid;
		ctladdr->q_gid = st.st_gid;
		ctladdr->q_flags |= QGOODUID;
	}
	if (ca != NULL && ca->q_uid == st.st_uid)
	{
		/* optimization -- avoid getpwuid if we already have info */
		ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
		ctladdr->q_ruser = ca->q_ruser;
	}
	else if (!forwarding)
	{
		register struct passwd *pw;

		pw = sm_getpwuid(st.st_uid);
		if (pw == NULL)
		{
			ctladdr->q_uid = st.st_uid;
			ctladdr->q_flags |= QBOGUSSHELL;
		}
		else
		{
			char *sh;

			ctladdr->q_ruser = newstr(pw->pw_name);
			if (safechown)
				sh = pw->pw_shell;
			else
				sh = "/SENDMAIL/ANY/SHELL/";
			if (!usershellok(pw->pw_name, sh))
			{
				if (LogLevel >= 12)
					sm_syslog(LOG_INFO, e->e_id,
						  "%s: user %s has bad shell %s, marked %s",
						  shortenstring(fname, MAXSHORTSTR),
						  pw->pw_name, sh,
						  safechown ? "bogus" : "unsafe");
				if (safechown)
					ctladdr->q_flags |= QBOGUSSHELL;
				else
					ctladdr->q_flags |= QUNSAFEADDR;
			}
		}
	}

	if (bitset(EF_VRFYONLY, e->e_flags))
	{
		/* don't do any more now */
		ctladdr->q_state = QS_VERIFIED;
		e->e_nrcpts++;
		(void) fclose(fp);
		return rval;
	}

	/*
	**  Check to see if some bad guy can write this file
	**
	**	Group write checking could be more clever, e.g.,
	**	guessing as to which groups are actually safe ("sys"
	**	may be; "user" probably is not).
	*/

	mode = S_IWOTH;
	if (!bitnset((forwarding ?
		      DBS_GROUPWRITABLEFORWARDFILESAFE :
		      DBS_GROUPWRITABLEINCLUDEFILESAFE),
		     DontBlameSendmail))
		mode |= S_IWGRP;

	if (bitset(mode, st.st_mode))
	{
		if (tTd(27, 6))
			dprintf("include: %s is %s writable, marked unsafe\n",
				shortenstring(fname, MAXSHORTSTR),
				bitset(S_IWOTH, st.st_mode) ? "world" : "group");
		if (LogLevel >= 12)
			sm_syslog(LOG_INFO, e->e_id,
				  "%s: %s writable %s file, marked unsafe",
				  shortenstring(fname, MAXSHORTSTR),
				  bitset(S_IWOTH, st.st_mode) ? "world" : "group",
				  forwarding ? "forward" : ":include:");
		ctladdr->q_flags |= QUNSAFEADDR;
	}

	/* read the file -- each line is a comma-separated list. */
	FileName = fname;
	LineNumber = 0;
	ctladdr->q_flags &= ~QSELFREF;
	nincludes = 0;
	while (fgets(buf, sizeof buf, fp) != NULL && !maxreached)
	{
		fixcrlf(buf, TRUE);
		LineNumber++;
		if (buf[0] == '#' || buf[0] == '\0')
			continue;

		/* <sp>#@# introduces a comment anywhere */
		/* for Japanese character sets */
		for (p = buf; (p = strchr(++p, '#')) != NULL; )
		{
			if (p[1] == '@' && p[2] == '#' &&
			    isascii(p[-1]) && isspace(p[-1]) &&
			    (p[3] == '\0' || (isascii(p[3]) && isspace(p[3]))))
			{
				--p;
				while (p > buf && isascii(p[-1]) &&
				       isspace(p[-1]))
					--p;
				p[0] = '\0';
				break;
			}
		}
		if (buf[0] == '\0')
			continue;

		e->e_to = NULL;
		message("%s to %s",
			forwarding ? "forwarding" : "sending", buf);
		if (forwarding && LogLevel > 10)
			sm_syslog(LOG_INFO, e->e_id,
				  "forward %.200s => %s",
				  oldto, shortenstring(buf, MAXSHORTSTR));

		nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);

		if (forwarding &&
		    MaxForwardEntries > 0 &&
		    nincludes >= MaxForwardEntries)
		{
			/* just stop reading and processing further entries */
			/* additional: (?)
			ctladdr->q_state = QS_DONTSEND;
			**/
			syserr("Attempt to forward to more then %d addresses (in %s)!",
				MaxForwardEntries,fname);
			maxreached = TRUE;
		}
	}

	if (ferror(fp) && tTd(27, 3))
		dprintf("include: read error: %s\n", errstring(errno));
	if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
	{
		if (tTd(27, 5))
		{
			dprintf("include: QS_DONTSEND ");
			printaddr(ctladdr, FALSE);
		}
		ctladdr->q_state = QS_DONTSEND;
	}

	(void) fclose(fp);
	FileName = oldfilename;
	LineNumber = oldlinenumber;
	e->e_to = oldto;
	return rval;
}

static void
includetimeout()
{
	longjmp(CtxIncludeTimeout, 1);
}
/*
**  SENDTOARGV -- send to an argument vector.
**
**	Parameters:
**		argv -- argument vector to send to.
**		e -- the current envelope.
**
**	Returns:
**		none.
**
**	Side Effects:
**		puts all addresses on the argument vector onto the
**			send queue.
*/

void
sendtoargv(argv, e)
	register char **argv;
	register ENVELOPE *e;
{
	register char *p;

	while ((p = *argv++) != NULL)
	{
		(void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
	}
}
/*
**  GETCTLADDR -- get controlling address from an address header.
**
**	If none, get one corresponding to the effective userid.
**
**	Parameters:
**		a -- the address to find the controller of.
**
**	Returns:
**		the controlling address.
**
**	Side Effects:
**		none.
*/

ADDRESS *
getctladdr(a)
	register ADDRESS *a;
{
	while (a != NULL && !bitset(QGOODUID, a->q_flags))
		a = a->q_alias;
	return a;
}
/*
**  SELF_REFERENCE -- check to see if an address references itself
**
**	The check is done through a chain of aliases.  If it is part of
**	a loop, break the loop at the "best" address, that is, the one
**	that exists as a real user.
**
**	This is to handle the case of:
**		awc:		Andrew.Chang
**		Andrew.Chang:	awc@mail.server
**	which is a problem only on mail.server.
**
**	Parameters:
**		a -- the address to check.
**
**	Returns:
**		The address that should be retained.
*/

static ADDRESS *
self_reference(a)
	ADDRESS *a;
{
	ADDRESS *b;		/* top entry in self ref loop */
	ADDRESS *c;		/* entry that point to a real mail box */

	if (tTd(27, 1))
		dprintf("self_reference(%s)\n", a->q_paddr);

	for (b = a->q_alias; b != NULL; b = b->q_alias)
	{
		if (sameaddr(a, b))
			break;
	}

	if (b == NULL)
	{
		if (tTd(27, 1))
			dprintf("\t... no self ref\n");
		return NULL;
	}

	/*
	**  Pick the first address that resolved to a real mail box
	**  i.e has a pw entry.  The returned value will be marked
	**  QSELFREF in recipient(), which in turn will disable alias()
	**  from marking it as QS_IS_DEAD(), which mean it will be used
	**  as a deliverable address.
	**
	**  The 2 key thing to note here are:
	**	1) we are in a recursive call sequence:
	**		alias->sentolist->recipient->alias
	**	2) normally, when we return back to alias(), the address
	**	   will be marked QS_EXPANDED, since alias() assumes the
	**	   expanded form will be used instead of the current address.
	**	   This behaviour is turned off if the address is marked
	**	   QSELFREF We set QSELFREF when we return to recipient().
	*/

	c = a;
	while (c != NULL)
	{
		if (tTd(27, 10))
			dprintf("  %s", c->q_user);
		if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
		{
			if (tTd(27, 2))
				dprintf("\t... getpwnam(%s)... ", c->q_user);
			if (sm_getpwnam(c->q_user) != NULL)
			{
				if (tTd(27, 2))
					dprintf("found\n");

				/* ought to cache results here */
				if (sameaddr(b, c))
					return b;
				else
					return c;
			}
			if (tTd(27, 2))
				dprintf("failed\n");
		}
		else
		{
			/* if local delivery, compare usernames */
			if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) &&
			    b->q_mailer == c->q_mailer)
			{
				if (tTd(27, 2))
					dprintf("\t... local match (%s)\n",
						c->q_user);
				if (sameaddr(b, c))
					return b;
				else
					return c;
			}
		}
		if (tTd(27, 10))
			dprintf("\n");
		c = c->q_alias;
	}

	if (tTd(27, 1))
		dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr);

	return NULL;
}

⌨️ 快捷键说明

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