📄 recipient.c
字号:
*fuzzyp = FALSE; /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ for (p = name; *p != '\0'; p++) if (!isascii(*p) || !isdigit(*p)) break; if (*p == '\0') { if (tTd(29, 4)) printf("failed (numeric input)\n"); return NULL; } /* look up this login name using fast path */ if ((pw = getpwnam(name)) != NULL) { if (tTd(29, 4)) printf("found (non-fuzzy)\n"); return (pw); }#ifdef MATCHGECOS /* see if fuzzy matching allowed */ if (!MatchGecos) { if (tTd(29, 4)) printf("not found (fuzzy disabled)\n"); return NULL; } /* search for a matching full name instead */ for (p = name; *p != '\0'; p++) { if (*p == (SpaceSub & 0177) || *p == '_') *p = ' '; } (void) setpwent(); while ((pw = getpwent()) != NULL) { char buf[MAXNAME]; buildfname(pw->pw_gecos, pw->pw_name, buf); if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) { if (tTd(29, 4)) printf("fuzzy matches %s\n", pw->pw_name); message("sending to login name %s", pw->pw_name); *fuzzyp = TRUE; return (pw); } } if (tTd(29, 4)) printf("no fuzzy match found\n");#else if (tTd(29, 4)) printf("not found (fuzzy disabled)\n");#endif return (NULL);}/*** WRITABLE -- predicate returning if the file is writable.**** This routine must duplicate the algorithm in sys/fio.c.** Unfortunately, we cannot use the access call since we** won't necessarily be the real uid when we try to** actually open the file.**** Notice that ANY file with ANY execute bit is automatically** not writable. This is also enforced by mailfile.**** Parameters:** 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.** FALSE -- if we cannot write this file.**** Side Effects:** none.*/boolwritable(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 (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 { /* 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) { euid = DefUid; uname = DefUser; } 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.**** Parameters:** fname -- filename to include.** forwarding -- if TRUE, we are reading a .forward file.** if FALSE, it's a :include: file.** ctladdr -- address template to use to fill in these** addresses -- effective user/group id are** the important things.** sendq -- a pointer to the head of the send queue** to put these addresses in.**** Returns:** open error status**** Side Effects:** reads the :include: file and sends to everyone** listed in that file.**** Security Note:** If you have restricted chown (that is, you can't** give a file away), it is reasonable to allow programs** and files called from this :include: file to be to be** run as the owner of the :include: file. This is bogus** if there is any chance of someone giving away a file.** We assume that pre-POSIX systems can give away files.**** There is an additional restriction that if you** forward to a :include: file, it will not take on** the ownership of the :include: file. This may not** be necessary, but shouldn't hurt.*/static jmp_buf CtxIncludeTimeout;static int includetimeout();#ifndef S_IWOTH# define S_IWOTH (S_IWRITE >> 6)#endifintinclude(fname, forwarding, ctladdr, sendq, e) char *fname; bool forwarding; ADDRESS *ctladdr; ADDRESS **sendq; ENVELOPE *e;{ register FILE *fp = NULL; char *oldto = e->e_to; char *oldfilename = FileName; int oldlinenumber = LineNumber; register EVENT *ev = NULL; int nincludes; register ADDRESS *ca; uid_t saveduid, uid; gid_t savedgid, gid; char *uname; int rval = 0; int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE; struct stat st; char buf[MAXLINE];#ifdef _POSIX_CHOWN_RESTRICTED# if _POSIX_CHOWN_RESTRICTED == -1# define safechown FALSE# else# define safechown TRUE# endif#else# ifdef _PC_CHOWN_RESTRICTED bool safechown;# else# ifdef BSD# define safechown TRUE# else# define safechown FALSE# endif# endif#endif extern bool chownsafe(); if (tTd(27, 2)) printf("include(%s)\n", fname); if (tTd(27, 4)) printf(" ruid=%d euid=%d\n", getuid(), geteuid()); if (tTd(27, 14)) { printf("ctladdr "); printaddr(ctladdr, FALSE); } if (tTd(27, 9)) printf("include: old uid = %d/%d\n", getuid(), geteuid()); ca = getctladdr(ctladdr); if (ca == NULL) { uid = DefUid; gid = DefGid; uname = DefUser; saveduid = -1; } else { uid = ca->q_uid; gid = ca->q_gid; uname = ca->q_user;#ifdef HASSETREUID saveduid = geteuid(); savedgid = getegid(); if (saveduid == 0) { initgroups(uname, gid); if (uid != 0) (void) setreuid(0, uid); }#endif } if (tTd(27, 9)) printf("include: new uid = %d/%d\n", getuid(), geteuid()); /* ** If home directory is remote mounted but server is down, ** this can hang or give errors; use a timeout to avoid this */ if (setjmp(CtxIncludeTimeout) != 0) { ctladdr->q_flags |= QQUEUEUP; errno = 0; /* return pseudo-error code */ rval = EOPENTIMEOUT; goto resetuid; } ev = setevent((time_t) 60, includetimeout, 0); /* the input file must be marked safe */ rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD); if (rval != 0) { /* don't use this :include: file */ if (tTd(27, 4)) printf("include: not safe (uid=%d): %s\n", uid, errstring(rval)); } else { fp = fopen(fname, "r"); if (fp == NULL) { rval = errno; if (tTd(27, 4)) printf("include: open: %s\n", errstring(rval)); } } clrevent(ev);resetuid:#ifdef HASSETREUID if (saveduid == 0) { if (uid != 0) if (setreuid(-1, 0) < 0 || setreuid(RealUid, 0) < 0) syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", RealUid, getuid(), geteuid()); setgid(savedgid); }#endif 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; }#ifndef safechown safechown = chownsafe(fileno(fp));#endif if (ca == NULL && safechown) { 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 { char *sh; register struct passwd *pw; sh = "/SENDMAIL/ANY/SHELL/"; pw = getpwuid(st.st_uid); if (pw != NULL) { ctladdr->q_ruser = newstr(pw->pw_name); if (safechown) sh = pw->pw_shell; } if (pw == NULL) ctladdr->q_flags |= QBOGUSSHELL; else if(!usershellok(sh)) { if (safechown) ctladdr->q_flags |= QBOGUSSHELL; else ctladdr->q_flags |= QUNSAFEADDR; } } if (bitset(EF_VRFYONLY, e->e_flags)) { /* don't do any more now */ ctladdr->q_flags |= QVERIFIED; e->e_nrcpts++; xfclose(fp, "include", fname); 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; ctladdr->q_flags &= ~QSELFREF; nincludes = 0; while (fgets(buf, sizeof buf, fp) != NULL) { register char *p = strchr(buf, '\n'); LineNumber++; if (p != NULL) *p = '\0'; if (buf[0] == '#' || buf[0] == '\0') continue; e->e_to = NULL; message("%s to %s", forwarding ? "forwarding" : "sending", buf);#ifdef LOG if (forwarding && LogLevel > 9) syslog(LOG_INFO, "%s: forward %s => %s", e->e_id == NULL ? "NOQUEUE" : e->e_id, oldto, buf);#endif AliasLevel++; nincludes += sendtolist(buf, ctladdr, sendq, e); AliasLevel--; } if (ferror(fp) && tTd(27, 3)) printf("include: read error: %s\n", errstring(errno)); if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) { if (tTd(27, 5)) { printf("include: QDONTSEND "); printaddr(ctladdr, FALSE); } ctladdr->q_flags |= QDONTSEND; } (void) xfclose(fp, "include", fname); FileName = oldfilename; LineNumber = oldlinenumber; e->e_to = oldto; return rval;}staticincludetimeout(){ longjmp(CtxIncludeTimeout, 1);}/*** SENDTOARGV -- send to an argument vector.**** Parameters:** argv -- argument vector to send to.** e -- the current envelope.**** Returns:** none.**** Side Effects:** puts all addresses on the argument vector onto the** send queue.*/sendtoargv(argv, e) register char **argv; register ENVELOPE *e;{ register char *p; while ((p = *argv++) != NULL) { (void) sendtolist(p, NULLADDR, &e->e_sendqueue, e); }}/*** GETCTLADDR -- get controlling address from an address header.**** If none, get one corresponding to the effective userid.**** Parameters:** a -- the address to find the controller of.**** Returns:** the controlling address.**** Side Effects:** none.*/ADDRESS *getctladdr(a) register ADDRESS *a;{ while (a != NULL && !bitset(QGOODUID, a->q_flags)) a = a->q_alias; return (a);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -