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

📄 util.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)util.c	8.39 (Berkeley) 4/14/94";#endif /* not lint */# include "sendmail.h"# include <sysexits.h>/***  STRIPQUOTES -- Strip quotes & quote bits from a string.****	Runs through a string and strips off unquoted quote**	characters and quote bits.  This is done in place.****	Parameters:**		s -- the string to strip.****	Returns:**		none.****	Side Effects:**		none.****	Called By:**		deliver*/stripquotes(s)	char *s;{	register char *p;	register char *q;	register char c;	if (s == NULL)		return;	p = q = s;	do	{		c = *p++;		if (c == '\\')			c = *p++;		else if (c == '"')			continue;		*q++ = c;	} while (c != '\0');}/***  XALLOC -- Allocate memory and bitch wildly on failure.****	THIS IS A CLUDGE.  This should be made to give a proper**	error -- but after all, what can we do?****	Parameters:**		sz -- size of area to allocate.****	Returns:**		pointer to data region.****	Side Effects:**		Memory is allocated.*/char *xalloc(sz)	register int sz;{	register char *p;	/* some systems can't handle size zero mallocs */	if (sz <= 0)		sz = 1;	p = malloc((unsigned) sz);	if (p == NULL)	{		syserr("Out of memory!!");		abort();		/* exit(EX_UNAVAILABLE); */	}	return (p);}/***  COPYPLIST -- copy list of pointers.****	This routine is the equivalent of newstr for lists of**	pointers.****	Parameters:**		list -- list of pointers to copy.**			Must be NULL terminated.**		copycont -- if TRUE, copy the contents of the vector**			(which must be a string) also.****	Returns:**		a copy of 'list'.****	Side Effects:**		none.*/char **copyplist(list, copycont)	char **list;	bool copycont;{	register char **vp;	register char **newvp;	for (vp = list; *vp != NULL; vp++)		continue;	vp++;	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);	if (copycont)	{		for (vp = newvp; *vp != NULL; vp++)			*vp = newstr(*vp);	}	return (newvp);}/***  COPYQUEUE -- copy address queue.****	This routine is the equivalent of newstr for address queues**	addresses marked with QDONTSEND aren't copied****	Parameters:**		addr -- list of address structures to copy.****	Returns:**		a copy of 'addr'.****	Side Effects:**		none.*/ADDRESS *copyqueue(addr)	ADDRESS *addr;{	register ADDRESS *newaddr;	ADDRESS *ret;	register ADDRESS **tail = &ret;	while (addr != NULL)	{		if (!bitset(QDONTSEND, addr->q_flags))		{			newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));			STRUCTCOPY(*addr, *newaddr);			*tail = newaddr;			tail = &newaddr->q_next;		}		addr = addr->q_next;	}	*tail = NULL;		return ret;}/***  PRINTAV -- print argument vector.****	Parameters:**		av -- argument vector.****	Returns:**		none.****	Side Effects:**		prints av.*/printav(av)	register char **av;{	while (*av != NULL)	{		if (tTd(0, 44))			printf("\n\t%08x=", *av);		else			(void) putchar(' ');		xputs(*av++);	}	(void) putchar('\n');}/***  LOWER -- turn letter into lower case.****	Parameters:**		c -- character to turn into lower case.****	Returns:**		c, in lower case.****	Side Effects:**		none.*/charlower(c)	register char c;{	return((isascii(c) && isupper(c)) ? tolower(c) : c);}/***  XPUTS -- put string doing control escapes.****	Parameters:**		s -- string to put.****	Returns:**		none.****	Side Effects:**		output to stdout*/xputs(s)	register char *s;{	register int c;	register struct metamac *mp;	extern struct metamac MetaMacros[];	if (s == NULL)	{		printf("<null>");		return;	}	while ((c = (*s++ & 0377)) != '\0')	{		if (!isascii(c))		{			if (c == MATCHREPL || c == MACROEXPAND)			{				putchar('$');				continue;			}			for (mp = MetaMacros; mp->metaname != '\0'; mp++)			{				if ((mp->metaval & 0377) == c)				{					printf("$%c", mp->metaname);					break;				}			}			if (mp->metaname != '\0')				continue;			(void) putchar('\\');			c &= 0177;		}		if (isprint(c))		{			putchar(c);			continue;		}		/* wasn't a meta-macro -- find another way to print it */		switch (c)		{		  case '\0':			continue;		  case '\n':			c = 'n';			break;		  case '\r':			c = 'r';			break;		  case '\t':			c = 't';			break;		  default:			(void) putchar('^');			(void) putchar(c ^ 0100);			continue;		}	}	(void) fflush(stdout);}/***  MAKELOWER -- Translate a line into lower case****	Parameters:**		p -- the string to translate.  If NULL, return is**			immediate.****	Returns:**		none.****	Side Effects:**		String pointed to by p is translated to lower case.****	Called By:**		parse*/makelower(p)	register char *p;{	register char c;	if (p == NULL)		return;	for (; (c = *p) != '\0'; p++)		if (isascii(c) && isupper(c))			*p = tolower(c);}/***  BUILDFNAME -- build full name from gecos style entry.****	This routine interprets the strange entry that would appear**	in the GECOS field of the password file.****	Parameters:**		p -- name to build.**		login -- the login name of this user (for &).**		buf -- place to put the result.****	Returns:**		none.****	Side Effects:**		none.*/buildfname(gecos, login, buf)	register char *gecos;	char *login;	char *buf;{	register char *p;	register char *bp = buf;	int l;	if (*gecos == '*')		gecos++;	/* find length of final string */	l = 0;	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)	{		if (*p == '&')			l += strlen(login);		else			l++;	}	/* now fill in buf */	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)	{		if (*p == '&')		{			(void) strcpy(bp, login);			*bp = toupper(*bp);			while (*bp != '\0')				bp++;		}		else			*bp++ = *p;	}	*bp = '\0';}/***  SAFEFILE -- return true if a file exists and is safe for a user.****	Parameters:**		fn -- filename to check.**		uid -- user id to compare against.**		gid -- group id to compare against.**		uname -- user name to compare against (used for group**			sets).**		flags -- modifiers:**			SFF_MUSTOWN -- "uid" must own this file.**			SFF_NOSLINK -- file cannot be a symbolic link.**		mode -- mode bits that must match.****	Returns:**		0 if fn exists, is owned by uid, and matches mode.**		An errno otherwise.  The actual errno is cleared.****	Side Effects:**		none.*/#include <grp.h>#ifndef S_IXOTH# define S_IXOTH	(S_IEXEC >> 6)#endif#ifndef S_IXGRP# define S_IXGRP	(S_IEXEC >> 3)#endif#ifndef S_IXUSR# define S_IXUSR	(S_IEXEC)#endifintsafefile(fn, uid, gid, uname, flags, mode)	char *fn;	uid_t uid;	gid_t gid;	char *uname;	int flags;	int mode;{	register char *p;	register struct group *gr = NULL;	struct stat stbuf;	if (tTd(54, 4))		printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n",			fn, uid, gid, flags, mode);	errno = 0;	for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/')	{		*p = '\0';		if (stat(fn, &stbuf) < 0)			break;		if (uid == 0 && !bitset(SFF_ROOTOK, flags))		{			if (bitset(S_IXOTH, stbuf.st_mode))				continue;			break;		}		if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode))			continue;		if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode))			continue;#ifndef NO_GROUP_SET		if (uname != NULL &&		    ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||		     (gr = getgrgid(stbuf.st_gid)) != NULL))		{			register char **gp;			for (gp = gr->gr_mem; *gp != NULL; gp++)				if (strcmp(*gp, uname) == 0)					break;			if (*gp != NULL && bitset(S_IXGRP, stbuf.st_mode))				continue;		}#endif		if (!bitset(S_IXOTH, stbuf.st_mode))			break;	}	if (p != NULL)	{		int ret = errno;		if (ret == 0)			ret = EACCES;		if (tTd(54, 4))			printf("\t[dir %s] %s\n", fn, errstring(ret));		*p = '/';		return ret;	}#ifdef HASLSTAT	if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, &stbuf)					: stat(fn, &stbuf)) < 0)#else	if (stat(fn, &stbuf) < 0)#endif	{		int ret = errno;		if (tTd(54, 4))			printf("\t%s\n", errstring(ret));		errno = 0;		return ret;	}#ifdef S_ISLNK	if (bitset(SFF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode))	{		if (tTd(54, 4))			printf("\t[slink mode %o]\tEPERM\n", stbuf.st_mode);		return EPERM;	}#endif	if (uid == 0 && !bitset(SFF_ROOTOK, flags))		mode >>= 6;	else if (stbuf.st_uid != uid)	{		mode >>= 3;		if (stbuf.st_gid == gid)			;#ifndef NO_GROUP_SET		else if (uname != NULL &&			 ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||			  (gr = getgrgid(stbuf.st_gid)) != NULL))		{			register char **gp;			for (gp = gr->gr_mem; *gp != NULL; gp++)				if (strcmp(*gp, uname) == 0)					break;			if (*gp == NULL)				mode >>= 3;		}#endif		else			mode >>= 3;	}	if (tTd(54, 4))		printf("\t[uid %d, stat %o, mode %o] ",			stbuf.st_uid, stbuf.st_mode, mode);	if ((stbuf.st_uid == uid || stbuf.st_uid == 0 ||	     !bitset(SFF_MUSTOWN, flags)) &&	    (stbuf.st_mode & mode) == mode)	{		if (tTd(54, 4))			printf("\tOK\n");		return 0;	}	if (tTd(54, 4))		printf("\tEACCES\n");	return EACCES;}/***  FIXCRLF -- fix <CR><LF> in line.****	Looks for the <CR><LF> combination and turns it into the**	UNIX canonical <NL> character.  It only takes one line,**	i.e., it is assumed that the first <NL> found is the end**	of the line.****	Parameters:**		line -- the line to fix.**		stripnl -- if true, strip the newline also.****	Returns:**		none.****	Side Effects:**		line is changed in place.*/fixcrlf(line, stripnl)	char *line;	bool stripnl;{	register char *p;	p = strchr(line, '\n');	if (p == NULL)		return;	if (p > line && p[-1] == '\r')		p--;	if (!stripnl)		*p++ = '\n';	*p = '\0';}/***  DFOPEN -- determined file open****	This routine has the semantics of fopen, except that it will**	keep trying a few times to make this happen.  The idea is that**	on very loaded systems, we may run out of resources (inodes,**	whatever), so this tries to get around it.*/#ifndef O_ACCMODE# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)#endifstruct omodes{	int	mask;	int	mode;	char	*farg;} OpenModes[] ={	O_ACCMODE,		O_RDONLY,		"r",	O_ACCMODE|O_APPEND,	O_WRONLY,		"w",	O_ACCMODE|O_APPEND,	O_WRONLY|O_APPEND,	"a",	O_TRUNC,		0,			"w+",	O_APPEND,		O_APPEND,		"a+",	0,			0,			"r+",};FILE *dfopen(filename, omode, cmode)	char *filename;	int omode;	int cmode;{	register int tries;	int fd;	register struct omodes *om;	struct stat st;	for (om = OpenModes; om->mask != 0; om++)		if ((omode & om->mask) == om->mode)			break;	for (tries = 0; tries < 10; tries++)	{		sleep((unsigned) (10 * tries));		errno = 0;		fd = open(filename, omode, cmode);		if (fd >= 0)			break;		switch (errno)		{		  case ENFILE:		/* system file table full */		  case EINTR:		/* interrupted syscall */#ifdef ETXTBSY		  case ETXTBSY:		/* Apollo: net file locked */#endif			continue;		}		break;	}	if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode))	{		int locktype;		/* lock the file to avoid accidental conflicts */		if ((omode & O_ACCMODE) != O_RDONLY)			locktype = LOCK_EX;		else			locktype = LOCK_SH;		(void) lockfile(fd, filename, NULL, locktype);		errno = 0;	}	if (fd < 0)		return NULL;	else		return fdopen(fd, om->farg);}/***  PUTLINE -- put a line like fputs obeying SMTP conventions****	This routine always guarantees outputing a newline (or CRLF,**	as appropriate) at the end of the string.****	Parameters:**		l -- line to put.**		mci -- the mailer connection information.****	Returns:**		none****	Side Effects:**		output of l to fp.*/putline(l, mci)	register char *l;	register MCI *mci;{	register char *p;	register char svchar;	int slop = 0;	/* strip out 0200 bits -- these can look like TELNET protocol */	if (bitset(MCIF_7BIT, mci->mci_flags))	{		for (p = l; (svchar = *p) != '\0'; ++p)			if (bitset(0200, svchar))				*p = svchar &~ 0200;	}	do	{		/* find the end of the line */		p = strchr(l, '\n');		if (p == NULL)			p = &l[strlen(l)];		if (TrafficLogFile != NULL)			fprintf(TrafficLogFile, "%05d >>> ", getpid());		/* check for line overflow */		while (mci->mci_mailer->m_linelimit > 0 &&		       (p - l + slop) > mci->mci_mailer->m_linelimit)		{			register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];			svchar = *q;			*q = '\0';			if (l[0] == '.' && slop == 0 &&			    bitnset(M_XDOT, mci->mci_mailer->m_flags))			{				(void) putc('.', mci->mci_out);				if (TrafficLogFile != NULL)

⌨️ 快捷键说明

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