Imported Upstream version 1.8.2
[debian/sudo] / plugins / sudoers / set_perms.c
index 17c87b4a6dd9372ad802877b900419dc39a8a8e5..84215fb098764c3b430f95b20c5d1d494b265c07 100644 (file)
@@ -50,7 +50,7 @@
 /*
  * Prototypes
  */
-static void runas_setgroups(void);
+static struct group_list *runas_setgroups(void);
 
 /*
  * We keep track of the current permisstions and use a stack to restore
@@ -67,20 +67,13 @@ struct perm_state {
 #ifdef HAVE_SETRESUID
     gid_t sgid;
 #endif
-    GETGROUPS_T *groups;
-    int ngroups;
+    struct group_list *grlist;
 };
 
 #define PERM_STACK_MAX 16
 static struct perm_state perm_stack[PERM_STACK_MAX];
 static int perm_stack_depth = 0;
 
-/* XXX - make a runas_user struct? */
-int runas_ngroups = -1;
-#ifdef HAVE_GETGROUPS
-GETGROUPS_T *runas_groups;
-#endif
-
 #undef ID
 #define ID(x) (state->x == ostate->x ? -1 : state->x)
 #undef OID
@@ -91,6 +84,7 @@ rewind_perms(void)
 {
     while (perm_stack_depth > 1)
        restore_perms();
+    grlist_delref(perm_stack[0].grlist);
 }
 
 #ifdef HAVE_SETRESUID
@@ -104,7 +98,7 @@ rewind_perms(void)
 int
 set_perms(int perm)
 {
-    struct perm_state *state, *ostate = NULL;
+    struct perm_state *state, *ostate;
     const char *errstr;
     int noexit;
 
@@ -112,17 +106,22 @@ set_perms(int perm)
     CLR(perm, PERM_MASK);
 
     if (perm_stack_depth == PERM_STACK_MAX) {
-       errstr = "perm stack overflow";
+       errstr = _("perm stack overflow");
        errno = EINVAL;
        goto bad;
     }
 
     state = &perm_stack[perm_stack_depth];
-    if (perm_stack_depth)
+    if (perm != PERM_INITIAL) {
+       if (perm_stack_depth == 0) {
+           errstr = _("perm stack underflow");
+           errno = EINVAL;
+           goto bad;
+       }
        ostate = &perm_stack[perm_stack_depth - 1];
-
-    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
-       goto done;
+       if (memcmp(state, ostate, sizeof(*state)) == 0)
+           goto done;
+    }
 
     switch (perm) {
     case PERM_INITIAL:
@@ -146,8 +145,8 @@ set_perms(int perm)
        state->egid = getegid();
        state->sgid = state->egid; /* in case we are setgid */
 #endif
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
        break;
 
     case PERM_ROOT:
@@ -161,19 +160,11 @@ set_perms(int perm)
        state->rgid = -1;
        state->egid = -1;
        state->sgid = -1;
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
        break;
 
     case PERM_USER:
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
-       if (state->ngroups != -1 && state->groups != ostate->groups) {
-           if (setgroups(state->ngroups, state->groups)) {
-               errstr = "setgroups()";
-               goto bad;
-           }
-       }
        state->rgid = -1;
        state->egid = user_gid;
        state->sgid = -1;
@@ -181,6 +172,14 @@ set_perms(int perm)
            errstr = "setresgid(-1, user_gid, -1)";
            goto bad;
        }
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
+       if (state->grlist != ostate->grlist) {
+           if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
        state->ruid = user_uid;
        state->euid = user_uid;
        state->suid = ROOT_UID;
@@ -192,14 +191,6 @@ set_perms(int perm)
 
     case PERM_FULL_USER:
        /* headed for exec() */
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
-       if (state->ngroups != -1 && state->groups != ostate->groups) {
-           if (setgroups(state->ngroups, state->groups)) {
-               errstr = "setgroups()";
-               goto bad;
-           }
-       }
        state->rgid = user_gid;
        state->egid = user_gid;
        state->sgid = user_gid;
@@ -207,6 +198,14 @@ set_perms(int perm)
            errstr = "setresgid(user_gid, user_gid, user_gid)";
            goto bad;
        }
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
+       if (state->grlist != ostate->grlist) {
+           if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
        state->ruid = user_uid;
        state->euid = user_uid;
        state->suid = user_uid;
@@ -217,36 +216,33 @@ set_perms(int perm)
        break;
 
     case PERM_RUNAS:
-       runas_setgroups();
-       state->groups = runas_groups;
-       state->ngroups = runas_ngroups;
-
        state->rgid = -1;
        state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
        state->sgid = -1;
        if (setresgid(-1, ID(egid), -1)) {
-           errstr = "unable to change to runas gid";
+           errstr = _("unable to change to runas gid");
            goto bad;
        }
+       state->grlist = runas_setgroups();
        state->ruid = -1;
        state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
        state->suid = -1;
        if (setresuid(-1, ID(euid), -1)) {
-           errstr = "unable to change to runas uid";
+           errstr = _("unable to change to runas uid");
            goto bad;
        }
        break;
 
     case PERM_SUDOERS:
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
 
        /* assumes euid == ROOT_UID, ruid == user */
        state->rgid = -1;
        state->egid = sudoers_gid;
        state->sgid = -1;
        if (setresgid(-1, ID(egid), -1))
-           error(1, "unable to change to sudoers gid");
+           error(1, _("unable to change to sudoers gid"));
 
        state->ruid = ROOT_UID;
        /*
@@ -266,8 +262,8 @@ set_perms(int perm)
        break;
 
     case PERM_TIMESTAMP:
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
        state->rgid = -1;
        state->egid = -1;
        state->sgid = -1;
@@ -287,7 +283,7 @@ done:
 bad:
     /* XXX - better warnings inline */
     warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
+       errno == EAGAIN ? _("too many processes") : strerror(errno));
     if (noexit)
        return 0;
     exit(1);
@@ -323,12 +319,13 @@ restore_perms(void)
            state->egid, state->sgid, OID(rgid), OID(egid), OID(sgid));
        goto bad;
     }
