summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/nsswitch/wb_client.c138
-rw-r--r--source3/nsswitch/wbinfo.c35
2 files changed, 166 insertions, 7 deletions
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 */