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

📄 queue.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
				  "dowork, pid=%d",
				  getpid());

		/* don't use the headers from sendmail.cf... */
		e->e_header = NULL;

		/* read the queue control file -- return if locked */
		if (!readqf(e))
		{
			if (tTd(40, 4) && e->e_id != NULL)
				dprintf("readqf(%s) failed\n",
					qid_printname(e));
			e->e_id = NULL;
			if (forkflag)
				finis(FALSE, EX_OK);
			else
				return 0;
		}

		e->e_flags |= EF_INQUEUE;
		eatheader(e, requeueflag);

		if (requeueflag)
			queueup(e, FALSE);

		/* do the delivery */
		sendall(e, SM_DELIVER);

		/* finish up and exit */
		if (forkflag)
			finis(TRUE, ExitStat);
		else
			dropenvelope(e, TRUE);
	}
	e->e_id = NULL;
	return pid;
}
/*
**  READQF -- read queue file and set up environment.
**
**	Parameters:
**		e -- the envelope of the job to run.
**
**	Returns:
**		TRUE if it successfully read the queue file.
**		FALSE otherwise.
**
**	Side Effects:
**		The queue file is returned locked.
*/

static bool
readqf(e)
	register ENVELOPE *e;
{
	register FILE *qfp;
	ADDRESS *ctladdr;
	struct stat st;
	char *bp;
	int qfver = 0;
	long hdrsize = 0;
	register char *p;
	char *orcpt = NULL;
	bool nomore = FALSE;
	MODE_T qsafe;
	char qf[MAXPATHLEN];
	char buf[MAXLINE];

	/*
	**  Read and process the file.
	*/

	(void) strlcpy(qf, queuename(e, 'q'), sizeof qf);
	qfp = fopen(qf, "r+");
	if (qfp == NULL)
	{
		int save_errno = errno;

		if (tTd(40, 8))
			dprintf("readqf(%s): fopen failure (%s)\n",
				qf, errstring(errno));
		errno = save_errno;
		if (errno != ENOENT
		    )
			syserr("readqf: no control file %s", qf);
		return FALSE;
	}

	if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
	{
		/* being processed by another queuer */
		if (Verbose)
			printf("%s: locked\n", e->e_id);
		if (tTd(40, 8))
			dprintf("%s: locked\n", e->e_id);
		if (LogLevel > 19)
			sm_syslog(LOG_DEBUG, e->e_id, "locked");
		(void) fclose(qfp);
		return FALSE;
	}

	/*
	**  Check the queue file for plausibility to avoid attacks.
	*/

	if (fstat(fileno(qfp), &st) < 0)
	{
		/* must have been being processed by someone else */
		if (tTd(40, 8))
			dprintf("readqf(%s): fstat failure (%s)\n",
				qf, errstring(errno));
		(void) fclose(qfp);
		return FALSE;
	}

	qsafe = S_IWOTH|S_IWGRP;
#if _FFR_QUEUE_FILE_MODE
	if (bitset(S_IWGRP, QueueFileMode))
		qsafe &= ~S_IWGRP;
#endif /* _FFR_QUEUE_FILE_MODE */

	if ((st.st_uid != geteuid() &&
	     st.st_uid != TrustedUid &&
	     geteuid() != RealUid) ||
	    bitset(qsafe, st.st_mode))
	{
		if (LogLevel > 0)
		{
			sm_syslog(LOG_ALERT, e->e_id,
				  "bogus queue file, uid=%d, mode=%o",
				  st.st_uid, st.st_mode);
		}
		if (tTd(40, 8))
			dprintf("readqf(%s): bogus file\n", qf);
		loseqfile(e, "bogus file uid in mqueue");
		(void) fclose(qfp);
		return FALSE;
	}

	if (st.st_size == 0)
	{
		/* must be a bogus file -- if also old, just remove it */
		if (st.st_ctime + 10 * 60 < curtime())
		{
			(void) xunlink(queuename(e, 'd'));
			(void) xunlink(queuename(e, 'q'));
		}
		(void) fclose(qfp);
		return FALSE;
	}

	if (st.st_nlink == 0)
	{
		/*
		**  Race condition -- we got a file just as it was being
		**  unlinked.  Just assume it is zero length.
		*/

		(void) fclose(qfp);
		return FALSE;
	}

	/* good file -- save this lock */
	e->e_lockfp = qfp;

	/* do basic system initialization */
	initsys(e);
	define('i', e->e_id, e);

	LineNumber = 0;
	e->e_flags |= EF_GLOBALERRS;
	OpMode = MD_QUEUERUN;
	ctladdr = NULL;
	e->e_dfino = -1;
	e->e_msgsize = -1;
# if _FFR_QUEUEDELAY
	e->e_queuealg = QD_LINEAR;
	e->e_queuedelay = (time_t) 0;
# endif /* _FFR_QUEUEDELAY */
	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
	{
		u_long qflags;
		ADDRESS *q;
		int mid;
		auto char *ep;

		if (tTd(40, 4))
			dprintf("+++++ %s\n", bp);
		if (nomore)
		{
			/* hack attack */
			syserr("SECURITY ALERT: extra data in qf: %s", bp);
			(void) fclose(qfp);
			loseqfile(e, "bogus queue line");
			return FALSE;
		}
		switch (bp[0])
		{
		  case 'V':		/* queue file version number */
			qfver = atoi(&bp[1]);
			if (qfver <= QF_VERSION)
				break;
			syserr("Version number in qf (%d) greater than max (%d)",
				qfver, QF_VERSION);
			(void) fclose(qfp);
			loseqfile(e, "unsupported qf file version");
			return FALSE;

		  case 'C':		/* specify controlling user */
			ctladdr = setctluser(&bp[1], qfver);
			break;

		  case 'Q':		/* original recipient */
			orcpt = newstr(&bp[1]);
			break;

		  case 'R':		/* specify recipient */
			p = bp;
			qflags = 0;
			if (qfver >= 1)
			{
				/* get flag bits */
				while (*++p != '\0' && *p != ':')
				{
					switch (*p)
					{
					  case 'N':
						qflags |= QHASNOTIFY;
						break;

					  case 'S':
						qflags |= QPINGONSUCCESS;
						break;

					  case 'F':
						qflags |= QPINGONFAILURE;
						break;

					  case 'D':
						qflags |= QPINGONDELAY;
						break;

					  case 'P':
						qflags |= QPRIMARY;
						break;
					}
				}
			}
			else
				qflags |= QPRIMARY;
			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
			if (q != NULL)
			{
				q->q_alias = ctladdr;
				if (qfver >= 1)
					q->q_flags &= ~Q_PINGFLAGS;
				q->q_flags |= qflags;
				q->q_orcpt = orcpt;
				(void) recipient(q, &e->e_sendqueue, 0, e);
			}
			orcpt = NULL;
			break;

		  case 'E':		/* specify error recipient */
			/* no longer used */
			break;

		  case 'H':		/* header */
			(void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
			hdrsize += strlen(&bp[1]);
			break;

		  case 'L':		/* Solaris Content-Length: */
		  case 'M':		/* message */
			/* ignore this; we want a new message next time */
			break;

		  case 'S':		/* sender */
			setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
			break;

		  case 'B':		/* body type */
			e->e_bodytype = newstr(&bp[1]);
			break;

# if _FFR_SAVE_CHARSET
		  case 'X':		/* character set */
			e->e_charset = newstr(&bp[1]);
			break;
# endif /* _FFR_SAVE_CHARSET */

		  case 'D':		/* data file name */
			/* obsolete -- ignore */
			break;

		  case 'T':		/* init time */
			e->e_ctime = atol(&bp[1]);
			break;

		  case 'I':		/* data file's inode number */
			/* regenerated below */
			break;

		  case 'K':	/* time of last delivery attempt */
			e->e_dtime = atol(&buf[1]);
			break;

# if _FFR_QUEUEDELAY
		  case 'G':	/* queue delay algorithm */
			e->e_queuealg = atoi(&buf[1]);
			break;
		  case 'Y':	/* current delay */
			e->e_queuedelay = (time_t) atol(&buf[1]);
			break;
# endif /* _FFR_QUEUEDELAY */

		  case 'N':		/* number of delivery attempts */
			e->e_ntries = atoi(&buf[1]);

			/* if this has been tried recently, let it be */
			if (e->e_ntries > 0 && e->e_dtime <= curtime() &&
			    curtime() < e->e_dtime + queuedelay(e))
			{
				char *howlong;

				howlong = pintvl(curtime() - e->e_dtime, TRUE);
				if (Verbose)
					printf("%s: too young (%s)\n",
					       e->e_id, howlong);
				if (tTd(40, 8))
					dprintf("%s: too young (%s)\n",
						e->e_id, howlong);
				if (LogLevel > 19)
					sm_syslog(LOG_DEBUG, e->e_id,
						  "too young (%s)",
						  howlong);
				e->e_id = NULL;
				unlockqueue(e);
				return FALSE;
			}
			define(macid("{ntries}", NULL), newstr(&buf[1]), e);

# if NAMED_BIND
			/* adjust BIND parameters immediately */
			if (e->e_ntries == 0)
			{
				_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
				_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
			}
			else
			{
				_res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
				_res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
			}
# endif /* NAMED_BIND */
			break;

		  case 'P':		/* message priority */
			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
			break;

		  case 'F':		/* flag bits */
			if (strncmp(bp, "From ", 5) == 0)
			{
				/* we are being spoofed! */
				syserr("SECURITY ALERT: bogus qf line %s", bp);
				(void) fclose(qfp);
				loseqfile(e, "bogus queue line");
				return FALSE;
			}
			for (p = &bp[1]; *p != '\0'; p++)
			{
				switch (*p)
				{
				  case 'w':	/* warning sent */
					e->e_flags |= EF_WARNING;
					break;

				  case 'r':	/* response */
					e->e_flags |= EF_RESPONSE;
					break;

				  case '8':	/* has 8 bit data */
					e->e_flags |= EF_HAS8BIT;
					break;

				  case 'b':	/* delete Bcc: header */
					e->e_flags |= EF_DELETE_BCC;
					break;

				  case 'd':	/* envelope has DSN RET= */
					e->e_flags |= EF_RET_PARAM;
					break;

				  case 'n':	/* don't return body */
					e->e_flags |= EF_NO_BODY_RETN;
					break;
				}
			}
			break;

		  case 'Z':		/* original envelope id from ESMTP */
			e->e_envid = newstr(&bp[1]);
			define(macid("{dsn_envid}", NULL), newstr(&bp[1]), e);
			break;

		  case 'A':		/* AUTH= parameter */
			e->e_auth_param = newstr(&bp[1]);
			break;

		  case '$':		/* define macro */
			{
				char *p;

				mid = macid(&bp[1], &ep);
				p = newstr(ep);
				define(mid, p, e);

				/*
				**  HACK ALERT: Unfortunately, 8.10 and
				**  8.11 reused the ${if_addr} and
				**  ${if_family} macros for both the incoming
				**  interface address/family (getrequests())
				**  and the outgoing interface address/family
				**  (makeconnection()).  In order for D_BINDIF
				**  to work properly, have to preserve the
				**  incoming information in the queue file for
				**  later delivery attempts.  The original
				**  information is stored in the envelope
				**  in readqf() so it can be stored in
				**  queueup_macros().  This should be fixed
				**  in 8.12.
				*/

				if (strcmp(macname(mid), "if_addr") == 0)
					e->e_if_macros[EIF_ADDR] = p;
			}
			break;

		  case '.':		/* terminate file */
			nomore = TRUE;
			break;

		  default:
			syserr("readqf: %s: line %d: bad line \"%s\"",
				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
			(void) fclose(qfp);
			loseqfile(e, "unrecognized line");
			return FALSE;
		}

		if (bp != buf)
			free(bp);
	}

	/*
	**  If we haven't read any lines, this queue file is empty.
	**  Arrange to remove it without referencing any null pointers.
	*/

	if (LineNumber == 0)
	{
		errno = 0;
		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
		return TRUE;
	}

	/* possibly set ${dsn_ret} macro */
	if (bitset(EF_RET_PARAM, e->e_flags))
	{
		if (bitset(EF_NO_BODY_RETN, e->e_flags))
			define(macid("{dsn_ret}", NULL), "hdrs", e);
		else
			define(macid("{dsn_ret}", NULL), "full", e);
	}

	/*
	**  Arrange to read the data file.
	*/

	p = queuename(e, 'd');
	e->e_dfp = fopen(p, "r");
	if (e->e_dfp == NULL)
	{
		syserr("readqf: cannot open %s", p);
	}
	else
	{
		e->e_flags |= EF_HAS_DF;
		if (fstat(fileno(e->e_dfp), &st) >= 0)
		{
			e->e_msgsize = st.st_size + hdrsize;
			e->e_dfdev = st.st_dev;
			e->e_dfino = st.st_ino;
		}
	}

	return TRUE;
}
/*
**  PRTSTR -- print a string, "unprintable" characters are shown as \oct
**
**	Parameters:
**		s -- string to print
**		ml -- maximum length of output
**
**	Returns:
**		none.
**
**	Side Effects:
**		Prints a string on stdout.
*/

static void
prtstr(s, ml)
	char *s;
	int ml;
{
	char c;

	if (s == NULL)
		return;
	while (ml-- > 0 && ((c = *s++) != '\0'))
	{
		if (c == '\\')
		{
			if (ml-- > 0)
			{
				putchar(c);
				putchar(c);
			}
		}
		else if (isascii(c) && isprint(c))
			putchar(c);
		else
		{
			if ((ml -= 3) > 0)
				printf("\\%03o", c);
		}
	}
}
/*
**  PRINTQUEUE -- print out a representation of the mail queue
**
**	Parameters:
**		none.
**
**	Returns:
**		none.
**
**	Side Effects:
**		Prints a listing of the mail queue on the standard output.
*/

void
printqueue()
{
	int i, nrequests = 0;

	for (i = 0; i < NumQueues; i++)
		nrequests += print_single_queue(i);
	if (NumQueues > 1)
		printf("\t\tTotal Requests: %d\n", nrequests);
}
/*
**  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
**
**	Parameters:
**		queuedir -- queue directory
**
**	Returns:
**		none.
**
**	Side Effects:
**		Prints a listing of the mail queue on the standard output.
*/

static int
print_single_queue(queuedir)
	int queuedir;
{
	register WORK *w;
	FILE *f;
	int nrequests;
	char qd[MAXPATHLEN];
	char qddf[MAXPATHLEN];
	char buf[MAXLINE];

	if (queuedir == NOQDIR)
	{

⌨️ 快捷键说明

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