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

📄 safefile.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 2 页
字号:
			break;
		}

# ifdef S_ISLNK
		/* Follow symlinks */
		if (S_ISLNK(stbuf.st_mode))
		{
			char *target;
			char buf[MAXPATHLEN + 1];

			memset(buf, '\0', sizeof buf);
			if (readlink(s, buf, sizeof buf) < 0)
			{
				ret = errno;
				break;
			}

			offset = 0;
			if (*buf == '/')
			{
				target = buf;

				/* If path is the same, avoid rechecks */
				while (s[offset] == buf[offset] &&
				       s[offset] != '\0')
					offset++;

				if (s[offset] == '\0' && buf[offset] == '\0')
				{
					/* strings match, symlink loop */
					return ELOOP;
				}

				/* back off from the mismatch */
				if (offset > 0)
					offset--;

				/* Make sure we are at a directory break */
				if (offset > 0 &&
				    s[offset] != '/' &&
				    s[offset] != '\0')
				{
					while (buf[offset] != '/' &&
					       offset > 0)
						offset--;
				}
				if (offset > 0 &&
				    s[offset] == '/' &&
				    buf[offset] == '/')
				{
					/* Include the trailing slash */
					offset++;
				}
			}
			else
			{
				char *sptr;
				char fullbuf[MAXLINKPATHLEN + 1];

				sptr = strrchr(s, '/');
				if (sptr != NULL)
				{
					*sptr = '\0';
					offset = sptr + 1 - s;
					if ((strlen(s) + 1 +
					     strlen(buf) + 1) > sizeof fullbuf)
					{
						ret = EINVAL;
						break;
					}
					snprintf(fullbuf, sizeof fullbuf,
						 "%s/%s", s, buf);
					*sptr = '/';
				}
				else
				{
					if (strlen(buf) + 1 > sizeof fullbuf)
					{
						ret = EINVAL;
						break;
					}
					(void) strlcpy(fullbuf, buf,
						       sizeof fullbuf);
				}
				target = fullbuf;
			}
			ret = safedirpath(target, uid, gid, user, flags,
					  level + 1, offset);
			if (ret != 0)
				break;

			/* Don't check permissions on the link file itself */
			continue;
		}
#endif /* S_ISLNK */

		if ((uid == 0 || bitset(SFF_SAFEDIRPATH, flags)) &&
#ifdef S_ISVTX
		    !(bitnset(DBS_TRUSTSTICKYBIT, DontBlameSendmail) &&
		      bitset(S_ISVTX, stbuf.st_mode)) &&
#endif /* S_ISVTX */
		    bitset(mode, stbuf.st_mode))
		{
			if (tTd(44, 4))
				dprintf("\t[dir %s] mode %lo ",
					s, (u_long) stbuf.st_mode);
			if (bitset(SFF_SAFEDIRPATH, flags))
			{
				if (bitset(S_IWOTH, stbuf.st_mode))
					ret = E_SM_WWDIR;
				else
					ret = E_SM_GWDIR;
				if (tTd(44, 4))
					dprintf("FATAL\n");
				break;
			}
			if (tTd(44, 4))
				dprintf("WARNING\n");
			if (Verbose > 1)
				message("051 WARNING: %s writable directory %s",
					bitset(S_IWOTH, stbuf.st_mode)
					   ? "World"
					   : "Group",
					s);
		}
		if (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags))
		{
			if (bitset(S_IXOTH, stbuf.st_mode))
				continue;
			ret = EACCES;
			break;
		}

		/*
		**  Let OS determine access to file if we are not
		**  running as a privileged user.  This allows ACLs
		**  to work.  Also, if opening as root, assume we can
		**  scan the directory.
		*/
		if (geteuid() != 0 || bitset(SFF_OPENASROOT, flags))
			continue;

		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 (user != NULL && !DontInitGroups &&
		    ((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 != NULL; gp++)
				if (strcmp(*gp, user) == 0)
					break;
			if (gp != NULL && *gp != NULL &&
			    bitset(S_IXGRP, stbuf.st_mode))
				continue;
		}
# endif /* ! NO_GROUP_SET */
		if (!bitset(S_IXOTH, stbuf.st_mode))
		{
			ret = EACCES;
			break;
		}
	}
	if (tTd(44, 4))
		dprintf("\t[dir %s] %s\n", fn,
			ret == 0 ? "OK" : errstring(ret));
	return ret;
}
/*
**  SAFEOPEN -- do a file open with extra checking
**
**	Parameters:
**		fn -- the file name to open.
**		omode -- the open-style mode flags.
**		cmode -- the create-style mode flags.
**		sff -- safefile flags.
**
**	Returns:
**		Same as open.
*/

