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:
1
MANIFEST
1
MANIFEST
@@ -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
|
||||
|
@@ -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
59
common/setgroups.c
Normal 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;
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user