From c72f94dad9639bc241890aad338ae0bea8eed84d Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Wed, 11 Oct 2000 05:25:32 +0000 Subject: Modified initgroups to provide a get groups a user is a member of functionality. This is much faster than inverting the group database. Added client side command for this to wbinfo. (This used to be commit e87b2d3d1fb84311d83d21a76900f994e4ff71dd) --- source3/nsswitch/wb_client.c | 138 +++++++++++++++++++++++++++++++++++++++++-- source3/nsswitch/wbinfo.c | 35 ++++++++++- 2 files changed, 166 insertions(+), 7 deletions(-) (limited to 'source3') diff --git a/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c index 67cc8c2208..f319531993 100644 --- a/source3/nsswitch/wb_client.c +++ b/source3/nsswitch/wb_client.c @@ -233,10 +233,136 @@ static BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid) return (result == NSS_STATUS_SUCCESS); } +/* Fetch the list of groups a user is a member of from winbindd. This is + used by winbind_initgroups and winbind_getgroups. */ +static int wb_getgroups(char *user, gid_t **groups) +{ + struct winbindd_request request; + struct winbindd_response response; + int result; + + /* Call winbindd */ + + fstrcpy(request.data.username, user); + + ZERO_STRUCT(response); + + result = winbindd_request(WINBINDD_INITGROUPS, &request, &response); + + if (result == NSS_STATUS_SUCCESS) { + + /* Return group list. Don't forget to free the group list + when finished. */ + + *groups = (gid_t *)response.extra_data; + return response.data.num_entries; + } + + return -1; +} + +/* Call winbindd to initialise group membership. This is necessary for + some systems (i.e RH5.2) that do not have an initgroups function as part + of the nss extension. In RH5.2 this is implemented using getgrent() + which can be amazingly inefficient as well as having problems with + username case. */ + +int winbind_initgroups(char *user, gid_t gid) +{ + gid_t *groups = NULL; + int result; + char *sep; + + /* Call normal initgroups if we are a local user */ + + sep = lp_winbind_separator(); + + if (!strchr(user, *sep)) { + return initgroups(user, gid); + } + + result = wb_getgroups(user, &groups); + + if (result != -1) { + int ngroups = result, i; + BOOL is_member = False; + + /* Check to see if the passed gid is already in the list */ + + for (i = 0; i < ngroups; i++) { + if (groups[i] == gid) { + is_member = True; + } + } + + /* Add group to list if necessary */ + + if (!is_member) { + groups = Realloc(groups, sizeof(gid_t) * ngroups + 1); + + if (!groups) { + errno = ENOMEM; + result = -1; + goto done; + } + + groups[ngroups] = gid; + ngroups++; + } + + /* Set the groups */ + + if (setgroups(ngroups, groups) == -1) { + errno = EPERM; + result = -1; + goto done; + } + } + + /* Free response data if necessary */ + + done: + safe_free(groups); + + return result; +} + +/* Return a list of groups the user is a member of. This function is + useful for large systems where inverting the group database would be too + time consuming. If size is zero, list is not modified and the total + number of groups for the user is returned. */ + +int winbind_getgroups(char *user, int size, gid_t *list) +{ + gid_t *groups = NULL; + int result, i; + + /* Fetch list of groups */ + + result = wb_getgroups(user, &groups); + + if (size == 0) goto done; + + if (result > size) { + result = -1; + errno = EINVAL; /* This is what getgroups() does */ + goto done; + } + + /* Copy list of groups across */ + + for (i = 0; i < result; i++) { + list[i] = groups[i]; + } + + done: + safe_free(groups); + return result; +} /***************************************************************** - *THE CANNONICAL* convert name to SID function. + *THE CANONICAL* convert name to SID function. Tries winbind first - then uses local lookup. *****************************************************************/ @@ -267,7 +393,7 @@ BOOL lookup_name(char *name, DOM_SID *psid, enum SID_NAME_USE *name_type) } /***************************************************************** - *THE CANNONICAL* convert SID to name function. + *THE CANONICAL* convert SID to name function. Tries winbind first - then uses local lookup. *****************************************************************/ @@ -289,7 +415,7 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE } /***************************************************************** - *THE CANNONICAL* convert uid_t to SID function. + *THE CANONICAL* convert uid_t to SID function. Tries winbind first - then uses local lookup. Returns SID pointer. *****************************************************************/ @@ -311,7 +437,7 @@ DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid) } /***************************************************************** - *THE CANNONICAL* convert gid_t to SID function. + *THE CANONICAL* convert gid_t to SID function. Tries winbind first - then uses local lookup. Returns SID pointer. *****************************************************************/ @@ -333,7 +459,7 @@ DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid) } /***************************************************************** - *THE CANNONICAL* convert SID to uid function. + *THE CANONICAL* convert SID to uid function. Tries winbind first - then uses local lookup. Returns True if this name is a user sid and the conversion was done correctly, False if not. @@ -387,7 +513,7 @@ BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype) } /***************************************************************** - *THE CANNONICAL* convert SID to gid function. + *THE CANONICAL* convert SID to gid function. Tries winbind first - then uses local lookup. Returns True if this name is a user sid and the conversion was done correctly, False if not. diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c index 40b53bf9d8..31de512267 100644 --- a/source3/nsswitch/wbinfo.c +++ b/source3/nsswitch/wbinfo.c @@ -32,6 +32,31 @@ enum nss_status winbindd_request(int req_type, struct winbindd_request *request, struct winbindd_response *response); +static BOOL wbinfo_get_usergroups(char *user) +{ + struct winbindd_request request; + struct winbindd_response response; + int result, i; + + ZERO_STRUCT(response); + + /* Send request */ + + fstrcpy(request.data.username, user); + + result = winbindd_request(WINBINDD_INITGROUPS, &request, &response); + + if (result != NSS_STATUS_SUCCESS) { + return False; + } + + for (i = 0; i < response.data.num_entries; i++) { + printf("%d\n", ((gid_t *)response.extra_data)[i]); + } + + return True; +} + /* List trusted domains */ static BOOL wbinfo_list_domains(void) @@ -288,6 +313,7 @@ static void usage(void) printf("\t-Y sid\tconverts sid to gid\n"); printf("\t-t\tcheck shared secret\n"); printf("\t-m\tlist trusted domains\n"); + printf("\t-r user\tget user groups\n"); } /* Main program */ @@ -327,7 +353,7 @@ int main(int argc, char **argv) return 1; } - while ((opt = getopt(argc, argv, "ugs:n:U:G:S:Y:tm")) != EOF) { + while ((opt = getopt(argc, argv, "ugs:n:U:G:S:Y:tmr:")) != EOF) { switch (opt) { case 'u': if (!print_domain_users()) { @@ -393,6 +419,13 @@ int main(int argc, char **argv) return 1; } break; + case 'r': + if (!wbinfo_get_usergroups(optarg)) { + printf("Could not get groups for user %s\n", + optarg); + return 1; + } + break; /* Invalid option */ -- cgit