From f2af7a6ffcead3ffd1f2ae9fac5fc682c6c8c7ac Mon Sep 17 00:00:00 2001 From: Michael Meffie Date: Wed, 10 Mar 2010 08:48:38 -0600 Subject: [PATCH] pts mem -expandgroups option Improve support for supergroups in the pts membership command with a new option called -expandgroups. This option will recursively show the complete membership of users and groups. The expanded members of a group are all the users which are members of all of the group's sub-groups. The expanded groups of a user are all the groups which are supergroups of the users's groups. Change-Id: I811a4e5e73632e5e205fe10f3f3a36a98464d49e Reviewed-on: http://gerrit.openafs.org/1601 Reviewed-by: Andrew Deason Tested-by: Andrew Deason Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- doc/man-pages/pod1/pts_membership.pod | 26 +++- src/ptserver/pts.c | 9 +- src/ptserver/ptuser.c | 232 ++++++++++++++++++++++++++++++++++ src/ptserver/ptuser.h | 1 + 4 files changed, 261 insertions(+), 7 deletions(-) diff --git a/doc/man-pages/pod1/pts_membership.pod b/doc/man-pages/pod1/pts_membership.pod index d6680fe..a4f0fa1 100644 --- a/doc/man-pages/pod1/pts_membership.pod +++ b/doc/man-pages/pod1/pts_membership.pod @@ -8,20 +8,19 @@ pts_membership - Displays the membership list for a user or group
B S<<< B<-nameorid> >+ >>> - [B<-supergroups>] - S<<< [B<-cell> >] >>> [B<-localauth>] [B<-noauth>] - [B<-force>] [B<-help>] + [B<-supergroups>] [B<-expandgroups>] S<<< [B<-cell> >] >>> + [B<-localauth>] [B<-noauth>] [B<-force>] [B<-help>] B S<<< B<-na> >+ >>> - [B<-s>] S<<< [B<-c> >] >>> + [B<-s>] [B<-ex>] S<<< [B<-c> >] >>> [B<-no>] [B<-l>] [B<-f>] [B<-h>] B S<<< B<-na> >+ >>> - [B<-s>] S<<< [B<-c> >] >>> + [B<-s>] [B<-ex>] S<<< [B<-c> >] >>> [B<-no>] [B<-l>] [B<-f>] [B<-h>] B S<<< B<-na> >+ >>> - [B<-s>] S<<< [B<-c> >] >>> + [B<-s>] [B<-ex>] S<<< [B<-c> >] >>> [B<-no>] [B<-l>] [B<-f>] [B<-h>] =for html @@ -61,6 +60,21 @@ argument belongs, in addition to user and machine members. Group membership may be nested when B is compilied with the SUPERGROUPS option enabled. +=item B<-expandgroups> + +Instead of listing only the groups in which the user or machine is a direct +member, list every group in which the user or machine belongs, including +membership due to nested groups, for each user or machine specified by +the B<-nameorid> argument. + +Instead of listing groups which are members of a group, list every user and +machine which is a member of a group, including the users and machines which +are members due to nested groups, for each group specified by the B<-nameorid> +argument. + +Group membership may be nested when B is compilied with the +SUPERGROUPS option enabled. + =item B<-cell> > Names the cell in which to run the command. For more details, see diff --git a/src/ptserver/pts.c b/src/ptserver/pts.c index 5108b1e..26058ec 100644 --- a/src/ptserver/pts.c +++ b/src/ptserver/pts.c @@ -608,7 +608,13 @@ ListMembership(struct cmd_syndesc *as, void *arock) list.namelist_val = 0; list.namelist_len = 0; - code = pr_IDListMembers(ids.idlist_val[i], &list); + if (as->parms[2].items) { /* -expandgroups */ + code = pr_IDListExpandedMembers(id, &list); + if (!code) + printf("Expanded "); + } else { + code = pr_IDListMembers(id, &list); + } if (code) { afs_com_err(whoami, code, "; unable to get membership of %s (id: %d)", name, id); @@ -1163,6 +1169,7 @@ main(int argc, char **argv) "list membership of a user or group"); cmd_AddParm(ts, "-nameorid", CMD_LIST, 0, "user or group name or id"); cmd_AddParm(ts, "-supergroups", CMD_FLAG, CMD_OPTIONAL, "show supergroups"); + cmd_AddParm(ts, "-expandgroups", CMD_FLAG, CMD_OPTIONAL, "expand super and sub group membership"); add_std_args(ts); cmd_CreateAlias(ts, "groups"); diff --git a/src/ptserver/ptuser.c b/src/ptserver/ptuser.c index 9e1b915..12054ab 100644 --- a/src/ptserver/ptuser.c +++ b/src/ptserver/ptuser.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "ptclient.h" #include "ptuser.h" #include "pterror.h" @@ -57,6 +58,143 @@ static afs_int32 lastLevel; /* security level pruclient, if any */ static char *whoami = "libprot"; + +#define ID_HASH_SIZE 1024 +#define ID_STACK_SIZE 1024 + +/** + * Hash table chain of user and group ids. + */ +struct idchain { + struct idchain *next; + afs_int32 id; +}; + +/** + * Hash table of user and group ids. + */ +struct idhash { + afs_uint32 userEntries; /**< number of user id entries hashed */ + afs_uint32 groupEntries; /**< number of group id entries hashed */ + struct idchain *hash[ID_HASH_SIZE]; +}; + +/** + * Allocate a new id hash table. + */ +static afs_int32 +AllocateIdHash(struct idhash **aidhash) +{ + struct idhash *idhash; + + idhash = (struct idhash *)malloc(sizeof(struct idhash)); + if (!idhash) { + return ENOMEM; + } + memset((void *)idhash, 0, sizeof(struct idhash)); + *aidhash = idhash; + return 0; +} + +/** + * Free the id hash. + */ +static void +FreeIdHash(struct idhash *idhash) +{ + int index; + struct idchain *chain; + struct idchain *next; + + for (index = 0; index < ID_HASH_SIZE; index++) { + for (chain = idhash->hash[index]; chain; chain = next) { + next = chain->next; + free(chain); + } + } + free(idhash); +} + +/** + * Indicate if group/user id is already hashed, and + * if not insert it. + * + * @returns whether id is present + * @retval >0 id is already present in the hash + * @retval 0 id was not found and was inserted into the hash + * @retval <0 error encountered + */ +static afs_int32 +FindId(struct idhash *idhash, afs_int32 id) +{ + afs_int32 index; + struct idchain *chain; + struct idchain *newChain; + + index = abs(id) % ID_HASH_SIZE; + for (chain = idhash->hash[index]; chain; chain = chain->next) { + if (chain->id == id) { + return 1; + } + } + + /* Insert this id but return not found. */ + newChain = (struct idchain *)malloc(sizeof(struct idchain)); + if (!newChain) { + return ENOMEM; + } else { + newChain->id = id; + newChain->next = idhash->hash[index]; + idhash->hash[index] = newChain; + if (id < 0) { + idhash->groupEntries++; + } else { + idhash->userEntries++; + } + } + return 0; +} + +/** + * Create an idlist from the ids in the hash. + */ +static afs_int32 +CreateIdList(struct idhash *idhash, idlist * alist, afs_int32 select) +{ + struct idchain *chain; + afs_int32 entries = 0; + int index; + int i; + + if (select & PRGROUPS) { + entries += idhash->groupEntries; + } + if (select & PRUSERS) { + entries += idhash->userEntries; + } + + alist->idlist_len = entries; + alist->idlist_val = (afs_int32 *) malloc(sizeof(afs_int32) * entries); + if (!alist->idlist_val) { + return ENOMEM; + } + + for (i = 0, index = 0; index < ID_HASH_SIZE; index++) { + for (chain = idhash->hash[index]; chain; chain = chain->next) { + if (chain->id < 0) { + if (select & PRGROUPS) { + alist->idlist_val[i++] = chain->id; + } + } else { + if (select & PRUSERS) { + alist->idlist_val[i++] = chain->id; + } + } + } + } + return 0; +} + afs_int32 pr_Initialize(IN afs_int32 secLevel, IN const char *confDir, IN char *cell) { @@ -569,6 +707,100 @@ pr_IDListMembers(afs_int32 gid, namelist *lnames) } int +pr_IDListExpandedMembers(afs_int32 aid, namelist * lnames) +{ + afs_int32 code; + afs_int32 gid; + idlist lids; + prlist alist; + afs_int32 over; + struct idhash *members = NULL; + afs_int32 *stack = NULL; + afs_int32 maxstack = ID_STACK_SIZE; + int n = 0; /* number of ids stacked */ + int i; + int firstpass = 1; + + code = AllocateIdHash(&members); + if (code) { + return code; + } + stack = (afs_int32 *) malloc(sizeof(afs_int32) * maxstack); + if (!stack) { + code = ENOMEM; + goto done; + } + + stack[n++] = aid; + while (n) { + gid = stack[--n]; /* pop next group id */ + alist.prlist_len = 0; + alist.prlist_val = NULL; + if (firstpass || aid < 0) { + firstpass = 0; + code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over); + } else { + code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over); + if (code == RXGEN_OPCODE) { + alist.prlist_len = 0; + alist.prlist_val = NULL; + code = 0; /* server does not support supergroups. */ + } + } + if (code) + goto done; + if (over) { + fprintf(stderr, + "membership list for id %d exceeds display limit\n", gid); + } + for (i = 0; i < alist.prlist_len; i++) { + afs_int32 found; + afs_int32 id; + + id = alist.prlist_val[i]; + found = FindId(members, id); + if (found < 0) { + code = found; + xdr_free((xdrproc_t) xdr_prlist, &alist); + goto done; + } + if (found == 0 && id < 0) { + if (n == maxstack) { /* need more stack space */ + afs_int32 *tmp; + maxstack += n; + tmp = + (afs_int32 *) realloc(stack, + maxstack * sizeof(afs_int32)); + if (!tmp) { + code = ENOMEM; + xdr_free((xdrproc_t) xdr_prlist, &alist); + goto done; + } + stack = tmp; + } + stack[n++] = id; /* push group id */ + } + } + xdr_free((xdrproc_t) xdr_prlist, &alist); + } + + code = CreateIdList(members, &lids, (aid < 0 ? PRUSERS : PRGROUPS)); + if (code) { + goto done; + } + code = pr_IdToName(&lids, lnames); + if (lids.idlist_len) + free(lids.idlist_val); + + done: + if (stack) + free(stack); + if (members) + FreeIdHash(members); + return code; +} + +int pr_ListEntry(afs_int32 id, struct prcheckentry *aentry) { register afs_int32 code; diff --git a/src/ptserver/ptuser.h b/src/ptserver/ptuser.h index e597110..850f3f9 100644 --- a/src/ptserver/ptuser.h +++ b/src/ptserver/ptuser.h @@ -53,5 +53,6 @@ extern afs_int32 pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers); extern int pr_ListSuperGroups(afs_int32 gid, namelist *lnames); +extern int pr_IDListExpandedMembers(afs_int32 gid, namelist *lnames); #endif /* PTUSER_H */ -- 1.9.4