From 250209d7a8392d4afddd1fecc637a6e962c8af63 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 28 Nov 2017 09:48:43 -0700 Subject: [PATCH] When running a command as the invoking user we cannot use the gid list from the front-end since it may not correspond to the user's aux group vector as defined by the group database. --- plugins/sudoers/ldap.c | 2 +- plugins/sudoers/policy.c | 5 ++- plugins/sudoers/pwutil.c | 69 ++++++++++++++++++++++++++--------- plugins/sudoers/pwutil.h | 7 ++-- plugins/sudoers/pwutil_impl.c | 13 +++++-- plugins/sudoers/set_perms.c | 5 ++- plugins/sudoers/sudoers.c | 4 +- plugins/sudoers/sudoers.h | 13 +++++-- 8 files changed, 84 insertions(+), 34 deletions(-) diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index 07d936605..9a5156a65 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -1697,7 +1697,7 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) sz += 12 + sudo_ldap_value_len(grlist->groups[i]); } } - if ((gidlist = sudo_get_gidlist(pw)) != NULL) { + if ((gidlist = sudo_get_gidlist(pw, ENTRY_TYPE_ANY)) != NULL) { for (i = 0; i < gidlist->ngids; i++) { if (pw->pw_gid == gidlist->gids[i]) continue; diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index 3afc33e3c..d0a17ae85 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -540,7 +540,10 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask, gid_t egid; size_t glsize; char *cp, *gid_list; - struct gid_list *gidlist = sudo_get_gidlist(runas_pw); + struct gid_list *gidlist; + + /* Only use results from a group db query, not the front end. */ + gidlist = sudo_get_gidlist(runas_pw, ENTRY_TYPE_QUERIED); /* We reserve an extra spot in the list for the effective gid. */ glsize = sizeof("runas_groups=") - 1 + diff --git a/plugins/sudoers/pwutil.c b/plugins/sudoers/pwutil.c index 34bbe92f1..2e817702c 100644 --- a/plugins/sudoers/pwutil.c +++ b/plugins/sudoers/pwutil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998-2005, 2007-2016 + * Copyright (c) 1996, 1998-2005, 2007-2017 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -69,7 +69,8 @@ static int cmp_grgid(const void *, const void *); #endif /* - * Compare by uid. + * Compare by user ID. + * v1 is the key to find or data to insert, v2 is in-tree data. */ static int cmp_pwuid(const void *v1, const void *v2) @@ -78,11 +79,14 @@ cmp_pwuid(const void *v1, const void *v2) const struct cache_item *ci2 = (const struct cache_item *) v2; if (ci1->k.uid == ci2->k.uid) return strcmp(ci1->registry, ci2->registry); - return ci1->k.uid - ci2->k.uid; + if (ci1->k.uid < ci2->k.uid) + return -1; + return 1; } /* - * Compare by user name. + * Compare by user/group name. + * v1 is the key to find or data to insert, v2 is in-tree data. */ static int cmp_pwnam(const void *v1, const void *v2) @@ -95,6 +99,28 @@ cmp_pwnam(const void *v1, const void *v2) return ret; } +/* + * Compare by user name, taking into account the source type. + * Need to differentiate between group IDs received from the front-end + * (via getgroups()) and groups IDs queried from the group database. + * v1 is the key to find or data to insert, v2 is in-tree data. + */ +static int +cmp_gidlist(const void *v1, const void *v2) +{ + const struct cache_item *ci1 = (const struct cache_item *) v1; + const struct cache_item *ci2 = (const struct cache_item *) v2; + int ret = strcmp(ci1->k.name, ci2->k.name); + if (ret == 0) { + if (ci1->type == ENTRY_TYPE_ANY || ci1->type == ci2->type) + return strcmp(ci1->registry, ci2->registry); + if (ci1->type < ci2->type) + return -1; + return 1; + } + return ret; +} + void sudo_pw_addref(struct passwd *pw) { @@ -401,7 +427,8 @@ sudo_freepwcache(void) } /* - * Compare by gid. + * Compare by group ID. + * v1 is the key to find or data to insert, v2 is in-tree data. */ static int cmp_grgid(const void *v1, const void *v2) @@ -410,7 +437,9 @@ cmp_grgid(const void *v1, const void *v2) const struct cache_item *ci2 = (const struct cache_item *) v2; if (ci1->k.gid == ci2->k.gid) return strcmp(ci1->registry, ci2->registry); - return ci1->k.gid - ci2->k.gid; + if (ci1->k.gid < ci2->k.gid) + return -1; + return 1; } void @@ -836,7 +865,7 @@ sudo_set_grlist(struct passwd *pw, char * const *groups) } struct gid_list * -sudo_get_gidlist(const struct passwd *pw) +sudo_get_gidlist(const struct passwd *pw, unsigned int type) { struct cache_item key, *item; struct rbnode *node; @@ -846,7 +875,7 @@ sudo_get_gidlist(const struct passwd *pw) __func__, pw->pw_name); if (gidlist_cache == NULL) { - gidlist_cache = rbcreate(cmp_pwnam); + gidlist_cache = rbcreate(cmp_gidlist); if (gidlist_cache == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_ptr(NULL); @@ -854,6 +883,7 @@ sudo_get_gidlist(const struct passwd *pw) } key.k.name = pw->pw_name; + key.type = type; getauthregistry(pw->pw_name, key.registry); if ((node = rbfind(gidlist_cache, &key)) != NULL) { item = node->data; @@ -862,7 +892,7 @@ sudo_get_gidlist(const struct passwd *pw) /* * Cache group db entry if it exists or a negative response if not. */ - item = sudo_make_gidlist_item(pw, NULL); + item = sudo_make_gidlist_item(pw, NULL, type); if (item == NULL) { /* Out of memory? */ debug_return_ptr(NULL); @@ -896,14 +926,14 @@ done: } int -sudo_set_gidlist(struct passwd *pw, char * const *gids) +sudo_set_gidlist(struct passwd *pw, char * const *gids, unsigned int type) { struct cache_item key, *item; struct rbnode *node; debug_decl(sudo_set_gidlist, SUDOERS_DEBUG_NSS) if (gidlist_cache == NULL) { - gidlist_cache = rbcreate(cmp_pwnam); + gidlist_cache = rbcreate(cmp_gidlist); if (gidlist_cache == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_int(-1); @@ -914,9 +944,10 @@ sudo_set_gidlist(struct passwd *pw, char * const *gids) * Cache group db entry if it doesn't already exist */ key.k.name = pw->pw_name; + key.type = type; getauthregistry(NULL, key.registry); if ((node = rbfind(gidlist_cache, &key)) == NULL) { - if ((item = sudo_make_gidlist_item(pw, gids)) == NULL) { + if ((item = sudo_make_gidlist_item(pw, gids, type)) == NULL) { sudo_warnx(U_("unable to parse gids for %s"), pw->pw_name); debug_return_int(-1); } @@ -961,7 +992,7 @@ user_in_group(const struct passwd *pw, const char *group) matched = true; goto done; } - if ((gidlist = sudo_get_gidlist(pw)) != NULL) { + if ((gidlist = sudo_get_gidlist(pw, ENTRY_TYPE_ANY)) != NULL) { for (i = 0; i < gidlist->ngids; i++) { if (gid == gidlist->gids[i]) { matched = true; @@ -992,11 +1023,13 @@ user_in_group(const struct passwd *pw, const char *group) } /* Check the supplementary group vector. */ - if (gidlist == NULL && (gidlist = sudo_get_gidlist(pw)) != NULL) { - for (i = 0; i < gidlist->ngids; i++) { - if (gid == gidlist->gids[i]) { - matched = true; - goto done; + if (gidlist == NULL) { + if ((gidlist = sudo_get_gidlist(pw, ENTRY_TYPE_ANY)) != NULL) { + for (i = 0; i < gidlist->ngids; i++) { + if (gid == gidlist->gids[i]) { + matched = true; + goto done; + } } } } diff --git a/plugins/sudoers/pwutil.h b/plugins/sudoers/pwutil.h index f1ade0056..1599ead3b 100644 --- a/plugins/sudoers/pwutil.h +++ b/plugins/sudoers/pwutil.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Todd C. Miller + * Copyright (c) 2010-2013, 2015-2017 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,7 +24,8 @@ */ struct cache_item { unsigned int refcnt; - char registry[16]; + unsigned int type; /* only used for gidlist */ + char registry[16]; /* AIX-specific, empty otherwise */ /* key */ union { uid_t uid; @@ -68,7 +69,7 @@ struct cache_item_gidlist { struct cache_item *sudo_make_gritem(gid_t gid, const char *group); struct cache_item *sudo_make_grlist_item(const struct passwd *pw, char * const *groups); -struct cache_item *sudo_make_gidlist_item(const struct passwd *pw, char * const *gids); +struct cache_item *sudo_make_gidlist_item(const struct passwd *pw, char * const *gids, unsigned int type); struct cache_item *sudo_make_pwitem(uid_t uid, const char *user); #endif /* SUDOERS_PWUTIL_H */ diff --git a/plugins/sudoers/pwutil_impl.c b/plugins/sudoers/pwutil_impl.c index 88e14d76f..1749a19b1 100644 --- a/plugins/sudoers/pwutil_impl.c +++ b/plugins/sudoers/pwutil_impl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998-2005, 2007-2015 + * Copyright (c) 1996, 1998-2005, 2007-2017 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -230,7 +230,8 @@ sudo_make_gritem(gid_t gid, const char *name) * elements. Fills in datum from user_gids or from getgrouplist(3). */ struct cache_item * -sudo_make_gidlist_item(const struct passwd *pw, char * const *unused1) +sudo_make_gidlist_item(const struct passwd *pw, char * const *unused1, + unsigned int type) { char *cp; size_t nsize, total; @@ -240,12 +241,15 @@ sudo_make_gidlist_item(const struct passwd *pw, char * const *unused1) int i, ngids; debug_decl(sudo_make_gidlist_item, SUDOERS_DEBUG_NSS) - if (pw == sudo_user.pw && sudo_user.gids != NULL) { + /* Don't use user_gids if the entry type says we must query the db. */ + if (type != ENTRY_TYPE_QUERIED && pw == sudo_user.pw && sudo_user.gids != NULL) { gids = user_gids; ngids = user_ngids; user_gids = NULL; user_ngids = 0; + type = ENTRY_TYPE_FRONTEND; } else { + type = ENTRY_TYPE_QUERIED; if (sudo_user.max_groups > 0) { ngids = sudo_user.max_groups; gids = reallocarray(NULL, ngids, sizeof(GETGROUPS_T)); @@ -320,6 +324,7 @@ sudo_make_gidlist_item(const struct passwd *pw, char * const *unused1) glitem->cache.k.name = cp; glitem->cache.d.gidlist = gidlist; glitem->cache.refcnt = 1; + glitem->cache.type = type; /* * Store group IDs. @@ -348,7 +353,7 @@ sudo_make_grlist_item(const struct passwd *pw, char * const *unused1) int i, groupname_len; debug_decl(sudo_make_grlist_item, SUDOERS_DEBUG_NSS) - gidlist = sudo_get_gidlist(pw); + gidlist = sudo_get_gidlist(pw, ENTRY_TYPE_ANY); if (gidlist == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "no gid list for use %s", pw->pw_name); diff --git a/plugins/sudoers/set_perms.c b/plugins/sudoers/set_perms.c index 20890a920..4fd794a0e 100644 --- a/plugins/sudoers/set_perms.c +++ b/plugins/sudoers/set_perms.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994-1996,1998-2015 Todd C. Miller + * Copyright (c) 1994-1996, 1998-2017 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1699,8 +1699,9 @@ runas_setgroups(void) debug_return_ptr(user_gid_list); } + /* Only use results from a group db query, not the front end. */ pw = runas_pw ? runas_pw : sudo_user.pw; - gidlist = sudo_get_gidlist(pw); + gidlist = sudo_get_gidlist(pw, ENTRY_TYPE_QUERIED); if (gidlist != NULL) { if (sudo_setgroups(gidlist->ngids, gidlist->gids) < 0) { sudo_gidlist_delref(gidlist); diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 10c1d6aa2..8bb5cab40 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1993-1996, 1998-2016 Todd C. Miller + * Copyright (c) 1993-1996, 1998-2017 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -732,7 +732,7 @@ init_vars(char * const envp[]) } } if (user_gid_list == NULL) - user_gid_list = sudo_get_gidlist(sudo_user.pw); + user_gid_list = sudo_get_gidlist(sudo_user.pw, ENTRY_TYPE_ANY); /* Store initialize permissions so we can restore them later. */ if (!set_perms(PERM_INITIAL)) diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 4caa857ea..062c8ee4d 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1993-1996, 1998-2005, 2007-2016 + * Copyright (c) 1993-1996, 1998-2005, 2007-2017 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -110,6 +110,13 @@ struct sudo_user { pid_t sid; }; +/* + * sudo_get_gidlist() type values + */ +#define ENTRY_TYPE_ANY 0x00 +#define ENTRY_TYPE_QUERIED 0x01 +#define ENTRY_TYPE_FRONTEND 0x02 + /* * sudo_user flag values */ @@ -303,7 +310,7 @@ __dso_public void sudo_gr_addref(struct group *); __dso_public void sudo_gr_delref(struct group *); bool user_in_group(const struct passwd *, const char *); struct group *sudo_fakegrnam(const char *); -struct gid_list *sudo_get_gidlist(const struct passwd *pw); +struct gid_list *sudo_get_gidlist(const struct passwd *pw, unsigned int type); struct group_list *sudo_get_grlist(const struct passwd *pw); struct passwd *sudo_fakepwnam(const char *, gid_t); struct passwd *sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home, const char *shell); @@ -318,7 +325,7 @@ void sudo_grlist_addref(struct group_list *); void sudo_grlist_delref(struct group_list *); void sudo_pw_addref(struct passwd *); void sudo_pw_delref(struct passwd *); -int sudo_set_gidlist(struct passwd *pw, char * const *gids); +int sudo_set_gidlist(struct passwd *pw, char * const *gids, unsigned int type); int sudo_set_grlist(struct passwd *pw, char * const *groups); void sudo_setspent(void); -- 2.40.0