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

📄 recipient.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 3 页
字号:
					errstring(ret));
			}
			else if (ret != 0)
			{
				a->q_state = QS_BADADDR;
				a->q_status = "5.2.4";
				usrerrenh(a->q_status,
					  "550 Cannot open %s: %s",
					  shortenstring(a->q_user, MAXSHORTSTR),
					  errstring(ret));
			}
		}
	}
	else if (m == FileMailer)
	{
		/* check if writable or creatable */
		if (a->q_alias == NULL)
		{
			a->q_state = QS_BADADDR;
			a->q_status = "5.7.1";
			usrerrenh(a->q_status,
				  "550 Cannot mail directly to files");
		}
		else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
		{
			a->q_state = QS_BADADDR;
			a->q_status = "5.7.1";
			if (a->q_alias->q_ruser == NULL)
				usrerrenh(a->q_status,
					  "550 UID %d is an unknown user: cannot mail to files",
					  a->q_alias->q_uid);
			else
				usrerrenh(a->q_status,
					  "550 User %s@%s doesn't have a valid shell for mailing to files",
					  a->q_alias->q_ruser, MyHostName);
		}
		else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
		{
			a->q_state = QS_BADADDR;
			a->q_status = "5.7.1";
			a->q_rstatus = newstr("550 Unsafe for mailing to files");
			usrerrenh(a->q_status,
				  "550 Address %s is unsafe for mailing to files",
				  a->q_alias->q_paddr);
		}
	}

	/* try aliasing */
	if (!quoted && QS_IS_OK(a->q_state) &&
	    bitnset(M_ALIASABLE, m->m_flags))
		alias(a, sendq, aliaslevel, e);

#if USERDB
	/* if not aliased, look it up in the user database */
	if (!bitset(QNOTREMOTE, a->q_flags) &&
	    QS_IS_SENDABLE(a->q_state) &&
	    bitnset(M_CHECKUDB, m->m_flags))
	{
		if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
		{
			a->q_state = QS_QUEUEUP;
			if (e->e_message == NULL)
				e->e_message = newstr("Deferred: user database error");
			if (LogLevel > 8)
				sm_syslog(LOG_INFO, e->e_id,
					  "deferred: udbexpand: %s",
					  errstring(errno));
			message("queued (user database error): %s",
				errstring(errno));
			e->e_nrcpts++;
			goto testselfdestruct;
		}
	}
