X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fmgetgroups.c;h=76474c21b9936e6138e401026b67e4c2582f3701;hb=6bd173f7ffcd7f02646ad1086035e8ba9cbddcba;hp=7a61db41d900661e3542ea650429a6b3c94405ab;hpb=3e035a5d686888e5eba0b622dac459b65cdd99d3;p=gnulib.git diff --git a/lib/mgetgroups.c b/lib/mgetgroups.c index 7a61db41d..76474c21b 100644 --- a/lib/mgetgroups.c +++ b/lib/mgetgroups.c @@ -1,6 +1,6 @@ /* mgetgroups.c -- return a list of the groups a user or current process is in - Copyright (C) 2007-2009 Free Software Foundation, Inc. + Copyright (C) 2007-2010 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,7 +53,8 @@ realloc_groupbuf (gid_t *g, size_t num) NULL, store the supplementary groups of the current process, and GID should be -1 or the effective group ID (getegid). Upon failure, don't modify *GROUPS, set errno, and return -1. Otherwise, return - the number of groups. */ + the number of groups. The resulting list may contain duplicates, + but adjacent members will be distinct. */ int mgetgroups (char const *username, gid_t gid, gid_t **groups) @@ -140,7 +141,8 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups) ng = (username ? getugroups (max_n_groups, g, username, gid) - : getgroups (max_n_groups, g + (gid != (gid_t) -1))); + : getgroups (max_n_groups - (gid != (gid_t) -1), + g + (gid != (gid_t) -1))); if (ng < 0) { @@ -157,6 +159,38 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups) ng++; } *groups = g; + + /* Reduce the number of duplicates. On some systems, getgroups + returns the effective gid twice: once as the first element, and + once in its position within the supplementary groups. On other + systems, getgroups does not return the effective gid at all, + which is why we provide a GID argument. Meanwhile, the GID + argument, if provided, is typically any member of the + supplementary groups, and not necessarily the effective gid. So, + the most likely duplicates are the first element with an + arbitrary other element, or pair-wise duplication between the + first and second elements returned by getgroups. It is possible + that this O(n) pass will not remove all duplicates, but it is not + worth the effort to slow down to an O(n log n) algorithm that + sorts the array in place, nor the extra memory needed for + duplicate removal via an O(n) hash-table. Hence, this function + is only documented as guaranteeing no pair-wise duplicates, + rather than returning the minimal set. */ + if (1 < ng) + { + gid_t first = *g; + gid_t *next; + gid_t *groups_end = g + ng; + + for (next = g + 1; next < groups_end; next++) + { + if (*next == first || *next == *g) + ng--; + else + *++g = *next; + } + } + return ng; }