diff options
| author | glass <glass@NetBSD.org> | 1994-01-31 02:38:08 +0000 |
|---|---|---|
| committer | glass <glass@NetBSD.org> | 1994-01-31 02:38:08 +0000 |
| commit | f1cb96b2ca44e4aa70b57abc58ffc615af6b0583 (patch) | |
| tree | a6ebcdd285462a08f65dcae64a1b57567dd129ea /usr.sbin/sendmail/src/recipient.c | |
| parent | f12eaca826e8750987e7055165cd38313cb63b46 (diff) | |
upgrade to version 8.6.5
Diffstat (limited to 'usr.sbin/sendmail/src/recipient.c')
| -rw-r--r-- | usr.sbin/sendmail/src/recipient.c | 241 |
1 files changed, 186 insertions, 55 deletions
diff --git a/usr.sbin/sendmail/src/recipient.c b/usr.sbin/sendmail/src/recipient.c index e80c6b5fb9a..706fddc82c4 100644 --- a/usr.sbin/sendmail/src/recipient.c +++ b/usr.sbin/sendmail/src/recipient.c @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)recipient.c 8.21 (Berkeley) 10/29/93"; +static char sccsid[] = "@(#)recipient.c 8.39 (Berkeley) 1/10/94"; #endif /* not lint */ # include "sendmail.h" @@ -222,10 +222,25 @@ recipient(a, sendq, e) stripquotes(buf); /* check for direct mailing to restricted mailers */ - if (a->q_alias == NULL && m == ProgMailer) + if (m == ProgMailer) { - a->q_flags |= QBADADDR; - usrerr("550 Cannot mail directly to programs"); + if (a->q_alias == NULL) + { + a->q_flags |= QBADADDR; + usrerr("550 Cannot mail directly to programs"); + } + else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) + { + a->q_flags |= QBADADDR; + usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", + a->q_alias->q_ruser, MyHostName); + } + else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) + { + a->q_flags |= QBADADDR; + usrerr("550 Address %s is unsafe for mailing to programs", + a->q_alias->q_paddr); + } } /* @@ -252,6 +267,8 @@ recipient(a, sendq, e) message("duplicate suppressed"); q->q_flags |= a->q_flags; } + else if (bitset(QSELFREF, q->q_flags)) + q->q_flags |= a->q_flags & ~QDONTSEND; a = q; goto testselfdestruct; } @@ -294,6 +311,7 @@ recipient(a, sendq, e) e->e_id, a->q_user, errstring(ret)); #endif a->q_flags |= QQUEUEUP; + a->q_flags &= ~QDONTSEND; usrerr("451 Cannot open %s: %s", a->q_user, errstring(ret)); } @@ -307,18 +325,27 @@ recipient(a, sendq, e) } else if (m == FileMailer) { - struct stat stb; extern bool writable(); - p = strrchr(buf, '/'); /* check if writable or creatable */ if (a->q_alias == NULL) { a->q_flags |= QBADADDR; usrerr("550 Cannot mail directly to files"); } - else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : - (*p = '\0', safefile(buf, RealUid, RealGid, NULL, TRUE, S_IWRITE|S_IEXEC) != 0)) + else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) + { + a->q_flags |= QBADADDR; + usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", + a->q_alias->q_ruser, MyHostName); + } + else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) + { + a->q_flags |= QBADADDR; + usrerr("550 Address %s is unsafe for mailing to files", + a->q_alias->q_paddr); + } + else if (!writable(buf, getctladdr(a), SFF_ANYFILE)) { a->q_flags |= QBADADDR; giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, e); @@ -340,7 +367,6 @@ recipient(a, sendq, e) if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags)) { extern int udbexpand(); - extern int errno; if (udbexpand(a, sendq, e) == EX_TEMPFAIL) { @@ -429,6 +455,11 @@ recipient(a, sendq, e) buildfname(pw->pw_gecos, pw->pw_name, nbuf); if (nbuf[0] != '\0') a->q_fullname = newstr(nbuf); + if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && + !usershellok(pw->pw_shell)) + { + a->q_flags |= QBOGUSSHELL; + } if (!quoted) forward(a, sendq, e); } @@ -563,7 +594,9 @@ finduser(name, fuzzyp) ** not writable. This is also enforced by mailfile. ** ** Parameters: -** s -- pointer to a stat struct for the file. +** filename -- the file name to check. +** ctladdr -- the controlling address for this file. +** flags -- SFF_* flags to control the function. ** ** Returns: ** TRUE -- if we will be able to write this file. @@ -574,35 +607,98 @@ finduser(name, fuzzyp) */ bool -writable(s) - register struct stat *s; +writable(filename, ctladdr, flags) + char *filename; + ADDRESS *ctladdr; + int flags; { uid_t euid; gid_t egid; int bits; + register char *p; + char *uname; + struct stat stb; + extern char RealUserName[]; - if (bitset(0111, s->st_mode)) - return (FALSE); - euid = RealUid; - egid = RealGid; - if (geteuid() == 0) + if (tTd(29, 5)) + printf("writable(%s, %x)\n", filename, flags); + +#ifdef HASLSTAT + if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb) + : stat(filename, &stb)) < 0) +#else + if (stat(filename, &stb) < 0) +#endif { - if (bitset(S_ISUID, s->st_mode)) - euid = s->st_uid; - if (bitset(S_ISGID, s->st_mode)) - egid = s->st_gid; + /* file does not exist -- see if directory is safe */ + p = strrchr(filename, '/'); + if (p == NULL) + { + errno = ENOTDIR; + return FALSE; + } + *p = '\0'; + errno = safefile(filename, RealUid, RealGid, RealUserName, + SFF_MUSTOWN, S_IWRITE|S_IEXEC); + *p = '/'; + return errno == 0; } +#ifdef SUID_ROOT_FILES_OK + /* really ought to be passed down -- and not a good idea */ + flags |= SFF_ROOTOK; +#endif + + /* + ** File does exist -- check that it is writable. + */ + + if (bitset(0111, stb.st_mode)) + { + if (tTd(29, 5)) + printf("failed (mode %o: x bits)\n", stb.st_mode); + errno = EPERM; + return (FALSE); + } + + if (ctladdr != NULL && geteuid() == 0) + { + euid = ctladdr->q_uid; + egid = ctladdr->q_gid; + uname = ctladdr->q_user; + } + else + { + euid = RealUid; + egid = RealGid; + uname = RealUserName; + } if (euid == 0) - return (TRUE); - bits = S_IWRITE; - if (euid != s->st_uid) { - bits >>= 3; - if (egid != s->st_gid) - bits >>= 3; + euid = DefUid; + uname = DefUser; } - return ((s->st_mode & bits) != 0); + if (egid == 0) + egid = DefGid; + if (geteuid() == 0) + { + if (bitset(S_ISUID, stb.st_mode) && + (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags))) + { + euid = stb.st_uid; + uname = NULL; + } + if (bitset(S_ISGID, stb.st_mode) && + (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags))) + egid = stb.st_gid; + } + + if (tTd(29, 5)) + printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n", + euid, egid, stb.st_uid, stb.st_gid); + + errno = safefile(filename, euid, egid, uname, flags, S_IWRITE); + return errno == 0; } /* ** INCLUDE -- handle :include: specification. @@ -628,6 +724,10 @@ writable(s) static jmp_buf CtxIncludeTimeout; static int includetimeout(); +#ifndef S_IWOTH +# define S_IWOTH (S_IWRITE >> 6) +#endif + int include(fname, forwarding, ctladdr, sendq, e) char *fname; @@ -647,6 +747,8 @@ include(fname, forwarding, ctladdr, sendq, e) gid_t savedgid, gid; char *uname; int rval = 0; + int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE; + struct stat st; char buf[MAXLINE]; if (tTd(27, 2)) @@ -665,9 +767,9 @@ include(fname, forwarding, ctladdr, sendq, e) ca = getctladdr(ctladdr); if (ca == NULL) { - uid = 0; - gid = 0; - uname = NULL; + uid = DefUid; + gid = DefGid; + uname = DefUser; saveduid = -1; } else @@ -699,7 +801,6 @@ include(fname, forwarding, ctladdr, sendq, e) { ctladdr->q_flags |= QQUEUEUP; errno = 0; - usrerr("451 open timeout on %s", fname); /* return pseudo-error code */ rval = EOPENTIMEOUT; @@ -708,41 +809,24 @@ include(fname, forwarding, ctladdr, sendq, e) ev = setevent((time_t) 60, includetimeout, 0); /* the input file must be marked safe */ - rval = safefile(fname, uid, gid, uname, forwarding, S_IREAD); + rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD); if (rval != 0) { /* don't use this :include: file */ - clrevent(ev); if (tTd(27, 4)) printf("include: not safe (uid=%d): %s\n", uid, errstring(rval)); - goto resetuid; } - - fp = fopen(fname, "r"); - if (fp == NULL) - { - rval = errno; - if (tTd(27, 4)) - printf("include: open: %s\n", errstring(rval)); - } - else if (ca == NULL) + else { - struct stat st; - - if (fstat(fileno(fp), &st) < 0) + fp = fopen(fname, "r"); + if (fp == NULL) { rval = errno; - syserr("Cannot fstat %s!", fname); - } - else - { - ctladdr->q_uid = st.st_uid; - ctladdr->q_gid = st.st_gid; - ctladdr->q_flags |= QGOODUID; + if (tTd(27, 4)) + printf("include: open: %s\n", errstring(rval)); } } - clrevent(ev); resetuid: @@ -761,9 +845,43 @@ resetuid: if (tTd(27, 9)) printf("include: reset uid = %d/%d\n", getuid(), geteuid()); + if (rval == EOPENTIMEOUT) + usrerr("451 open timeout on %s", fname); + if (fp == NULL) return rval; + if (fstat(fileno(fp), &st) < 0) + { + rval = errno; + syserr("Cannot fstat %s!", fname); + return rval; + } + + if (ca == NULL) + { + ctladdr->q_uid = st.st_uid; + ctladdr->q_gid = st.st_gid; + ctladdr->q_flags |= QGOODUID; + } + if (ca != NULL && ca->q_uid == st.st_uid) + { + /* optimization -- avoid getpwuid if we already have info */ + ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; + ctladdr->q_ruser = ca->q_ruser; + } + else + { + register struct passwd *pw; + + pw = getpwuid(st.st_uid); + if (pw == NULL || !usershellok(pw->pw_shell)) + { + ctladdr->q_ruser = newstr(pw->pw_name); + ctladdr->q_flags |= QBOGUSSHELL; + } + } + if (bitset(EF_VRFYONLY, e->e_flags)) { /* don't do any more now */ @@ -773,6 +891,19 @@ resetuid: return rval; } + /* + ** Check to see if some bad guy can write this file + ** + ** This should really do something clever with group + ** permissions; currently we just view world writable + ** as unsafe. Also, we don't check for writable + ** directories in the path. We've got to leave + ** something for the local sysad to do. + */ + + if (bitset(S_IWOTH, st.st_mode)) + ctladdr->q_flags |= QUNSAFEADDR; + /* read the file -- each line is a comma-separated list. */ FileName = fname; LineNumber = 0; |