#endif /* USERDB */

	/*
	**  If we have a level two config file, then pass the name through
	**  Ruleset 5 before sending it off.  Ruleset 5 has the right
	**  to send rewrite it to another mailer.  This gives us a hook
	**  after local aliasing has been done.
	*/

	if (tTd(29, 5))
	{
		dprintf("recipient: testing local?  cl=%d, rr5=%lx\n\t",
			ConfigLevel, (u_long) RewriteRules[5]);
		printaddr(a, FALSE);
	}
	if (ConfigLevel >= 2 && RewriteRules[5] != NULL &&
	    bitnset(M_TRYRULESET5, m->m_flags) &&
	    !bitset(QNOTREMOTE, a->q_flags) &&
	    QS_IS_OK(a->q_state))
	{
		maplocaluser(a, sendq, aliaslevel + 1, e);
	}

	/*
	**  If it didn't get rewritten to another mailer, go ahead
	**  and deliver it.
	*/

	if (QS_IS_OK(a->q_state) &&
	    bitnset(M_HASPWENT, m->m_flags))
	{
		auto bool fuzzy;
		register struct passwd *pw;

		/* warning -- finduser may trash buf */
		pw = finduser(buf, &fuzzy);
		if (pw == NULL || strlen(pw->pw_name) > MAXNAME)
		{
			{
				a->q_state = QS_BADADDR;
				a->q_status = "5.1.1";
				a->q_rstatus = newstr("550 5.1.1 User unknown");
				giveresponse(EX_NOUSER, a->q_status, m, NULL,
					     a->q_alias, (time_t) 0, e);
			}
		}
		else
		{
			char nbuf[MAXNAME + 1];

			if (fuzzy)
			{
				/* name was a fuzzy match */
				a->q_user = newstr(pw->pw_name);
				if (findusercount++ > 3)
				{
					a->q_state = QS_BADADDR;
					a->q_status = "5.4.6";
					usrerrenh(a->q_status,
						  "554 aliasing/forwarding loop for %s broken",
						  pw->pw_name);
					goto done;
				}

				/* see if it aliases */
				(void) strlcpy(buf, pw->pw_name, buflen);
				goto trylocaluser;
			}
			if (*pw->pw_dir == '\0')
				a->q_home = NULL;
			else if (strcmp(pw->pw_dir, "/") == 0)
				a->q_home = "";
			else
				a->q_home = newstr(pw->pw_dir);
			a->q_uid = pw->pw_uid;
			a->q_gid = pw->pw_gid;
			a->q_ruser = newstr(pw->pw_name);
			a->q_flags |= QGOODUID;
			buildfname(pw->pw_gecos, pw->pw_name, nbuf, sizeof nbuf);
			if (nbuf[0] != '\0')
				a->q_fullname = newstr(nbuf);
			if (!usershellok(pw->pw_name, pw->pw_shell))
			{
				a->q_flags |= QBOGUSSHELL;
			}
			if (bitset(EF_VRFYONLY, e->e_flags))
			{
				/* don't do any more now */
				a->q_state = QS_VERIFIED;
			}
			else if (!quoted)
				forward(a, sendq, aliaslevel, e);
		}
	}
	if (!QS_IS_DEAD(a->q_state))
		e->e_nrcpts++;

  testselfdestruct:
	a->q_flags |= QTHISPASS;
	if (tTd(26, 8))
	{
		dprintf("testselfdestruct: ");
		printaddr(a, FALSE);
		if (tTd(26, 10))
		{
			dprintf("SENDQ:\n");
			printaddr(*sendq, TRUE);
			dprintf("----\n");
		}
	}
	if (a->q_alias == NULL && a != &e->e_from &&
	    QS_IS_DEAD(a->q_state))
	{
		for (q = *sendq; q != NULL; q = q->q_next)
		{
			if (!QS_IS_DEAD(q->q_state))
				break;
		}
		if (q == NULL)
		{
			a->q_state = QS_BADADDR;
			a->q_status = "5.4.6";
			usrerrenh(a->q_status,
				  "554 aliasing/forwarding loop broken");
		}
	}

  done:
	a->q_flags |= QTHISPASS;
	if (buf != buf0)
		free(buf);

	/*
	**  If we are at the top level, check to see if this has
	**  expanded to exactly one address.  If so, it can inherit
	**  the primaryness of the address.
	**
	**  While we're at it, clear the QTHISPASS bits.
	*/

	if (aliaslevel == 0)
	{
		int nrcpts = 0;
		ADDRESS *only = NULL;

		for (q = *sendq; q != NULL; q = q->q_next)
		{
			if (bitset(QTHISPASS, q->q_flags) &&
			    QS_IS_SENDABLE(q->q_state))
			{
				nrcpts++;
				only = q;
			}
			q->q_flags &= ~QTHISPASS;
		}
		if (nrcpts == 1)
		{
			/* check to see if this actually got a new owner */
			q = only;
			while ((q = q->q_alias) != NULL)
			{
				if (q->q_owner != NULL)
					break;
			}
			if (q == NULL)
				only->q_flags |= QPRIMARY;
		}
		else if (!initialdontsend && nrcpts > 0)
		{
			/* arrange for return receipt */
			e->e_flags |= EF_SENDRECEIPT;
			a->q_flags |= QEXPANDED;
			if (e->e_xfp != NULL &&
			    bitset(QPINGONSUCCESS, a->q_flags))
				fprintf(e->e_xfp,
					"%s... expanded to multiple addresses\n",
					a->q_paddr);
		}
	}
	a->q_flags |= QRCPTOK;
	return a;
}
/*
**  FINDUSER -- find the password entry for a user.
**
**	This looks a lot like getpwnam, except that it may want to
**	do some fancier pattern matching in /etc/passwd.
**
**	This routine contains most of the time of many sendmail runs.
**	It deserves to be optimized.
**
**	Parameters:
**		name -- the name to match against.
**		fuzzyp -- an outarg that is set to TRUE if this entry
**			was found using the fuzzy matching algorithm;
**			set to FALSE otherwise.
**
**	Returns:
**		A pointer to a pw struct.
**		NULL if name is unknown or ambiguous.
**
**	Side Effects:
**		may modify name.
*/