#ifndef O_ACCMODE
# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
#endif /* ! O_ACCMODE */

int
safeopen(fn, omode, cmode, sff)
	char *fn;
	int omode;
	int cmode;
	long sff;
{
	int rval;
	int fd;
	int smode;
	struct stat stb;

	if (tTd(44, 10))
		printf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n",
		       fn, omode, cmode, sff);

	if (bitset(O_CREAT, omode))
		sff |= SFF_CREAT;
	omode &= ~O_CREAT;
	smode = 0;
	switch (omode & O_ACCMODE)
	{
	  case O_RDONLY:
		smode = S_IREAD;
		break;

	  case O_WRONLY:
		smode = S_IWRITE;
		break;

	  case O_RDWR:
		smode = S_IREAD|S_IWRITE;
		break;

	  default:
		smode = 0;
		break;
	}
	if (bitset(SFF_OPENASROOT, sff))
		rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName,
				sff, smode, &stb);
	else
		rval = safefile(fn, RealUid, RealGid, RealUserName,
				sff, smode, &stb);
	if (rval != 0)
	{
		errno = rval;
		return -1;
	}
	if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff))
		omode |= O_CREAT | (bitset(SFF_NOTEXCL, sff) ? 0 : O_EXCL);
	else if (bitset(SFF_CREAT, sff) && bitset(O_EXCL, omode))
	{
		/* The file exists so an exclusive create would fail */
		errno = EEXIST;
		return -1;
	}

	fd = dfopen(fn, omode, cmode, sff);
	if (fd < 0)
		return fd;
	if (filechanged(fn, fd, &stb))
	{
		syserr("554 5.3.0 cannot open: file %s changed after open", fn);
		(void) close(fd);
		errno = E_SM_FILECHANGE;
		return -1;
	}
	return fd;
}
/*
**  SAFEFOPEN -- do a file open with extra checking
**
**	Parameters:
**		fn -- the file name to open.
**		omode -- the open-style mode flags.
**		cmode -- the create-style mode flags.
**		sff -- safefile flags.
**
**	Returns:
**		Same as fopen.
*/

FILE *
safefopen(fn, omode, cmode, sff)
	char *fn;
	int omode;
	int cmode;
	long sff;
{
	int fd;
	int save_errno;
	FILE *fp;
	char *fmode;

	switch (omode & O_ACCMODE)
	{
	  case O_RDONLY:
		fmode = "r";
		break;

	  case O_WRONLY:
		if (bitset(O_APPEND, omode))
			fmode = "a";
		else
			fmode = "w";
		break;

	  case O_RDWR:
		if (bitset(O_TRUNC, omode))
			fmode = "w+";
		else if (bitset(O_APPEND, omode))
			fmode = "a+";
		else
			fmode = "r+";
		break;

	  default:
		syserr("554 5.3.5 safefopen: unknown omode %o", omode);
		fmode = "x";
	}
	fd = safeopen(fn, omode, cmode, sff);
	if (fd < 0)
	{
		save_errno = errno;
		if (tTd(44, 10))
			dprintf("safefopen: safeopen failed: %s\n",
				errstring(errno));
		errno = save_errno;
		return NULL;
	}
	fp = fdopen(fd, fmode);
	if (fp != NULL)
		return fp;

	save_errno = errno;
	if (tTd(44, 10))
	{
		dprintf("safefopen: fdopen(%s, %s) failed: omode=%x, sff=%lx, err=%s\n",
			fn, fmode, omode, sff, errstring(errno));
	}
	(void) close(fd);
	errno = save_errno;
	return NULL;
}
/*
**  FILECHANGED -- check to see if file changed after being opened
**
**	Parameters:
**		fn -- pathname of file to check.
**		fd -- file descriptor to check.
**		stb -- stat structure from before open.
**
**	Returns:
**		TRUE -- if a problem was detected.
**		FALSE -- if this file is still the same.
*/

