Modified initgroups to provide a get groups a user is a member of
authorTim Potter <tpot@samba.org>
Wed, 11 Oct 2000 05:25:32 +0000 (05:25 +0000)
committerTim Potter <tpot@samba.org>
Wed, 11 Oct 2000 05:25:32 +0000 (05:25 +0000)
functionality.  This is much faster than inverting the group database.

Added client side command for this to wbinfo.

source/nsswitch/wb_client.c
source/nsswitch/wbinfo.c

index 67cc8c2208cbe1820a7876a7cea9960c81ae411b..f319531993727f690942b0b634487a64e85cdaaf 100644 (file)
@@ -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.
index 40b53bf9d8cf040110648a36026ccf3a182da294..31de512267646418a482790a96a36fac640013b3 100644 (file)
@@ -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 */