struct passwd *
finduser(name, fuzzyp)
	char *name;
	bool *fuzzyp;
{
	register struct passwd *pw;
	register char *p;
	bool tryagain;

	if (tTd(29, 4))
		dprintf("finduser(%s): ", name);

	*fuzzyp = FALSE;

#ifdef HESIOD
	/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
	for (p = name; *p != '\0'; p++)
		if (!isascii(*p) || !isdigit(*p))
			break;
	if (*p == '\0')
	{
		if (tTd(29, 4))
			dprintf("failed (numeric input)\n");
		return NULL;
	}
#endif /* HESIOD */

	/* look up this login name using fast path */
	if ((pw = sm_getpwnam(name)) != NULL)
	{
		if (tTd(29, 4))
			dprintf("found (non-fuzzy)\n");
		return pw;
	}

	/* try mapping it to lower case */
	tryagain = FALSE;
	for (p = name; *p != '\0'; p++)
	{
		if (isascii(*p) && isupper(*p))
		{
			*p = tolower(*p);
			tryagain = TRUE;
		}
	}
	if (tryagain && (pw = sm_getpwnam(name)) != NULL)
	{
		if (tTd(29, 4))
			dprintf("found (lower case)\n");
		*fuzzyp = TRUE;
		return pw;
	}

#if MATCHGECOS
	/* see if fuzzy matching allowed */
	if (!MatchGecos)
	{
		if (tTd(29, 4))
			dprintf("not found (fuzzy disabled)\n");
		return NULL;
	}

	/* search for a matching full name instead */
	for (p = name; *p != '\0'; p++)
	{
		if (*p == (SpaceSub & 0177) || *p == '_')
			*p = ' ';
	}
	(void) setpwent();
	while ((pw = getpwent()) != NULL)
	{
		char buf[MAXNAME + 1];

# if 0
		if (strcasecmp(pw->pw_name, name) == 0)
		{
			if (tTd(29, 4))
				dprintf("found (case wrapped)\n");
			break;
		}
# endif /* 0 */

		buildfname(pw->pw_gecos, pw->pw_name, buf, sizeof buf);
		if (strchr(buf, ' ') != NULL && strcasecmp(buf, name) == 0)
		{
			if (tTd(29, 4))
				dprintf("fuzzy matches %s\n", pw->pw_name);
			message("sending to login name %s", pw->pw_name);
			break;
		}
	}
	if (pw != NULL)
		*fuzzyp = TRUE;
	else if (tTd(29, 4))
		dprintf("no fuzzy match found\n");
# if DEC_OSF_BROKEN_GETPWENT	/* DEC OSF/1 3.2 or earlier */
	endpwent();
# endif /* DEC_OSF_BROKEN_GETPWENT */
	return pw;
#else /* MATCHGECOS */
	if (tTd(29, 4))
		dprintf("not found (fuzzy disabled)\n");
	return NULL;
#endif /* MATCHGECOS */
}
/*
**  WRITABLE -- predicate returning if the file is writable.
**
**	This routine must duplicate the algorithm in sys/fio.c.
**	Unfortunately, we cannot use the access call since we
**	won't necessarily be the real uid when we try to
**	actually open the file.
**
**	Notice that ANY file with ANY execute bit is automatically
**	not writable.  This is also enforced by mailfile.
**
**	Parameters:
**		filename -- the file name to check.
**		ctladdr -- the controlling address for this file.
**		flags -- SFF_* flags to control the function.
**
**	Returns:
**		TRUE -- if we will be able to write this file.
**		FALSE -- if we cannot write this file.
**
**	Side Effects:
**		none.
*/

