diff options
Diffstat (limited to 'src/safefile.c')
-rw-r--r-- | src/safefile.c | 173 |
1 files changed, 106 insertions, 67 deletions
diff --git a/src/safefile.c b/src/safefile.c index 842a09f..ff94b3d 100644 --- a/src/safefile.c +++ b/src/safefile.c @@ -1,39 +1,17 @@ /* - * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1998 Sendmail, Inc. 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. * - * 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. + * 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. * - * 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 lint -static char sccsid[] = "@(#)safefile.c 8.18 (Berkeley) 8/1/97"; +static char sccsid[] = "@(#)safefile.c 8.43 (Berkeley) 10/13/1998"; #endif /* not lint */ # include "sendmail.h" @@ -63,18 +41,6 @@ static char sccsid[] = "@(#)safefile.c 8.18 (Berkeley) 8/1/97"; #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) -#endif - int safefile(fn, uid, gid, uname, flags, mode, st) char *fn; @@ -135,7 +101,8 @@ safefile(fn, uid, gid, uname, flags, mode, st) #ifdef SUID_ROOT_FILES_OK if (bitset(S_ISUID, st->st_mode)) #else - if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0) + if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0 && + st->st_uid != TrustedUid) #endif { uid = st->st_uid; @@ -174,6 +141,16 @@ safefile(fn, uid, gid, uname, flags, mode, st) } else { +#ifdef HASLSTAT + /* Need lstat() information if called stat() before */ + if (!bitset(SFF_NOSLINK, flags) && lstat(fn, st) < 0) + { + ret = errno; + if (tTd(44, 4)) + printf("\t%s\n", errstring(ret)); + return ret; + } +#endif /* directory is writable: disallow links */ flags |= SFF_NOLINK; } @@ -226,8 +203,34 @@ safefile(fn, uid, gid, uname, flags, mode, st) if (stat(dir, &stbuf) >= 0) { int md = S_IWRITE|S_IEXEC; - if (stbuf.st_uid != uid) - md >>= 6; + + if (stbuf.st_uid == uid) + ; + else if (uid == 0 && stbuf.st_uid == TrustedUid) + ; + else + { + md >>= 3; + if (stbuf.st_gid == gid) + ; +#ifndef NO_GROUP_SET + else if (uname != 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, uname) == 0) + break; + if (*gp == NULL) + md >>= 3; + } +#endif + else + md >>= 3; + } if ((stbuf.st_mode & md) != md) errno = EACCES; } @@ -246,40 +249,47 @@ safefile(fn, uid, gid, uname, flags, mode, st) if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) { if (tTd(44, 4)) - printf("\t[slink mode %o]\tE_SM_NOSLINK\n", - st->st_mode); + printf("\t[slink mode %lo]\tE_SM_NOSLINK\n", + (u_long) st->st_mode); return E_SM_NOSLINK; } #endif if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode)) { if (tTd(44, 4)) - printf("\t[non-reg mode %o]\tE_SM_REGONLY\n", - st->st_mode); + printf("\t[non-reg mode %lo]\tE_SM_REGONLY\n", + (u_long) st->st_mode); return E_SM_REGONLY; } - if (bitset(SFF_NOWFILES, flags) && - bitset(S_IWOTH | (UnsafeGroupWrites ? S_IWGRP : 0), st->st_mode)) + if (bitset(SFF_NOGWFILES, flags) && + bitset(S_IWGRP, st->st_mode)) { if (tTd(44, 4)) - printf("\t[write bits %o]\tE_SM_%cWFILE\n", - st->st_mode, - bitset(S_IWOTH, st->st_mode) ? 'W' : 'G'); - return bitset(S_IWOTH, st->st_mode) ? E_SM_WWFILE : E_SM_GWFILE; + printf("\t[write bits %lo]\tE_SM_GWFILE\n", + (u_long) st->st_mode); + return E_SM_GWFILE; + } + if (bitset(SFF_NOWWFILES, flags) && + bitset(S_IWOTH, st->st_mode)) + { + if (tTd(44, 4)) + printf("\t[write bits %lo]\tE_SM_WWFILE\n", + (u_long) st->st_mode); + return E_SM_WWFILE; } if (bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) && bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode)) { if (tTd(44, 4)) - printf("\t[exec bits %o]\tE_SM_ISEXEC]\n", - st->st_mode); + printf("\t[exec bits %lo]\tE_SM_ISEXEC]\n", + (u_long) st->st_mode); return E_SM_ISEXEC; } if (bitset(SFF_NOHLINK, flags) && st->st_nlink != 1) { if (tTd(44, 4)) printf("\t[link count %d]\tE_SM_NOHLINK\n", - st->st_nlink); + (int) st->st_nlink); return E_SM_NOHLINK; } @@ -287,7 +297,11 @@ safefile(fn, uid, gid, uname, flags, mode, st) ; else if (uid == 0 && !bitset(SFF_ROOTOK, flags)) mode >>= 6; - else if (st->st_uid != uid) + else if (st->st_uid == uid) + ; + else if (uid == 0 && st->st_uid == TrustedUid) + ; + else { mode >>= 3; if (st->st_gid == gid) @@ -314,6 +328,7 @@ safefile(fn, uid, gid, uname, flags, mode, st) (int) st->st_uid, (int) st->st_nlink, (u_long) st->st_mode, (u_long) mode); if ((st->st_uid == uid || st->st_uid == 0 || + st->st_uid == TrustedUid || !bitset(SFF_MUSTOWN, flags)) && (st->st_mode & mode) == mode) { @@ -357,6 +372,7 @@ safedirpath(fn, uid, gid, uname, flags) char *p; register struct group *gr = NULL; int ret = 0; + int mode = S_IWOTH; struct stat stbuf; /* special case root directory */ @@ -367,6 +383,9 @@ safedirpath(fn, uid, gid, uname, flags) printf("safedirpath(%s, uid=%ld, gid=%ld, flags=%x):\n", fn, (long) uid, (long) gid, flags); + if (!bitset(DBS_GROUPWRITABLEDIRPATHSAFE, DontBlameSendmail)) + mode |= S_IWGRP; + p = fn; do { @@ -381,11 +400,11 @@ safedirpath(fn, uid, gid, uname, flags) break; } if ((uid == 0 || bitset(SFF_SAFEDIRPATH, flags)) && - bitset(S_IWGRP|S_IWOTH, stbuf.st_mode)) + bitset(mode, stbuf.st_mode)) { if (tTd(44, 4)) - printf("\t[dir %s] mode %o\n", - fn, stbuf.st_mode); + printf("\t[dir %s] mode %lo\n", + fn, (u_long) stbuf.st_mode); if (bitset(SFF_SAFEDIRPATH, flags)) { if (bitset(S_IWOTH, stbuf.st_mode)) @@ -395,7 +414,11 @@ safedirpath(fn, uid, gid, uname, flags) break; } if (Verbose > 1) - message("051 WARNING: writable directory %s", fn); + message("051 WARNING: %s writable directory %s", + bitset(S_IWOTH, stbuf.st_mode) + ? "World" + : "Group", + fn); } if (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags)) { @@ -404,6 +427,15 @@ safedirpath(fn, uid, gid, uname, flags) ret = EACCES; break; } + + /* + ** Let OS determine access to file if we are not + ** running as a privileged user. This allows ACLs + ** to work. + */ + if (geteuid() != 0) + continue; + if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode)) continue; @@ -505,7 +537,7 @@ safeopen(fn, omode, cmode, sff) fd = dfopen(fn, omode, cmode, sff); if (fd < 0) return fd; - if (filechanged(fn, fd, &stb, sff)) + if (filechanged(fn, fd, &stb)) { syserr("554 cannot open: file %s changed after open", fn); close(fd); @@ -594,7 +626,6 @@ safefopen(fn, omode, cmode, sff) ** fn -- pathname of file to check. ** fd -- file descriptor to check. ** stb -- stat structure from before open. -** sff -- safe file flags. ** ** Returns: ** TRUE -- if a problem was detected. @@ -602,11 +633,10 @@ safefopen(fn, omode, cmode, sff) */ bool -filechanged(fn, fd, stb, sff) +filechanged(fn, fd, stb) char *fn; int fd; struct stat *stb; - int sff; { struct stat sta; @@ -639,8 +669,17 @@ filechanged(fn, fd, stb, sff) (long) stb->st_nlink, (long) sta.st_nlink); printf(" dev = %ld/%ld\n", (long) stb->st_dev, (long) sta.st_dev); - printf(" ino = %ld/%ld\n", - (long) stb->st_ino, (long) sta.st_ino); + if (sizeof sta.st_ino > sizeof (long)) + { + printf(" ino = %s/", + quad_to_string(stb->st_ino)); + printf("%s\n", + quad_to_string(sta.st_ino)); + } + else + printf(" ino = %lu/%lu\n", + (unsigned long) stb->st_ino, + (unsigned long) sta.st_ino); #if HAS_ST_GEN printf(" gen = %ld/%ld\n", (long) stb->st_gen, (long) sta.st_gen); |