}
-/* Compute the list of supplementary groups associated with @uid, and
- * including @gid in the list (unless it is -1), storing a malloc'd
- * result into @list. Return the size of the list on success, or -1
- * on failure with error reported and errno set. May not be called
- * between fork and exec. */
+/* Compute the list of primary and supplementary groups associated
+ * with @uid, and including @gid in the list (unless it is -1),
+ * storing a malloc'd result into @list. Return the size of the list
+ * on success, or -1 on failure with error reported and errno set. May
+ * not be called between fork and exec. */
int
virGetGroupList(uid_t uid, gid_t gid, gid_t **list)
{
int ret = -1;
char *user = NULL;
+ gid_t primary;
*list = NULL;
if (uid == (uid_t)-1)
return 0;
- if (virGetUserEnt(uid, &user,
- gid == (gid_t)-1 ? &gid : NULL, NULL) < 0)
+ if (virGetUserEnt(uid, &user, &primary, NULL) < 0)
return -1;
- ret = mgetgroups(user, gid, list);
- if (ret < 0)
+ ret = mgetgroups(user, primary, list);
+ if (ret < 0) {
virReportSystemError(errno,
_("cannot get group list for '%s'"), user);
+ goto cleanup;
+ }
+
+ if (gid != (gid_t)-1) {
+ size_t n = ret;
+
+ for (size_t i = 0; i < ret; i++) {
+ if ((*list)[i] == gid)
+ goto cleanup;
+ }
+ if (VIR_APPEND_ELEMENT(*list, n, gid) < 0) {
+ ret = -1;
+ VIR_FREE(*list);
+ goto cleanup;
+ } else {
+ ret = n;
+ }
+ }
+
+cleanup:
VIR_FREE(user);
return ret;
}