bool
writable(filename, ctladdr, flags)
	char *filename;
	ADDRESS *ctladdr;
	long flags;
{
	uid_t euid = 0;
	gid_t egid = 0;
	char *user = NULL;

	if (tTd(44, 5))
		dprintf("writable(%s, 0x%lx)\n", filename, flags);

	/*
	**  File does exist -- check that it is writable.
	*/

	if (geteuid() != 0)
	{
		euid = geteuid();
		egid = getegid();
		user = NULL;
	}
	else if (ctladdr != NULL)
	{
		euid = ctladdr->q_uid;
		egid = ctladdr->q_gid;
		user = ctladdr->q_user;
	}
	else if (bitset(SFF_RUNASREALUID, flags))
	{
		euid = RealUid;
		egid = RealGid;
		user = RealUserName;
	}
	else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags))
	{
		euid = FileMailer->m_uid;
		egid = FileMailer->m_gid;
		user = NULL;
	}
	else
	{
		euid = egid = 0;
		user = NULL;
	}
	if (!bitset(SFF_ROOTOK, flags))
	{
		if (euid == 0)
		{
			euid = DefUid;
			user = DefUser;
		}
		if (egid == 0)
			egid = DefGid;
	}
	if (geteuid() == 0 &&
	    (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags)))
		flags |= SFF_SETUIDOK;

	if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
		flags |= SFF_NOSLINK;
	if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
		flags |= SFF_NOHLINK;

	errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL);
	return errno == 0;
}
/*
**  INCLUDE -- handle :include: specification.
**
**	Parameters:
**		fname -- filename to include.
**		forwarding -- if TRUE, we are reading a .forward file.
**			if FALSE, it's a :include: file.
**		ctladdr -- address template to use to fill in these
**			addresses -- effective user/group id are
**			the important things.
**		sendq -- a pointer to the head of the send queue
**			to put these addresses in.
**		aliaslevel -- the alias nesting depth.
**		e -- the current envelope.
**
**	Returns:
**		open error status
**
**	Side Effects:
**		reads the :include: file and sends to everyone
**		listed in that file.
**
**	Security Note:
**		If you have restricted chown (that is, you can't
**		give a file away), it is reasonable to allow programs
**		and files called from this :include: file to be to be
**		run as the owner of the :include: file.  This is bogus
**		if there is any chance of someone giving away a file.
**		We assume that pre-POSIX systems can give away files.
**
**		There is an additional restriction that if you
**		forward to a :include: file, it will not take on
**		the ownership of the :include: file.  This may not
**		be necessary, but shouldn't hurt.
*/

static jmp_buf	CtxIncludeTimeout;

int
include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
	char *fname;
	bool forwarding;
	ADDRESS *ctladdr;
	ADDRESS **sendq;
	int aliaslevel;
	ENVELOPE *e;
{
	FILE *volatile fp = NULL;
	char *oldto = e->e_to;
	char *oldfilename = FileName;
	int oldlinenumber = LineNumber;
	register EVENT *ev = NULL;
	int nincludes;
	int mode;
	volatile bool maxreached = FALSE;
	register ADDRESS *ca;
	volatile uid_t saveduid;
	volatile gid_t savedgid;
	volatile uid_t uid;
	volatile gid_t gid;
	char *volatile user;
	int rval = 0;
	volatile long sfflags = SFF_REGONLY;
	register char *p;
	bool safechown = FALSE;
	volatile bool safedir = FALSE;
	struct stat st;
	char buf[MAXLINE];

	if (tTd(27, 2))
		dprintf("include(%s)\n", fname);
	if (tTd(27, 4))
		dprintf("   ruid=%d euid=%d\n",
			(int) getuid(), (int) geteuid());
	if (tTd(27, 14))
	{
		dprintf("ctladdr ");
		printaddr(ctladdr, FALSE);
	}

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

#if _FFR_UNSAFE_WRITABLE_INCLUDE
	if (forwarding)
	{
		if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail))
			sfflags |= SFF_NOGWFILES;
		if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail))
			sfflags |= SFF_NOWWFILES;
	}
	else
	{
		if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail))
			sfflags |= SFF_NOGWFILES;
		if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail))
			sfflags |= SFF_NOWWFILES;
	}
#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */

	if (forwarding)
		sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOWLINK;

⌨️ 快捷键说明

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