diff options
Diffstat (limited to 'contrib/sendmail/libsmutil/safefile.c')
-rw-r--r-- | contrib/sendmail/libsmutil/safefile.c | 955 |
1 files changed, 0 insertions, 955 deletions
diff --git a/contrib/sendmail/libsmutil/safefile.c b/contrib/sendmail/libsmutil/safefile.c deleted file mode 100644 index aed40a0482e0..000000000000 --- a/contrib/sendmail/libsmutil/safefile.c +++ /dev/null @@ -1,955 +0,0 @@ -/* - * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#include <sendmail.h> -#include <sm/io.h> -#include <sm/errstring.h> - -SM_RCSID("@(#)$Id: safefile.c,v 8.124 2002/05/24 20:50:15 gshapiro Exp $") - - -/* -** SAFEFILE -- return 0 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. -** user -- 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. -** st -- if set, points to a stat structure that will -** get the stat info for the file. -** -** Returns: -** 0 if fn exists, is owned by uid, and matches mode. -** An errno otherwise. The actual errno is cleared. -** -** Side Effects: -** none. -*/ - -int -safefile(fn, uid, gid, user, flags, mode, st) - char *fn; - UID_T uid; - GID_T gid; - char *user; - long flags; - int mode; - struct stat *st; -{ - register char *p; - register struct group *gr = NULL; - int file_errno = 0; - bool checkpath; - struct stat stbuf; - struct stat fstbuf; - char fbuf[MAXPATHLEN]; - - if (tTd(44, 4)) - sm_dprintf("safefile(%s, uid=%d, gid=%d, flags=%lx, mode=%o):\n", - fn, (int) uid, (int) gid, flags, mode); - errno = 0; - if (sm_strlcpy(fbuf, fn, sizeof fbuf) >= sizeof fbuf) - { - if (tTd(44, 4)) - sm_dprintf("\tpathname too long\n"); - return ENAMETOOLONG; - } - fn = fbuf; - if (st == NULL) - st = &fstbuf; - - /* ignore SFF_SAFEDIRPATH if we are debugging */ - if (RealUid != 0 && RunAsUid == RealUid) - flags &= ~SFF_SAFEDIRPATH; - - /* first check to see if the file exists at all */ -# if HASLSTAT - if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st) - : stat(fn, st)) < 0) -# else /* HASLSTAT */ - if (stat(fn, st) < 0) -# endif /* HASLSTAT */ - { - file_errno = errno; - } - else if (bitset(SFF_SETUIDOK, flags) && - !bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode) && - S_ISREG(st->st_mode)) - { - /* - ** If final file is set-user-ID, run as the owner of that - ** file. Gotta be careful not to reveal anything too - ** soon here! - */ - -# ifdef SUID_ROOT_FILES_OK - if (bitset(S_ISUID, st->st_mode)) -# else /* SUID_ROOT_FILES_OK */ - if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0 && - st->st_uid != TrustedUid) -# endif /* SUID_ROOT_FILES_OK */ - { - uid = st->st_uid; - user = NULL; - } -# ifdef SUID_ROOT_FILES_OK - if (bitset(S_ISGID, st->st_mode)) -# else /* SUID_ROOT_FILES_OK */ - if (bitset(S_ISGID, st->st_mode) && st->st_gid != 0) -# endif /* SUID_ROOT_FILES_OK */ - gid = st->st_gid; - } - - checkpath = !bitset(SFF_NOPATHCHECK, flags) || - (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags)); - if (bitset(SFF_NOWLINK, flags) && !bitset(SFF_SAFEDIRPATH, flags)) - { - int ret; - - /* check the directory */ - p = strrchr(fn, '/'); - if (p == NULL) - { - ret = safedirpath(".", uid, gid, user, - flags|SFF_SAFEDIRPATH, 0, 0); - } - else - { - *p = '\0'; - ret = safedirpath(fn, uid, gid, user, - flags|SFF_SAFEDIRPATH, 0, 0); - *p = '/'; - } - if (ret == 0) - { - /* directory is safe */ - checkpath = false; - } - else - { -# if HASLSTAT - /* Need lstat() information if called stat() before */ - if (!bitset(SFF_NOSLINK, flags) && lstat(fn, st) < 0) - { - ret = errno; - if (tTd(44, 4)) - sm_dprintf("\t%s\n", sm_errstring(ret)); - return ret; - } -# endif /* HASLSTAT */ - /* directory is writable: disallow links */ - flags |= SFF_NOLINK; - } - } - - if (checkpath) - { - int ret; - - p = strrchr(fn, '/'); - if (p == NULL) - { - ret = safedirpath(".", uid, gid, user, flags, 0, 0); - } - else - { - *p = '\0'; - ret = safedirpath(fn, uid, gid, user, flags, 0, 0); - *p = '/'; - } - if (ret != 0) - return ret; - } - - /* - ** If the target file doesn't exist, check the directory to - ** ensure that it is writable by this user. - */ - - if (file_errno != 0) - { - int ret = file_errno; - char *dir = fn; - - if (tTd(44, 4)) - sm_dprintf("\t%s\n", sm_errstring(ret)); - - errno = 0; - if (!bitset(SFF_CREAT, flags) || file_errno != ENOENT) - return ret; - - /* check to see if legal to create the file */ - p = strrchr(dir, '/'); - if (p == NULL) - dir = "."; - else if (p == dir) - dir = "/"; - else - *p = '\0'; - if (stat(dir, &stbuf) >= 0) - { - int md = S_IWRITE|S_IEXEC; - - ret = 0; - if (stbuf.st_uid == uid) - /* EMPTY */ - ; - else if (uid == 0 && stbuf.st_uid == TrustedUid) - /* EMPTY */ - ; - else - { - md >>= 3; - if (stbuf.st_gid == gid) - /* EMPTY */ - ; -# ifndef NO_GROUP_SET - else 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++) - if (strcmp(*gp, user) == 0) - break; - if (*gp == NULL) - md >>= 3; - } -# endif /* ! NO_GROUP_SET */ - else - md >>= 3; - } - if ((stbuf.st_mode & md) != md) - ret = errno = EACCES; - } - else - ret = errno; - if (tTd(44, 4)) - sm_dprintf("\t[final dir %s uid %d mode %lo] %s\n", - dir, (int) stbuf.st_uid, - (unsigned long) stbuf.st_mode, - sm_errstring(ret)); - if (p != NULL) - *p = '/'; - st->st_mode = ST_MODE_NOFILE; - return ret; - } - -# ifdef S_ISLNK - if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) - { - if (tTd(44, 4)) - sm_dprintf("\t[slink mode %lo]\tE_SM_NOSLINK\n", - (unsigned long) st->st_mode); - return E_SM_NOSLINK; - } -# endif /* S_ISLNK */ - if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode)) - { - if (tTd(44, 4)) - sm_dprintf("\t[non-reg mode %lo]\tE_SM_REGONLY\n", - (unsigned long) st->st_mode); - return E_SM_REGONLY; - } - if (bitset(SFF_NOGWFILES, flags) && - bitset(S_IWGRP, st->st_mode)) - { - if (tTd(44, 4)) - sm_dprintf("\t[write bits %lo]\tE_SM_GWFILE\n", - (unsigned long) st->st_mode); - return E_SM_GWFILE; - } - if (bitset(SFF_NOWWFILES, flags) && - bitset(S_IWOTH, st->st_mode)) - { - if (tTd(44, 4)) - sm_dprintf("\t[write bits %lo]\tE_SM_WWFILE\n", - (unsigned long) st->st_mode); - return E_SM_WWFILE; - } - if (bitset(SFF_NOGRFILES, flags) && bitset(S_IRGRP, st->st_mode)) - { - if (tTd(44, 4)) - sm_dprintf("\t[read bits %lo]\tE_SM_GRFILE\n", - (unsigned long) st->st_mode); - return E_SM_GRFILE; - } - if (bitset(SFF_NOWRFILES, flags) && bitset(S_IROTH, st->st_mode)) - { - if (tTd(44, 4)) - sm_dprintf("\t[read bits %lo]\tE_SM_WRFILE\n", - (unsigned long) st->st_mode); - return E_SM_WRFILE; - } - if (!bitset(SFF_EXECOK, flags) && - bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) && - bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode)) - { - if (tTd(44, 4)) - sm_dprintf("\t[exec bits %lo]\tE_SM_ISEXEC]\n", - (unsigned long) st->st_mode); - return E_SM_ISEXEC; - } - if (bitset(SFF_NOHLINK, flags) && st->st_nlink != 1) - { - if (tTd(44, 4)) - sm_dprintf("\t[link count %d]\tE_SM_NOHLINK\n", - (int) st->st_nlink); - return E_SM_NOHLINK; - } - - if (uid == 0 && bitset(SFF_OPENASROOT, flags)) - /* EMPTY */ - ; - else if (uid == 0 && !bitset(SFF_ROOTOK, flags)) - mode >>= 6; - else if (st->st_uid == uid) - /* EMPTY */ - ; - else if (uid == 0 && st->st_uid == TrustedUid) - /* EMPTY */ - ; - else - { - mode >>= 3; - if (st->st_gid == gid) - /* EMPTY */ - ; -# ifndef NO_GROUP_SET - else if (user != NULL && !DontInitGroups && - ((gr != NULL && gr->gr_gid == st->st_gid) || - (gr = getgrgid(st->st_gid)) != NULL)) - { - register char **gp; - - for (gp = gr->gr_mem; *gp != NULL; gp++) - if (strcmp(*gp, user) == 0) - break; - if (*gp == NULL) - mode >>= 3; - } -# endif /* ! NO_GROUP_SET */ - else - mode >>= 3; - } - if (tTd(44, 4)) - sm_dprintf("\t[uid %d, nlink %d, stat %lo, mode %lo] ", - (int) st->st_uid, (int) st->st_nlink, - (unsigned long) st->st_mode, (unsigned long) mode); - if ((st->st_uid == uid || st->st_uid == 0 || - st->st_uid == TrustedUid || - !bitset(SFF_MUSTOWN, flags)) && - (st->st_mode & mode) == mode) - { - if (tTd(44, 4)) - sm_dprintf("\tOK\n"); - return 0; - } - if (tTd(44, 4)) - sm_dprintf("\tEACCES\n"); - return EACCES; -} -/* -** SAFEDIRPATH -- check to make sure a path to a directory is safe -** -** Safe means not writable and owned by the right folks. -** -** Parameters: -** fn -- filename to check. -** uid -- user id to compare against. -** gid -- group id to compare against. -** user -- user name to compare against (used for group -** sets). -** flags -- modifiers: -** SFF_ROOTOK -- ok to use root permissions to open. -** SFF_SAFEDIRPATH -- writable directories are considered -** to be fatal errors. -** level -- symlink recursive level. -** offset -- offset into fn to start checking from. -** -** Returns: -** 0 -- if the directory path is "safe". -** else -- an error number associated with the path. -*/ - -int -safedirpath(fn, uid, gid, user, flags, level, offset) - char *fn; - UID_T uid; - GID_T gid; - char *user; - long flags; - int level; - int offset; -{ - int ret = 0; - int mode = S_IWOTH; - char save = '\0'; - char *saveptr = NULL; - char *p, *enddir; - register struct group *gr = NULL; - char s[MAXLINKPATHLEN]; - struct stat stbuf; - - /* make sure we aren't in a symlink loop */ - if (level > MAXSYMLINKS) - return ELOOP; - - if (level < 0 || offset < 0 || offset > strlen(fn)) - return EINVAL; - - /* special case root directory */ - if (*fn == '\0') - fn = "/"; - - if (tTd(44, 4)) - sm_dprintf("safedirpath(%s, uid=%ld, gid=%ld, flags=%lx, level=%d, offset=%d):\n", - fn, (long) uid, (long) gid, flags, level, offset); - - if (!bitnset(DBS_GROUPWRITABLEDIRPATHSAFE, DontBlameSendmail)) - mode |= S_IWGRP; - - /* Make a modifiable copy of the filename */ - if (sm_strlcpy(s, fn, sizeof s) >= sizeof s) - return EINVAL; - - p = s + offset; - while (p != NULL) - { - /* put back character */ - if (saveptr != NULL) - { - *saveptr = save; - saveptr = NULL; - p++; - } - - if (*p == '\0') - break; - - p = strchr(p, '/'); - - /* Special case for root directory */ - if (p == s) - { - save = *(p + 1); - saveptr = p + 1; - *(p + 1) = '\0'; - } - else if (p != NULL) - { - save = *p; - saveptr = p; - *p = '\0'; - } - - /* Heuristic: . and .. have already been checked */ - enddir = strrchr(s, '/'); - if (enddir != NULL && - (strcmp(enddir, "/..") == 0 || - strcmp(enddir, "/.") == 0)) - continue; - - if (tTd(44, 20)) - sm_dprintf("\t[dir %s]\n", s); - -# if HASLSTAT - ret = lstat(s, &stbuf); -# else /* HASLSTAT */ - ret = stat(s, &stbuf); -# endif /* HASLSTAT */ - if (ret < 0) - { - ret = errno; - break; - } - -# ifdef S_ISLNK - /* Follow symlinks */ - if (S_ISLNK(stbuf.st_mode)) - { - int linklen; - char *target; - char buf[MAXPATHLEN]; - - memset(buf, '\0', sizeof buf); - linklen = readlink(s, buf, sizeof buf); - if (linklen < 0) - { - ret = errno; - break; - } - if (linklen >= sizeof buf) - { - /* file name too long for buffer */ - ret = errno = EINVAL; - 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]; - - sptr = strrchr(s, '/'); - if (sptr != NULL) - { - *sptr = '\0'; - offset = sptr + 1 - s; - if (sm_strlcpyn(fullbuf, - sizeof fullbuf, 2, - s, "/") >= - sizeof fullbuf || - sm_strlcat(fullbuf, buf, - sizeof fullbuf) >= - sizeof fullbuf) - { - ret = EINVAL; - break; - } - *sptr = '/'; - } - else - { - if (sm_strlcpy(fullbuf, buf, - sizeof fullbuf) >= - sizeof fullbuf) - { - ret = EINVAL; - break; - } - } - 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)) - sm_dprintf("\t[dir %s] mode %lo ", - s, (unsigned 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)) - sm_dprintf("FATAL\n"); - break; - } - if (tTd(44, 4)) - sm_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)) - sm_dprintf("\t[dir %s] %s\n", fn, - ret == 0 ? "OK" : sm_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. -*/ - -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)) - sm_dprintf("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. -*/ - -SM_FILE_T * -safefopen(fn, omode, cmode, sff) - char *fn; - int omode; - int cmode; - long sff; -{ - int fd; - int save_errno; - SM_FILE_T *fp; - int fmode; - - switch (omode & O_ACCMODE) - { - case O_RDONLY: - fmode = SM_IO_RDONLY; - break; - - case O_WRONLY: - if (bitset(O_APPEND, omode)) - fmode = SM_IO_APPEND; - else - fmode = SM_IO_WRONLY; - break; - - case O_RDWR: - if (bitset(O_TRUNC, omode)) - fmode = SM_IO_RDWRTR; - else if (bitset(O_APPEND, omode)) - fmode = SM_IO_APPENDRW; - else - fmode = SM_IO_RDWR; - break; - - default: - syserr("554 5.3.5 safefopen: unknown omode %o", omode); - fmode = 0; - } - fd = safeopen(fn, omode, cmode, sff); - if (fd < 0) - { - save_errno = errno; - if (tTd(44, 10)) - sm_dprintf("safefopen: safeopen failed: %s\n", - sm_errstring(errno)); - errno = save_errno; - return NULL; - } - fp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, - (void *) &fd, fmode, NULL); - if (fp != NULL) - return fp; - - save_errno = errno; - if (tTd(44, 10)) - { - sm_dprintf("safefopen: fdopen(%s, %d) failed: omode=%x, sff=%lx, err=%s\n", - fn, fmode, omode, sff, sm_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)) - { - sm_dprintf("File changed after opening:\n"); - sm_dprintf(" nlink = %ld/%ld\n", - (long) stb->st_nlink, (long) sta.st_nlink); - sm_dprintf(" dev = %ld/%ld\n", - (long) stb->st_dev, (long) sta.st_dev); - sm_dprintf(" ino = %llu/%llu\n", - (ULONGLONG_T) stb->st_ino, - (ULONGLONG_T) sta.st_ino); -# if HAS_ST_GEN - sm_dprintf(" gen = %ld/%ld\n", - (long) stb->st_gen, (long) sta.st_gen); -# endif /* HAS_ST_GEN */ - sm_dprintf(" uid = %ld/%ld\n", - (long) stb->st_uid, (long) sta.st_uid); - sm_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; -} |