]> granicus.if.org Git - sudo/commitdiff
When running a command as the invoking user we cannot use the gid
authorTodd C. Miller <Todd.Miller@sudo.ws>
Tue, 28 Nov 2017 16:48:43 +0000 (09:48 -0700)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Tue, 28 Nov 2017 16:48:43 +0000 (09:48 -0700)
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
plugins/sudoers/policy.c
plugins/sudoers/pwutil.c
plugins/sudoers/pwutil.h
plugins/sudoers/pwutil_impl.c
plugins/sudoers/set_perms.c
plugins/sudoers/sudoers.c
plugins/sudoers/sudoers.h

index 07d9366053c9bb14a618bece64dbcb827e355881..9a5156a65f058417a35fea048163e71a36a54418 100644 (file)
@@ -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;
index 3afc33e3c11ac0ce3ecab124f75cf54bc20179a2..d0a17ae8572ba050f5466f09b39bae8fed9f25a3 100644 (file)
@@ -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 +
index 34bbe92f10a40cac2161785ac72977d66590df3b..2e817702c4b081cac5caeef69608991441a1843a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2005, 2007-2016
+ * Copyright (c) 1996, 1998-2005, 2007-2017
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * 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;
+                   }
                }
            }
        }
index f1ade0056d116606e48fb8fd033c8fbb8327b3e6..1599ead3b0ded9bfc70937963378b1456535f3da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2010-2013, 2015-2017 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
@@ -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 */
index 88e14d76f8ebdfac471157e2a11647000a9d778e..1749a19b1ebe1841b16a197447450d2cf311b676 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2005, 2007-2015
+ * Copyright (c) 1996, 1998-2005, 2007-2017
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * 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);
index 20890a920ffdeaa89d867837c18179d196b7e15f..4fd794a0eef5e86b515b8c6e69613b2c8c320b93 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994-1996,1998-2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1994-1996, 1998-2017 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
@@ -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);
index 10c1d6aa28dde1fbb8005aa7864a72016fb1b1e9..8bb5cab4046900eeca06fe65a2b1b8cf652ea1db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1993-1996, 1998-2016 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1993-1996, 1998-2017 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
@@ -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))
index 4caa857ea40acc3d8e987a3f94c1e8dee6db1487..062c8ee4dd7d9e4a7be24c78e97ede2d90881538 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1993-1996, 1998-2005, 2007-2016
+ * Copyright (c) 1993-1996, 1998-2005, 2007-2017
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * 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);