-    if (state->ngroups != -1 && state->groups != ostate->groups) {
-       if (setgroups(ostate->ngroups, ostate->groups)) {
+    if (state->grlist != ostate->grlist) {
+       if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
            warning("setgroups()");
            goto bad;
        }
     }
+    grlist_delref(state->grlist);
     return;
 
 bad:
@@ -347,7 +344,7 @@ bad:
 int
 set_perms(int perm)
 {
-    struct perm_state *state, *ostate = NULL;
+    struct perm_state *state, *ostate;
     const char *errstr;
     int noexit;
 
@@ -355,17 +352,22 @@ set_perms(int perm)
     CLR(perm, PERM_MASK);
 
     if (perm_stack_depth == PERM_STACK_MAX) {
-       errstr = "perm stack overflow";
+       errstr = _("perm stack overflow");
        errno = EINVAL;
        goto bad;
     }
 
     state = &perm_stack[perm_stack_depth];
-    if (perm_stack_depth)
+    if (perm != PERM_INITIAL) {
+       if (perm_stack_depth == 0) {
+           errstr = _("perm stack underflow");
+           errno = EINVAL;
+           goto bad;
+       }
        ostate = &perm_stack[perm_stack_depth - 1];
-
-    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
-       goto done;
+       if (memcmp(state, ostate, sizeof(*state)) == 0)
+           goto done;
+    }
 
     switch (perm) {
     case PERM_INITIAL:
@@ -374,8 +376,8 @@ set_perms(int perm)
        state->euid = geteuid();
        state->rgid = getgid();
        state->egid = getegid();
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
        break;
 
     case PERM_ROOT:
@@ -395,25 +397,25 @@ set_perms(int perm)
        state->euid = ROOT_UID;
        state->rgid = -1;
        state->egid = -1;
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
        break;
 
     case PERM_USER:
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
-       if (state->ngroups != -1 && state->groups != ostate->groups) {
-           if (setgroups(state->ngroups, state->groups)) {
-               errstr = "setgroups()";
-               goto bad;
-           }
-       }
        state->rgid = -1;
        state->egid = user_gid;
        if (setregid(-1, ID(egid))) {
            errstr = "setregid(-1, user_gid)";
            goto bad;
        }
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
+       if (state->grlist != ostate->grlist) {
+           if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
        state->ruid = ROOT_UID;
        state->euid = user_uid;
        if (setreuid(ID(ruid), ID(euid))) {
@@ -424,20 +426,20 @@ set_perms(int perm)
 
     case PERM_FULL_USER:
        /* headed for exec() */
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
-       if (state->ngroups != -1 && state->groups != ostate->groups) {
-           if (setgroups(state->ngroups, state->groups)) {
-               errstr = "setgroups()";
-               goto bad;
-           }
-       }
        state->rgid = user_gid;
        state->egid = user_gid;
        if (setregid(ID(rgid), ID(egid))) {
            errstr = "setregid(user_gid, user_gid)";
            goto bad;
        }
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
+       if (state->grlist != ostate->grlist) {
+           if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
        state->ruid = user_uid;
        state->euid = user_uid;
        if (setreuid(ID(ruid), ID(euid))) {
@@ -447,33 +449,30 @@ set_perms(int perm)
        break;
 
     case PERM_RUNAS:
-       runas_setgroups();
-       state->groups = runas_groups;
-       state->ngroups = runas_ngroups;
-
        state->rgid = -1;
        state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
        if (setregid(ID(rgid), ID(egid))) {
-           errstr = "unable to change to runas gid";
+           errstr = _("unable to change to runas gid");
            goto bad;
        }
+       state->grlist = runas_setgroups();
        state->ruid = ROOT_UID;
        state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
        if (setreuid(ID(ruid), ID(euid))) {
-           errstr = "unable to change to runas uid";
+           errstr = _("unable to change to runas uid");
            goto bad;
        }
        break;
 
     case PERM_SUDOERS:
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
 
        /* assume euid == ROOT_UID, ruid == user */
        state->rgid = -1;
        state->egid = sudoers_gid;
        if (setregid(-1, ID(egid)))
-           error(1, "unable to change to sudoers gid");
+           error(1, _("unable to change to sudoers gid"));
 
        state->ruid = ROOT_UID;
        /*
@@ -492,8 +491,8 @@ set_perms(int perm)
        break;
 
     case PERM_TIMESTAMP:
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
        state->rgid = -1;
        state->egid = -1;
        state->ruid = ROOT_UID;
@@ -511,7 +510,7 @@ done:
 bad:
     /* XXX - better warnings inline */
     warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
+       errno == EAGAIN ? _("too many processes") : strerror(errno));
     if (noexit)
        return 0;
     exit(1);
@@ -552,12 +551,13 @@ restore_perms(void)
            state->egid, OID(rgid), OID(egid));
        goto bad;
     }
-    if (state->ngroups != -1 && state->groups != ostate->groups) {
-       if (setgroups(ostate->ngroups, ostate->groups)) {
+    if (state->grlist != ostate->grlist) {
+       if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
            warning("setgroups()");
            goto bad;
        }
     }
+    grlist_delref(state->grlist);
     return;
 
 bad:
@@ -576,7 +576,7 @@ bad:
 int
 set_perms(int perm)
 {
-    struct perm_state *state, *ostate = NULL;
+    struct perm_state *state, *ostate;
     const char *errstr;
     int noexit;
 
@@ -584,17 +584,22 @@ set_perms(int perm)
     CLR(perm, PERM_MASK);
 
     if (perm_stack_depth == PERM_STACK_MAX) {
-       errstr = "perm stack overflow";
+       errstr = _("perm stack overflow");
        errno = EINVAL;
        goto bad;
     }
 
     state = &perm_stack[perm_stack_depth];
-    if (perm_stack_depth)
+    if (perm != PERM_INITIAL) {
+       if (perm_stack_depth == 0) {
+           errstr = _("perm stack underflow");
+           errno = EINVAL;
+           goto bad;
+       }
        ostate = &perm_stack[perm_stack_depth - 1];
-
-    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
-       goto done;
+       if (memcmp(state, ostate, sizeof(*state)) == 0)
+           goto done;
+    }
 
     /*
      * Since we only have setuid() and seteuid() and semantics
@@ -619,8 +624,8 @@ set_perms(int perm)
        state->euid = geteuid();
        state->rgid = getgid();
        state->egid = getegid();
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
        break;
 
     case PERM_ROOT:
@@ -629,25 +634,25 @@ set_perms(int perm)
        state->euid = ROOT_UID;
        state->rgid = -1;
        state->egid = -1;
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
        break;
 
     case PERM_USER:
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
-       if (state->ngroups != -1 && state->groups != ostate->groups) {
-           if (setgroups(state->ngroups, state->groups)) {
-               errstr = "setgroups()";
-               goto bad;
-           }
-       }
-       state->rgid = -1;
        state->egid = user_gid;
        if (setegid(ID(egid))) {
            errstr = "setegid(user_gid)";
            goto bad;
        }
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
+       if (state->grlist != ostate->grlist) {
+           if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = -1;
        state->ruid = ROOT_UID;
        state->euid = user_uid;
        if (seteuid(ID(euid))) {
@@ -658,20 +663,20 @@ set_perms(int perm)
 
     case PERM_FULL_USER:
        /* headed for exec() */
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
-       if (state->ngroups != -1 && state->groups != ostate->groups) {
-           if (setgroups(state->ngroups, state->groups)) {
-               errstr = "setgroups()";
-               goto bad;
-           }
-       }
        state->rgid = user_gid;
        state->egid = user_gid;
        if (setgid(user_gid)) {
            errstr = "setgid(user_gid)";
            goto bad;
        }
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
+       if (state->grlist != ostate->grlist) {
+           if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
        state->ruid = user_uid;
        state->euid = user_uid;
        if (setuid(user_uid)) {
@@ -681,33 +686,30 @@ set_perms(int perm)
        break;
 
     case PERM_RUNAS:
-       runas_setgroups();
-       state->groups = runas_groups;
-       state->ngroups = runas_ngroups;
-
        state->rgid = -1;
        state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
        if (setegid(ID(egid))) {
-           errstr = "unable to change to runas gid";
+           errstr = _("unable to change to runas gid");
            goto bad;
        }
+       state->grlist = runas_setgroups();
        state->ruid = -1;
        state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
        if (seteuid(ID(euid))) {
-           errstr = "unable to change to runas uid";
+           errstr = _("unable to change to runas uid");
            goto bad;
        }
        break;
 
     case PERM_SUDOERS:
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
 
        /* assume euid == ROOT_UID, ruid == user */
        state->rgid = -1;
        state->egid = sudoers_gid;
        if (setegid(ID(egid)))
-           error(1, "unable to change to sudoers gid");
+           error(1, _("unable to change to sudoers gid"));
 
        state->ruid = ROOT_UID;
        /*
@@ -726,8 +728,8 @@ set_perms(int perm)
        break;
 
     case PERM_TIMESTAMP:
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
        state->rgid = -1;
        state->egid = -1;
        state->ruid = ROOT_UID;
@@ -745,7 +747,7 @@ done:
 bad:
     /* XXX - better warnings inline */
     warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
+       errno == EAGAIN ? _("too many processes") : strerror(errno));
     if (noexit)
        return 0;
     exit(1);
@@ -781,8 +783,8 @@ restore_perms(void)
        warning("setegid(%d)", OID(egid));
        goto bad;
     }
-    if (state->ngroups != -1 && state->groups != ostate->groups) {
-       if (setgroups(ostate->ngroups, ostate->groups)) {
+    if (state->grlist != ostate->grlist) {
+       if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
            warning("setgroups()");
            goto bad;
        }
@@ -791,6 +793,7 @@ restore_perms(void)
        warning("seteuid(%d)", OID(euid));
        goto bad;
     }
+    grlist_delref(state->grlist);
     return;
 
 bad:
@@ -807,7 +810,7 @@ bad:
 int
 set_perms(int perm)
 {
-    struct perm_state *state, *ostate = NULL;
+    struct perm_state *state, *ostate;
     const char *errstr;
     int noexit;
 
@@ -815,32 +818,37 @@ set_perms(int perm)
     CLR(perm, PERM_MASK);
 
     if (perm_stack_depth == PERM_STACK_MAX) {
-       errstr = "perm stack overflow";
+       errstr = _("perm stack overflow");
        errno = EINVAL;
        goto bad;
     }
 
     state = &perm_stack[perm_stack_depth];
-    if (perm_stack_depth)
+    if (perm != PERM_INITIAL) {
+       if (perm_stack_depth == 0) {
+           errstr = _("perm stack underflow");
+           errno = EINVAL;
+           goto bad;
+       }
        ostate = &perm_stack[perm_stack_depth - 1];
-
-    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
-       goto done;
+       if (memcmp(state, ostate, sizeof(*state)) == 0)
+           goto done;
+    }
 
     switch (perm) {
     case PERM_INITIAL:
        /* Stash initial state */
        state->ruid = getuid();
        state->rgid = getgid();
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
        break;
 
     case PERM_ROOT:
        state->ruid = ROOT_UID;
        state->rgid = -1;
-       state->groups = NULL;
-       state->ngroups = -1;
+       state->grlist = ostate->grlist;
+       grlist_addref(state->grlist);
        if (setuid(ROOT_UID)) {
            errstr = "setuid(ROOT_UID)";
            goto bad;
@@ -848,16 +856,16 @@ set_perms(int perm)
        break;
 
     case PERM_FULL_USER:
-       state->groups = user_groups;
-       state->ngroups = user_ngroups;
-       if (state->ngroups != -1 && state->groups != ostate->groups) {
-           if (setgroups(state->ngroups, state->groups)) {
+       state->rgid = user_gid;
+       (void) setgid(user_gid);
+       state->grlist = user_group_list;
+       grlist_addref(state->grlist);
+       if (state->grlist != ostate->grlist) {
+           if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) {
                errstr = "setgroups()";
                goto bad;
            }
        }
-       state->rgid = user_gid;
-       (void) setgid(user_gid);
        state->ruid = user_uid;
        if (setuid(user_uid)) {
            errstr = "setuid(user_uid)";
@@ -879,7 +887,7 @@ done:
 bad:
     /* XXX - better warnings inline */
     warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
+       errno == EAGAIN ? _("too many processes") : strerror(errno));
     if (noexit)
        return 0;
     exit(1);
@@ -897,16 +905,17 @@ restore_perms(void)
     ostate = &perm_stack[perm_stack_depth - 2];
     perm_stack_depth--;
 
-    if (state->ngroups != -1 && state->groups != ostate->groups) {
-       if (setgroups(ostate->ngroups, ostate->groups)) {
-           warning("setgroups()");
-           goto bad;
-       }
-    }
     if (OID(rgid) != -1 && setgid(ostate->rgid)) {
        warning("setgid(%d)", ostate->rgid);
        goto bad;
     }
+    if (state->grlist != ostate->grlist) {
+       if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
+           warning("setgroups()");
+           goto bad;
+       }
+    }
+    grlist_delref(state->grlist);
     if (OID(ruid) != -1 && setuid(ostate->ruid)) {
        warning("setuid(%d)", ostate->ruid);
        goto bad;
@@ -920,53 +929,26 @@ bad:
 # endif /* HAVE_SETREUID */
 #endif /* HAVE_SETRESUID */
 
-#ifdef HAVE_INITGROUPS
-static void
-runas_setgroups()
+static struct group_list *
+runas_setgroups(void)
 {
-    static struct passwd *pw;
-    struct passwd *opw = pw;
-
-    if (def_preserve_groups)
-       return;
+    struct passwd *pw;
+    struct group_list *grlist;
 
-    /*
-     * Use stashed copy of runas groups if available, else initgroups and stash.
-     */
-    pw = runas_pw ? runas_pw : sudo_user.pw;
-    if (pw != opw) {
-       pw = runas_pw ? runas_pw : sudo_user.pw;
-# ifdef HAVE_SETAUTHDB
-       aix_setauthdb(pw->pw_name);
-# endif
-       if (initgroups(pw->pw_name, pw->pw_gid) < 0)
-           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
-# ifdef HAVE_GETGROUPS
-       if (runas_groups) {
-           efree(runas_groups);
-           runas_groups = NULL;
-       }
-       if ((runas_ngroups = getgroups(0, NULL)) > 0) {
-           runas_groups = emalloc2(runas_ngroups, sizeof(GETGROUPS_T));
-           if (getgroups(runas_ngroups, runas_groups) < 0)
-               log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
-       }
-#  ifdef HAVE_SETAUTHDB
-       aix_restoreauthdb();
-#  endif
-    } else {
-       if (setgroups(runas_ngroups, runas_groups) < 0)
-           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
-# endif /* HAVE_GETGROUPS */
+    if (def_preserve_groups) {
+       grlist_addref(user_group_list);
+       return user_group_list;
     }
-}
 
-#else
-
-static void
-runas_setgroups()
-{
-    /* STUB */
+    pw = runas_pw ? runas_pw : sudo_user.pw;
+#ifdef HAVE_SETAUTHDB
+    aix_setauthdb(pw->pw_name);
+#endif
+    grlist = get_group_list(pw);
+#ifdef HAVE_SETAUTHDB
+    aix_restoreauthdb();
+#endif
+    if (sudo_setgroups(grlist->ngids, grlist->gids) < 0)
+       log_error(USE_ERRNO|MSG_ONLY, _("unable to set runas group vector"));
+    return grlist;
 }
-
-#endif /* HAVE_INITGROUPS */