COMMAND

    sendmail

SYSTEMS AFFECTED

    Systems running sendmail 8.8.4

PROBLEM

    The initgroups()  is not  done until  deliver.c???   The *purpose*
    behind the setuid/setgid/initgroups is for security right?  So  in
    main, you have:

 if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
        {
                /* drop privileges -- daemon mode done after socket/bind */
                if (RunAsGid != 0)
                        (void) setgid(RunAsGid);
                if (RunAsUid != 0)
                        (void) setuid(RunAsUid);
        }

and:

                /* drop privileges */
                if (RunAsGid != 0)
                        (void) setgid(RunAsGid);
                if (RunAsUid != 0)
                        (void) setuid(RunAsUid);

    So we set  the uid and  gid here; but  we are *STILL*  not calling
    initgroups here as we should.   There is no reason to keep  all of
    those groups when we are explicitly saying "use this uid:gid"...

SOLUTION

------- main.c -------
*** -   Wed Dec 31 16:00:00 1969
--- main.c      Fri Dec  6 11:01:10 1996
***************
*** 139,144 ****
--- 139,145 ----
        extern void printqueue __P((void));
        extern void sendtoargv __P((char **, ENVELOPE *));
        extern void resetlimits __P((void));
+       extern void drop_privileges __P((void));

        /*
        **  Check to see if we reentered.
***************
*** 202,207 ****
--- 203,211 ----

        tTsetup(tTdvect, sizeof tTdvect, "0-99.1");

+       /* drop group id privileges (RunAsUser not yet set) */
+       drop_privileges();
+
        /* Handle any non-getoptable constructions. */
        obsolete(argv);

***************
*** 780,789 ****
        if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
        {
                /* drop privileges -- daemon mode done after socket/bind */
!               if (RunAsGid != 0)
!                       (void) setgid(RunAsGid);
!               if (RunAsUid != 0)
!                       (void) setuid(RunAsUid);
        }

        /*
--- 784,790 ----
        if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
        {
                /* drop privileges -- daemon mode done after socket/bind */
!               drop_privileges();
        }

        /*
***************
*** 1292,1301 ****
                nullserver = getrequests(CurEnv);

                /* drop privileges */
!               if (RunAsGid != 0)
!                       (void) setgid(RunAsGid);
!               if (RunAsUid != 0)
!                       (void) setuid(RunAsUid);

                /* at this point we are in a child: reset state */
                (void) newenvelope(CurEnv, CurEnv);
--- 1293,1299 ----
                nullserver = getrequests(CurEnv);

                /* drop privileges */
!               drop_privileges();

                /* at this point we are in a child: reset state */
                (void) newenvelope(CurEnv, CurEnv);
***************
*** 1956,1961 ****
--- 1954,1984 ----
                syslog(LOG_ALERT, "could not exec %s: %m", SaveArgv[0]);
  #endif
        exit(EX_OSFILE);
+ }
+  /*
+ **  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
+ **
+ **    Parameters:
+ **            none.
+ **
+ **    Returns:
+ **            none.
+ */
+
+ void
+ drop_privileges()
+ {
+ #ifdef NGROUPS_MAX
+       /* reset group permissions; these can be set later */
+       GIDSET_T emptygidset[NGROUPS_MAX];
+
+       emptygidset[0] = RunAsGid == 0 ? geteuid() : RunAsGid;
+       (void) setgroups(1, emptygidset);
+ #endif
+       if (RunAsGid != 0)
+               (void) setgid(RunAsGid);
+       if (RunAsUid != 0)
+               (void) setuid(RunAsUid);
  }
   /*
  **  TESTMODELINE -- process a test mode input line

------- queue.c -------
*** -   Wed Dec 31 16:00:00 1969
--- queue.c     Fri Dec  6 11:01:16 1996
***************
*** 527,532 ****
--- 527,533 ----
        extern ENVELOPE BlankEnvelope;
        extern void clrdaemon __P((void));
        extern void runqueueevent __P((bool));
+       extern void drop_privileges __P((void));

        /*
        **  If no work will ever be selected, don't even bother reading
***************
*** 631,642 ****

        /* drop privileges */
        if (geteuid() == (uid_t) 0)
!       {
!               if (RunAsGid != (gid_t) 0)
!                       (void) setgid(RunAsGid);
!               if (RunAsUid != (uid_t) 0)
!                       (void) setuid(RunAsUid);
!       }

        /*
        **  Create ourselves an envelope
--- 632,638 ----

        /* drop privileges */
        if (geteuid() == (uid_t) 0)
!               drop_privileges();

        /*
        **  Create ourselves an envelope