Add a wrapper for setgroups() that trims off extra groups and retries

if setgroups() fails.  Also add some missing addrefs for PERM_USER
and PERM_FULL_USER.
This commit is contained in:
Todd C. Miller
2011-07-20 16:54:12 -04:00
parent b124635b04
commit 022591f4bf
8 changed files with 140 additions and 67 deletions

View File

@@ -15,6 +15,7 @@ common/fileops.c
common/fmt_string.c
common/lbuf.c
common/list.c
common/setgroups.c
common/term.c
common/zero_bytes.c
compat/Makefile.in

View File

@@ -43,7 +43,7 @@ DEFS = @OSDEFS@
SHELL = @SHELL@
LTOBJS = alloc.lo atobool.lo fileops.lo fmt_string.lo \
lbuf.lo list.lo term.lo zero_bytes.lo @COMMON_OBJS@
lbuf.lo list.lo setgroups.lo term.lo zero_bytes.lo @COMMON_OBJS@
all: libcommon.la
@@ -113,6 +113,8 @@ lbuf.lo: $(srcdir)/lbuf.c $(top_builddir)/config.h $(incdir)/missing.h \
list.lo: $(srcdir)/list.c $(top_builddir)/config.h $(incdir)/missing.h \
$(incdir)/list.h $(incdir)/error.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/list.c
setgroups.lo: $(srcdir)/setgroups.c $(top_builddir)/config.h $(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/setgroups.c
term.lo: $(srcdir)/term.c $(top_builddir)/config.h $(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/term.c
zero_bytes.lo: $(srcdir)/zero_bytes.c $(top_builddir)/config.h \

59
common/setgroups.c Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2011 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <errno.h>
#include <limits.h>
#include "missing.h"
int
sudo_setgroups(int ngids, const GETGROUPS_T *gids)
{
int maxgids, rval;
rval = setgroups(ngids, gids);
if (rval == -1 && errno == EINVAL) {
/* Too many groups, try again with fewer. */
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
maxgids = sysconf(_SC_NGROUPS_MAX);
if (maxgids == -1)
#endif
maxgids = NGROUPS_MAX;
if (maxgids > ngids) {
/* Skip base gid. */
if (getegid() == gids[0])
rval = setgroups(maxgids, gids + 1);
}
}
return rval;
}

View File

@@ -141,7 +141,7 @@ set_perms(int perm)
state->sgid = state->egid; /* in case we are setgid */
#endif
state->grlist = user_group_list;
grlist_addref(user_group_list);
grlist_addref(state->grlist);
break;
case PERM_ROOT:
@@ -160,14 +160,6 @@ set_perms(int perm)
break;
case PERM_USER:
state->grlist = user_group_list;
grlist_addref(user_group_list);
if (state->grlist != ostate->grlist) {
if (setgroups(state->grlist->ngids, state->grlist->gids)) {
errstr = "setgroups()";
goto bad;
}
}
state->rgid = -1;
state->egid = user_gid;
state->sgid = -1;
@@ -175,6 +167,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;
@@ -186,14 +186,6 @@ set_perms(int perm)
case PERM_FULL_USER:
/* headed for exec() */
state->grlist = user_group_list;
grlist_addref(user_group_list);
if (state->grlist != ostate->grlist) {
if (setgroups(state->grlist->ngids, state->grlist->gids)) {
errstr = "setgroups()";
goto bad;
}
}
state->rgid = user_gid;
state->egid = user_gid;
state->sgid = user_gid;
@@ -201,6 +193,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;
@@ -211,7 +211,6 @@ set_perms(int perm)
break;
case PERM_RUNAS:
state->grlist = runas_setgroups();
state->rgid = -1;
state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
state->sgid = -1;
@@ -219,6 +218,7 @@ set_perms(int perm)
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;
@@ -315,7 +315,7 @@ restore_perms(void)
goto bad;
}
if (state->grlist != ostate->grlist) {
if (setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
warning("setgroups()");
goto bad;
}
@@ -392,19 +392,20 @@ set_perms(int perm)
break;
case PERM_USER:
state->grlist = user_group_list;
if (state->grlist != ostate->grlist) {
if (setgroups(state->grlist->ngids, state->grlist->gids)) {
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))) {
@@ -415,19 +416,20 @@ set_perms(int perm)
case PERM_FULL_USER:
/* headed for exec() */
state->grlist = user_group_list;
if (state->grlist != ostate->grlist) {
if (setgroups(state->grlist->ngids, state->grlist->gids)) {
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))) {
@@ -437,13 +439,13 @@ set_perms(int perm)
break;
case PERM_RUNAS:
state->grlist = runas_setgroups();
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");
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))) {
@@ -540,7 +542,7 @@ restore_perms(void)
goto bad;
}
if (state->grlist != ostate->grlist) {
if (setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
warning("setgroups()");
goto bad;
}
@@ -622,19 +624,20 @@ set_perms(int perm)
break;
case PERM_USER:
state->grlist = user_group_list;
if (state->grlist != ostate->grlist) {
if (setgroups(state->grlist->ngids, state->grlist->gids)) {
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))) {
@@ -645,19 +648,20 @@ set_perms(int perm)
case PERM_FULL_USER:
/* headed for exec() */
state->grlist = user_group_list;
if (state->grlist != ostate->grlist) {
if (setgroups(state->grlist->ngids, state->grlist->gids)) {
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)) {
@@ -667,13 +671,13 @@ set_perms(int perm)
break;
case PERM_RUNAS:
state->grlist = runas_setgroups();
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");
goto bad;
}
state->grlist = runas_setgroups();
state->ruid = -1;
state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
if (seteuid(ID(euid))) {
@@ -765,7 +769,7 @@ restore_perms(void)
goto bad;
}
if (state->grlist != ostate->grlist) {
if (setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
warning("setgroups()");
goto bad;
}
@@ -832,15 +836,16 @@ set_perms(int perm)
break;
case PERM_FULL_USER:
state->rgid = user_gid;
(void) setgid(user_gid);
state->grlist = user_group_list;
grlist_addref(state->grlist);
if (state->grlist != ostate->grlist) {
if (setgroups(state->grlist->ngids, state->grlist->gids)) {
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)";
@@ -880,17 +885,17 @@ restore_perms(void)
ostate = &perm_stack[perm_stack_depth - 2];
perm_stack_depth--;
if (OID(rgid) != -1 && setgid(ostate->rgid)) {
warning("setgid(%d)", ostate->rgid);
goto bad;
}
if (state->grlist != ostate->grlist) {
if (setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) {
warning("setgroups()");
goto bad;
}
}
grlist_delref(state->grlist);
if (OID(rgid) != -1 && setgid(ostate->rgid)) {
warning("setgid(%d)", ostate->rgid);
goto bad;
}
if (OID(ruid) != -1 && setuid(ostate->ruid)) {
warning("setuid(%d)", ostate->ruid);
goto bad;
@@ -923,7 +928,7 @@ runas_setgroups(void)
#ifdef HAVE_SETAUTHDB
aix_restoreauthdb();
#endif
if (setgroups(grlist->ngids, grlist->gids) < 0)
if (sudo_setgroups(grlist->ngids, grlist->gids) < 0)
log_error(USE_ERRNO|MSG_ONLY, _("unable to set runas group vector"));
return grlist;
}

View File

@@ -333,6 +333,9 @@ void group_plugin_unload(void);
int group_plugin_query(const char *user, const char *group,
const struct passwd *pwd);
/* setgroups.c */
int sudo_setgroups(int ngids, const GETGROUPS_T *gids);
#ifndef _SUDO_MAIN
extern struct sudo_user sudo_user;
extern struct passwd *list_pw;

View File

@@ -928,7 +928,7 @@ exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
if (details->ngroups >= 0) {
if (setgroups(details->ngroups, details->groups) < 0) {
if (sudo_setgroups(details->ngroups, details->groups) < 0) {
warning(_("unable to set supplementary group IDs"));
goto done;
}

View File

@@ -227,6 +227,9 @@ void aix_setauthdb(char *user);
/* interfaces.c */
int get_net_ifs(char **addrinfo);
/* setgroups.c */
int sudo_setgroups(int ngids, const GETGROUPS_T *gids);
#ifndef errno
extern int errno;
#endif

View File

@@ -64,12 +64,12 @@ switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups)
if (seteuid(ROOT_UID) != 0)
error(1, "seteuid(ROOT_UID)");
}
if (ngroups != -1) {
if (setgroups(ngroups, groups) != 0)
error(1, "setgroups");
}
if (setegid(egid) != 0)
error(1, "setegid(%d)", (int)egid);
if (ngroups != -1) {
if (sudo_setgroups(ngroups, groups) != 0)
error(1, "setgroups");
}
if (euid != ROOT_UID) {
if (seteuid(euid) != 0)
error(1, "seteuid(%d)", (int)euid);