don't alias \-quoted addresses
[unix-history] / usr / src / usr.sbin / sendmail / src / recipient.c
index 3b3d249..af46314 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)recipient.c        8.81 (Berkeley) %G%";
+static char sccsid[] = "@(#)recipient.c        8.96 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -421,10 +421,11 @@ recipient(a, sendq, aliaslevel, e)
        }
 
        /* try aliasing */
        }
 
        /* try aliasing */
-       if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags))
+       if (!quoted && !bitset(QDONTSEND, a->q_flags) &&
+           bitnset(M_ALIASABLE, m->m_flags))
                alias(a, sendq, aliaslevel, e);
 
                alias(a, sendq, aliaslevel, e);
 
-# ifdef USERDB
+# if USERDB
        /* if not aliased, look it up in the user database */
        if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) &&
            bitnset(M_CHECKUDB, m->m_flags))
        /* if not aliased, look it up in the user database */
        if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) &&
            bitnset(M_CHECKUDB, m->m_flags))
@@ -523,12 +524,16 @@ recipient(a, sendq, aliaslevel, e)
                        buildfname(pw->pw_gecos, pw->pw_name, nbuf);
                        if (nbuf[0] != '\0')
                                a->q_fullname = newstr(nbuf);
                        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))
+                       if (!usershellok(pw->pw_name, pw->pw_shell))
                        {
                                a->q_flags |= QBOGUSSHELL;
                        }
                        {
                                a->q_flags |= QBOGUSSHELL;
                        }
-                       if (!quoted)
+                       if (bitset(EF_VRFYONLY, e->e_flags))
+                       {
+                               /* don't do any more now */
+                               a->q_flags |= QVERIFIED;
+                       }
+                       else if (!quoted)
                                forward(a, sendq, aliaslevel, e);
                }
        }
                                forward(a, sendq, aliaslevel, e);
                }
        }
@@ -553,7 +558,7 @@ recipient(a, sendq, aliaslevel, e)
        {
                for (q = *sendq; q != NULL; q = q->q_next)
                {
        {
                for (q = *sendq; q != NULL; q = q->q_next)
                {
-                       if (!bitset(QDONTSEND|QBADADDR, q->q_flags) &&
+                       if (!bitset(QDONTSEND, q->q_flags) &&
                            bitset(QTHISPASS, q->q_flags))
                                break;
                }
                            bitset(QTHISPASS, q->q_flags))
                                break;
                }
@@ -594,12 +599,22 @@ recipient(a, sendq, aliaslevel, e)
                        q->q_flags &= ~QTHISPASS;
                }
                if (nrcpts == 1)
                        q->q_flags &= ~QTHISPASS;
                }
                if (nrcpts == 1)
