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

📄 deliver.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
	ADDRESS *ctladdr;	register MCI *mci;	register ADDRESS *to = firstto;	bool clever = FALSE;		/* running user smtp to this mailer */	ADDRESS *tochain = NULL;	/* chain of users in this mailer call */	int rcode;			/* response code */	char *firstsig;			/* signature of firstto */	int pid;	char *curhost;	int mpvect[2];	int rpvect[2];	char *pv[MAXPV+1];	char tobuf[TOBUFSIZE];		/* text line of to people */	char buf[MAXNAME];	char rpathbuf[MAXNAME];		/* translated return path */	extern int checkcompat();	errno = 0;	if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags))		return (0);#if NAMED_BIND	/* unless interactive, try twice, over a minute */	if (OpMode == MD_DAEMON || OpMode == MD_SMTP)	{		_res.retrans = 30;		_res.retry = 2;	}#endif 	m = to->q_mailer;	host = to->q_host;	CurEnv = e;			/* just in case */	e->e_statmsg = NULL;	SmtpError[0] = '\0';	if (tTd(10, 1))		printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",			e->e_id, m->m_name, host, to->q_user);	if (tTd(10, 100))		printopenfds(FALSE);	/*	**  If this mailer is expensive, and if we don't want to make	**  connections now, just mark these addresses and return.	**	This is useful if we want to batch connections to	**	reduce load.  This will cause the messages to be	**	queued up, and a daemon will come along to send the	**	messages later.	**		This should be on a per-mailer basis.	*/	if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose)	{		for (; to != NULL; to = to->q_next)		{			if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) ||			    to->q_mailer != m)				continue;			to->q_flags |= QQUEUEUP;			e->e_to = to->q_paddr;			message("queued");			if (LogLevel > 8)				logdelivery(m, NULL, "queued", NULL, e);		}		e->e_to = NULL;		return (0);	}	/*	**  Do initial argv setup.	**	Insert the mailer name.  Notice that $x expansion is	**	NOT done on the mailer name.  Then, if the mailer has	**	a picky -f flag, we insert it as appropriate.  This	**	code does not check for 'pv' overflow; this places a	**	manifest lower limit of 4 for MAXPV.	**		The from address rewrite is expected to make	**		the address relative to the other end.	*/	/* rewrite from address, using rewriting rules */	rcode = EX_OK;	(void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m,					   RF_SENDERADDR|RF_CANONICAL,					   &rcode, e));	define('g', rpathbuf, e);		/* translated return path */	define('h', host, e);			/* to host */	Errors = 0;	pvp = pv;	*pvp++ = m->m_argv[0];	/* insert -f or -r flag as appropriate */	if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags)))	{		if (bitnset(M_FOPT, m->m_flags))			*pvp++ = "-f";		else			*pvp++ = "-r";		*pvp++ = newstr(rpathbuf);	}	/*	**  Append the other fixed parts of the argv.  These run	**  up to the first entry containing "$u".  There can only	**  be one of these, and there are only a few more slots	**  in the pv after it.	*/	for (mvp = m->m_argv; (p = *++mvp) != NULL; )	{		/* can't use strchr here because of sign extension problems */		while (*p != '\0')		{			if ((*p++ & 0377) == MACROEXPAND)			{				if (*p == 'u')					break;			}		}		if (*p != '\0')			break;		/* this entry is safe -- go ahead and process it */		expand(*mvp, buf, &buf[sizeof buf - 1], e);		*pvp++ = newstr(buf);		if (pvp >= &pv[MAXPV - 3])		{			syserr("554 Too many parameters to %s before $u", pv[0]);			return (-1);		}	}	/*	**  If we have no substitution for the user name in the argument	**  list, we know that we must supply the names otherwise -- and	**  SMTP is the answer!!	*/	if (*mvp == NULL)	{		/* running SMTP */# ifdef SMTP		clever = TRUE;		*pvp = NULL;# else /* SMTP */		/* oops!  we don't implement SMTP */		syserr("554 SMTP style mailer not implemented");		return (EX_SOFTWARE);# endif /* SMTP */	}	/*	**  At this point *mvp points to the argument with $u.  We	**  run through our address list and append all the addresses	**  we can.  If we run out of space, do not fret!  We can	**  always send another copy later.	*/	tobuf[0] = '\0';	e->e_to = tobuf;	ctladdr = NULL;	firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e);	for (; to != NULL; to = to->q_next)	{		/* avoid sending multiple recipients to dumb mailers */		if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))			break;		/* if already sent or not for this host, don't send */		if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) ||		    to->q_mailer != firstto->q_mailer ||		    strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0)			continue;		/* avoid overflowing tobuf */		if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))			break;		if (tTd(10, 1))		{			printf("\nsend to ");			printaddr(to, FALSE);		}		/* compute effective uid/gid when sending */		/* XXX perhaps this should be to->q_mailer != LocalMailer ?? */		/* XXX perhaps it should be a mailer flag? */		if (to->q_mailer == ProgMailer || to->q_mailer == FileMailer)			ctladdr = getctladdr(to);		user = to->q_user;		e->e_to = to->q_paddr;		if (tTd(10, 5))		{			printf("deliver: QDONTSEND ");			printaddr(to, FALSE);		}		to->q_flags |= QDONTSEND;		/*		**  Check to see that these people are allowed to		**  talk to each other.		*/		if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)		{			NoReturn = TRUE;			usrerr("552 Message is too large; %ld bytes max", m->m_maxsize);			giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, e);			continue;		}		rcode = checkcompat(to, e);		if (rcode != EX_OK)		{			markfailure(e, to, rcode);			giveresponse(rcode, m, NULL, ctladdr, e);			continue;		}		/*		**  Strip quote bits from names if the mailer is dumb		**	about them.		*/		if (bitnset(M_STRIPQ, m->m_flags))		{			stripquotes(user);			stripquotes(host);		}		/* hack attack -- delivermail compatibility */		if (m == ProgMailer && *user == '|')			user++;		/*		**  If an error message has already been given, don't		**	bother to send to this address.		**		**	>>>>>>>>>> This clause assumes that the local mailer		**	>> NOTE >> cannot do any further aliasing; that		**	>>>>>>>>>> function is subsumed by sendmail.		*/		if (bitset(QBADADDR|QQUEUEUP, to->q_flags))			continue;		/* save statistics.... */		markstats(e, to);		/*		**  See if this user name is "special".		**	If the user name has a slash in it, assume that this		**	is a file -- send it off without further ado.  Note		**	that this type of addresses is not processed along		**	with the others, so we fudge on the To person.		*/		if (m == FileMailer)		{			rcode = mailfile(user, ctladdr, e);			giveresponse(rcode, m, NULL, ctladdr, e);			if (rcode == EX_OK)				to->q_flags |= QSENT;			continue;		}		/*		**  Address is verified -- add this user to mailer		**  argv, and add it to the print list of recipients.		*/		/* link together the chain of recipients */		to->q_tchain = tochain;		tochain = to;		/* create list of users for error messages */		(void) strcat(tobuf, ",");		(void) strcat(tobuf, to->q_paddr);		define('u', user, e);		/* to user */		p = to->q_home;		if (p == NULL && ctladdr != NULL)			p = ctladdr->q_home;		define('z', p, e);	/* user's home */		/*		**  Expand out this user into argument list.		*/		if (!clever)		{			expand(*mvp, buf, &buf[sizeof buf - 1], e);			*pvp++ = newstr(buf);			if (pvp >= &pv[MAXPV - 2])			{				/* allow some space for trailing parms */				break;			}		}	}	/* see if any addresses still exist */	if (tobuf[0] == '\0')	{		define('g', (char *) NULL, e);		return (0);	}	/* print out messages as full list */	e->e_to = tobuf + 1;	/*	**  Fill out any parameters after the $u parameter.	*/	while (!clever && *++mvp != NULL)	{		expand(*mvp, buf, &buf[sizeof buf - 1], e);		*pvp++ = newstr(buf);		if (pvp >= &pv[MAXPV])			syserr("554 deliver: pv overflow after $u for %s", pv[0]);	}	*pvp++ = NULL;	/*	**  Call the mailer.	**	The argument vector gets built, pipes	**	are created as necessary, and we fork & exec as	**	appropriate.	**	If we are running SMTP, we just need to clean up.	*/	/*XXX this seems a bit wierd */	if (ctladdr == NULL && m != ProgMailer &&	    bitset(QGOODUID, e->e_from.q_flags))		ctladdr = &e->e_from;#if NAMED_BIND	if (ConfigLevel < 2)		_res.options &= ~(RES_DEFNAMES | RES_DNSRCH);	/* XXX */#endif	if (tTd(11, 1))	{		printf("openmailer:");		printav(pv);	}	errno = 0;	CurHostName = m->m_mailer;	/*	**  Deal with the special case of mail handled through an IPC	**  connection.	**	In this case we don't actually fork.  We must be	**	running SMTP for this to work.  We will return a	**	zero pid to indicate that we are running IPC.	**  We also handle a debug version that just talks to stdin/out.	*/	curhost = NULL;	SmtpPhase = NULL;	mci = NULL;#ifdef XDEBUG	{		char wbuf[MAXLINE];		/* make absolutely certain 0, 1, and 2 are in use */		sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name);		checkfd012(wbuf);	}#endif	/* check for Local Person Communication -- not for mortals!!! */	if (strcmp(m->m_mailer, "[LPC]") == 0)	{		mci = (MCI *) xalloc(sizeof *mci);		bzero((char *) mci, sizeof *mci);		mci->mci_in = stdin;		mci->mci_out = stdout;		mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;		mci->mci_mailer = m;	}	else if (strcmp(m->m_mailer, "[IPC]") == 0 ||		 strcmp(m->m_mailer, "[TCP]") == 0)	{#ifdef DAEMON		register int i;		register u_short port;		if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')		{			syserr("null host name for %s mailer", m->m_mailer);			rcode = EX_CONFIG;			goto give_up;		}		CurHostName = pv[1];		curhost = hostsignature(m, pv[1], e);		if (curhost == NULL || curhost[0] == '\0')		{			syserr("null host signature for %s", pv[1]);			rcode = EX_OSERR;			goto give_up;		}		if (!clever)		{			syserr("554 non-clever IPC");			rcode = EX_CONFIG;			goto give_up;		}		if (pv[2] != NULL)			port = atoi(pv[2]);		else			port = 0;tryhost:		while (*curhost != '\0')		{			register char *p;			static char hostbuf[MAXNAME];			/* pull the next host from the signature */			p = strchr(curhost, ':');			if (p == NULL)				p = &curhost[strlen(curhost)];			if (p == curhost)			{				syserr("deliver: null host name in signature");				curhost++;				continue;			}			strncpy(hostbuf, curhost, p - curhost);			hostbuf[p - curhost] = '\0';			if (*p != '\0')				p++;			curhost = p;			/* see if we already know that this host is fried */			CurHostName = hostbuf;			mci = mci_get(hostbuf, m);			if (mci->mci_state != MCIS_CLOSED)			{				if (tTd(11, 1))				{					printf("openmailer: ");					mci_dump(mci, FALSE);				}				CurHostName = mci->mci_host;				break;			}			mci->mci_mailer = m;			if (mci->mci_exitstat != EX_OK)				continue;			/* try the connection */			setproctitle("%s %s: %s", e->e_id, hostbuf, "user open");			message("Connecting to %s (%s)...",				hostbuf, m->m_name);			i = makeconnection(hostbuf, port, mci,				bitnset(M_SECURE_PORT, m->m_flags));			mci->mci_exitstat = i;			mci->mci_errno = errno;#if NAMED_BIND			mci->mci_herrno = h_errno;#endif			if (i == EX_OK)			{				mci->mci_state = MCIS_OPENING;				mci_cache(mci);				if (TrafficLogFile != NULL)					fprintf(TrafficLogFile, "%05d == CONNECT %s\n",						getpid(), hostbuf);				break;			}			else if (tTd(11, 1))				printf("openmailer: makeconnection => stat=%d, errno=%d\n",					i, errno);			/* enter status of this host */			setstat(i);			/* should print some message here for -v mode */		}		if (mci == NULL)		{			syserr("deliver: no host name");			rcode = EX_OSERR;			goto give_up;		}		mci->mci_pid = 0;#else /* no DAEMON */		syserr("554 openmailer: no IPC");		if (tTd(11, 1))			printf("openmailer: NULL\n");		rcode = EX_UNAVAILABLE;		goto give_up;#endif /* DAEMON */	}	else	{		if (TrafficLogFile != NULL)		{			char **av;			fprintf(TrafficLogFile, "%05d === EXEC", getpid());			for (av = pv; *av != NULL; av++)				fprintf(TrafficLogFile, " %s", *av);			fprintf(TrafficLogFile, "\n");		}		/* create a pipe to shove the mail through */		if (pipe(mpvect) < 0)		{			syserr("%s... openmailer(%s): pipe (to mailer)",				e->e_to, m->m_name);			if (tTd(11, 1))				printf("openmailer: NULL\n");			rcode = EX_OSERR;			goto give_up;		}		/* if this mailer speaks smtp, create a return pipe */		if (clever && pipe(rpvect) < 0)		{			syserr("%s... openmailer(%s): pipe (from mailer)",				e->e_to, m->m_name);			(void) close(mpvect[0]);			(void) close(mpvect[1]);			if (tTd(11, 1))				printf("openmailer: NULL\n");			rcode = EX_OSERR;			goto give_up;		}		/*		**  Actually fork the mailer process.		**	DOFORK is clever about retrying.		**		**	Dispose of SIGCHLD signal catchers that may be laying		**	around so that endmail will get it.		*/		if (e->e_xfp != NULL)			(void) fflush(e->e_xfp);		/* for debugging */		(void) fflush(stdout);# ifdef SIGCHLD		(void) setsignal(SIGCHLD, SIG_DFL);# endif /* SIGCHLD */		DOFORK(FORK);		/* pid is set by DOFORK */		if (pid < 0)		{			/* failure */			syserr("%s... openmailer(%s): cannot fork",				e->e_to, m->m_name);			(void) close(mpvect[0]);			(void) close(mpvect[1]);			if (clever)			{				(void) close(rpvect[0]);				(void) close(rpvect[1]);			}			if (tTd(11, 1))				printf("openmailer: NULL\n");			rcode = EX_OSERR;			goto give_up;		}		else if (pid == 0)		{			int i;			int saveerrno;			char **ep;			char *env[MAXUSERENVIRON];			extern char **environ;			extern int DtableSize;			/* child -- set up input & exec mailer */			(void) setsignal(SIGINT, SIG_IGN);			(void) setsignal(SIGHUP, SIG_IGN);			(void) setsignal(SIGTERM, SIG_DFL);			/* reset user and group */			if (!bitnset(M_RESTR, m->m_flags))			{				if (ctladdr == NULL || ctladdr->q_uid == 0)				{					(void) initgroups(DefUser, DefGid);					(void) setgid(DefGid);					(void) setuid(DefUid);				}				else				{					(void) initgroups(ctladdr->q_ruser?						ctladdr->q_ruser: ctladdr->q_user,						ctladdr->q_gid);					(void) setgid(ctladdr->q_gid);					(void) setuid(ctladdr->q_uid);				}			}

⌨️ 快捷键说明

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