bool
filechanged(fn, fd, stb)
	char *fn;
	int fd;
	struct stat *stb;
{
	struct stat sta;

	if (stb->st_mode == ST_MODE_NOFILE)
	{
# if HASLSTAT && BOGUS_O_EXCL
		/* only necessary if exclusive open follows symbolic links */
		if (lstat(fn, stb) < 0 || stb->st_nlink != 1)
			return TRUE;
# else /* HASLSTAT && BOGUS_O_EXCL */
		return FALSE;
# endif /* HASLSTAT && BOGUS_O_EXCL */
	}
	if (fstat(fd, &sta) < 0)
		return TRUE;

	if (sta.st_nlink != stb->st_nlink ||
	    sta.st_dev != stb->st_dev ||
	    sta.st_ino != stb->st_ino ||
# if HAS_ST_GEN && 0		/* AFS returns garbage in st_gen */
	    sta.st_gen != stb->st_gen ||
# endif /* HAS_ST_GEN && 0 */
	    sta.st_uid != stb->st_uid ||
	    sta.st_gid != stb->st_gid)
	{
		if (tTd(44, 8))
		{
			dprintf("File changed after opening:\n");
			dprintf(" nlink	= %ld/%ld\n",
				(long) stb->st_nlink, (long) sta.st_nlink);
			dprintf(" dev	= %ld/%ld\n",
				(long) stb->st_dev, (long) sta.st_dev);
			if (sizeof sta.st_ino > sizeof (long))
			{
				dprintf(" ino	= %s/",
					quad_to_string(stb->st_ino));
				dprintf("%s\n",
					quad_to_string(sta.st_ino));
			}
			else
				dprintf(" ino	= %lu/%lu\n",
					(unsigned long) stb->st_ino,
					(unsigned long) sta.st_ino);
# if HAS_ST_GEN
			dprintf(" gen	= %ld/%ld\n",
				(long) stb->st_gen, (long) sta.st_gen);
# endif /* HAS_ST_GEN */
			dprintf(" uid	= %ld/%ld\n",
				(long) stb->st_uid, (long) sta.st_uid);
			dprintf(" gid	= %ld/%ld\n",
				(long) stb->st_gid, (long) sta.st_gid);
		}
		return TRUE;
	}

	return FALSE;
}
/*
**  DFOPEN -- determined file open
**
**	This routine has the semantics of open, 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.
*/

int
dfopen(filename, omode, cmode, sff)
	char *filename;
	int omode;
	int cmode;
	long sff;
{
	register int tries;
	int fd = -1;
	struct stat st;

	for (tries = 0; tries < 10; tries++)
	{
		(void) 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 /* ETXTBSY */
			continue;
		}
		break;
	}
	if (!bitset(SFF_NOLOCK, sff) &&
	    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;
		if (!lockfile(fd, filename, NULL, locktype))
		{
			int save_errno = errno;

			(void) close(fd);
			fd = -1;
			errno = save_errno;
		}
		else
			errno = 0;
	}
	return fd;
}

⌨️ 快捷键说明

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