-                       only->q_flags |= QPRIMARY;
-               else if (!initialdontsend)
+               {
+                       /* check to see if this actually got a new owner */
+                       q = only;
+                       while ((q = q->q_alias) != NULL)
+                       {
+                               if (q->q_owner != NULL)
+                                       break;
+                       }
+                       if (q == NULL)
+                               only->q_flags |= QPRIMARY;
+               }
+               else if (!initialdontsend && nrcpts > 0)
                {
                        /* arrange for return receipt */
                        e->e_flags |= EF_SENDRECEIPT;
                {
                        /* arrange for return receipt */
                        e->e_flags |= EF_SENDRECEIPT;
-                       a->q_flags |= QEXPLODED;
+                       a->q_flags |= QEXPANDED;
                        if (e->e_xfp != NULL)
                                fprintf(e->e_xfp,
                                        "%s... expanded to multiple addresses\n",
                        if (e->e_xfp != NULL)
                                fprintf(e->e_xfp,
                                        "%s... expanded to multiple addresses\n",
@@ -668,7 +683,7 @@ finduser(name, fuzzyp)
                return (pw);
        }
 
                return (pw);
        }
 
-#ifdef MATCHGECOS
+#if MATCHGECOS
        /* see if fuzzy matching allowed */
        if (!MatchGecos)
        {
        /* see if fuzzy matching allowed */
        if (!MatchGecos)
        {
@@ -738,8 +753,6 @@ writable(filename, ctladdr, flags)
 {
        uid_t euid;
        gid_t egid;
 {
        uid_t euid;
        gid_t egid;
-       int bits;
-       register char *p;
        char *uname;
 
        if (tTd(29, 5))
        char *uname;
 
        if (tTd(29, 5))
@@ -762,8 +775,6 @@ writable(filename, ctladdr, flags)
        }
        else if (bitset(SFF_RUNASREALUID, flags))
        {
        }
        else if (bitset(SFF_RUNASREALUID, flags))
        {
-               extern char RealUserName[];
-
                euid = RealUid;
                egid = RealGid;
                uname = RealUserName;
                euid = RealUid;
                egid = RealGid;
                uname = RealUserName;
@@ -772,10 +783,12 @@ writable(filename, ctladdr, flags)
        {
                euid = FileMailer->m_uid;
                egid = FileMailer->m_gid;
        {
                euid = FileMailer->m_uid;
                egid = FileMailer->m_gid;
+               uname = NULL;
        }
        else
        {
                euid = egid = 0;
        }
        else
        {
                euid = egid = 0;
+               uname = NULL;
        }
        if (euid == 0)
        {
        }
        if (euid == 0)
        {
@@ -885,7 +898,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
                printf("include: old uid = %d/%d\n", getuid(), geteuid());
 
        if (forwarding)
                printf("include: old uid = %d/%d\n", getuid(), geteuid());
 
        if (forwarding)
-               sfflags |= SFF_MUSTOWN;
+               sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK;
 
        ca = getctladdr(ctladdr);
        if (ca == NULL)
 
        ca = getctladdr(ctladdr);
        if (ca == NULL)
@@ -900,7 +913,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
                gid = ca->q_gid;
                uname = ca->q_user;
        }
                gid = ca->q_gid;
                uname = ca->q_user;
        }
-#ifdef HASSETREUID
+#if HASSETREUID || USESETEUID
        saveduid = geteuid();
        savedgid = getegid();
        if (saveduid == 0)
        saveduid = geteuid();
        savedgid = getegid();
        if (saveduid == 0)
@@ -908,14 +921,20 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
                initgroups(uname, gid);
                if (uid != 0)
                {
                initgroups(uname, gid);
                if (uid != 0)
                {
+# if USESETEUID
+                       if (seteuid(uid) < 0)
+                               syserr("seteuid(%d) failure (real=%d, eff=%d)",
+                                       uid, getuid(), geteuid());
+# else
                        if (setreuid(0, uid) < 0)
                                syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
                                        uid, getuid(), geteuid());
                        if (setreuid(0, uid) < 0)
                                syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
                                        uid, getuid(), geteuid());
+# endif
                        else
                                sfflags |= SFF_NOPATHCHECK;
                }
        }
                        else
                                sfflags |= SFF_NOPATHCHECK;
                }
        }
-#endif                   
+#endif
 
        if (tTd(27, 9))
                printf("include: new uid = %d/%d\n", getuid(), geteuid());
 
        if (tTd(27, 9))
                printf("include: new uid = %d/%d\n", getuid(), geteuid());
@@ -963,17 +982,23 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
 
 resetuid:
 
 
 resetuid:
 
-#ifdef HASSETREUID
+#if HASSETREUID || USESETEUID
        if (saveduid == 0)
        {
                if (uid != 0)
                {
        if (saveduid == 0)
        {
                if (uid != 0)
                {
+# if USESETEUID
+                       if (seteuid(0) < 0)
+                               syserr("seteuid(0) failure (real=%d, eff=%d)",
+                                       getuid(), geteuid());
+# else
                        if (setreuid(-1, 0) < 0)
                                syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
                                        getuid(), geteuid());
                        if (setreuid(RealUid, 0) < 0)
                                syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
                                        RealUid, getuid(), geteuid());
                        if (setreuid(-1, 0) < 0)
                                syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
                                        getuid(), geteuid());
                        if (setreuid(RealUid, 0) < 0)
                                syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
                                        RealUid, getuid(), geteuid());
+# endif
                }
                setgid(savedgid);
        }
                }
                setgid(savedgid);
        }
@@ -1026,7 +1051,7 @@ resetuid:
                                sh = pw->pw_shell;
                        else
                                sh = "/SENDMAIL/ANY/SHELL/";
                                sh = pw->pw_shell;
                        else
                                sh = "/SENDMAIL/ANY/SHELL/";
-                       if (!usershellok(sh))
+                       if (!usershellok(pw->pw_name, sh))
                        {
                                if (safechown)
                                        ctladdr->q_flags |= QBOGUSSHELL;
                        {
                                if (safechown)
                                        ctladdr->q_flags |= QBOGUSSHELL;
@@ -1079,7 +1104,7 @@ resetuid:
                {
                        if (p[1] == '@' && p[2] == '#' &&
                            isascii(p[-1]) && isspace(p[-1]) &&
                {
                        if (p[1] == '@' && p[2] == '#' &&
                            isascii(p[-1]) && isspace(p[-1]) &&
-                           isascii(p[3]) && isspace(p[3]))
+                           (p[3] == '\0' || (isascii(p[3]) && isspace(p[3]))))
                        {
                                p[-1] = '\0';
                                break;
                        {
                                p[-1] = '\0';
                                break;
@@ -1140,6 +1165,7 @@ includetimeout()
 **                     send queue.
 */
 
 **                     send queue.
 */
 
+void
 sendtoargv(argv, e)
        register char **argv;
        register ENVELOPE *e;
 sendtoargv(argv, e)
        register char **argv;
        register ENVELOPE *e;
@@ -1174,3 +1200,93 @@ getctladdr(a)
                a = a->q_alias;
        return (a);
 }
                a = a->q_alias;
        return (a);
 }
+\f/*
+**  SELF_REFERENCE -- check to see if an address references itself
+**
+**     The check is done through a chain of aliases.  If it is part of
+**     a loop, break the loop at the "best" address, that is, the one
+**     that exists as a real user.
+**
+**     This is to handle the case of:
+**             awc:            Andrew.Chang
+**             Andrew.Chang:   awc@mail.server
+**     which is a problem only on mail.server.
+**
+**     Parameters:
+**             a -- the address to check.
+**             e -- the current envelope.
+**
+**     Returns:
+**             The address that should be retained.
+*/
+
+ADDRESS *
+self_reference(a, e)
+       ADDRESS *a;
+       ENVELOPE *e;
+{
+       ADDRESS *b;             /* top entry in self ref loop */
+       ADDRESS *c;             /* entry that point to a real mail box */
+
+       if (tTd(27, 1))
+               printf("self_reference(%s)\n", a->q_paddr);
+
+       for (b = a->q_alias; b != NULL; b = b->q_alias)
+       {
+               if (sameaddr(a, b))
+                       break;
+       }
+
+       if (b == NULL)
+       {
+               if (tTd(27, 1))
+                       printf("\t... no self ref\n");
+               return NULL;
+       }
+
+       /*
+       **  Pick the first address that resolved to a real mail box
+       **  i.e has a pw entry.  The returned value will be marked
+       **  QSELFREF in recipient(), which in turn will disable alias()
+       **  from marking it QDONTSEND, which mean it will be used
+       **  as a deliverable address.
+       **
+       **  The 2 key thing to note here are:
+       **      1) we are in a recursive call sequence:
+       **              alias->sentolist->recipient->alias
+       **      2) normally, when we return back to alias(), the address
+       **         will be marked QDONTSEND, since alias() assumes the
+       **         expanded form will be used instead of the current address.
+       **         This behaviour is turned off if the address is marked
+       **         QSELFREF We set QSELFREF when we return to recipient().
+       */
+
+       c = a;
+       while (c != NULL)
+       {
+               if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
+               {
+                       if (tTd(27, 2))
+                               printf("\t... getpwnam(%s)... ", c->q_user);
+                       if (sm_getpwnam(c->q_user) != NULL)
+                       {
+                               if (tTd(27, 2))
+                                       printf("found\n");
+
+                               /* ought to cache results here */
+                               if (sameaddr(b, c))
+                                       return b;
+                               else
+                                       return c;
+                       }
+                       if (tTd(27, 2))
+                               printf("failed\n");
+               }
+               c = c->q_alias;
+       }
+
+       if (tTd(27, 1))
+               printf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
+
+       return NULL;
+}