[PATCH] winbind nested groups fix?

Matthijs Kooijman m.kooijman at student.utwente.nl
Mon Jun 5 15:24:01 GMT 2006


Hey,

apparently, my message to this list I sent a week or so back didn't make it
here. Weird. Anyway, it said that from a discussion on IRC, we've concluded
that fixing the getgrent interface of winbind is not the way to go. Winbind
has a working getgroups interface that handles nested groups correctly. This
interface is at least by linux through the "initgroups_dyn" nss call.

I have now implemented a new nss call: "getgroupmembership". This performs a
similar function as the "initgroups_dyn" function, with two differences:
initgroups_dyn does dynamic (re)allocation of memory, while getgroupmembership
does not (this is not really needed, since at the libc side it is just a
wrapped in getgrouplist, which does not do memory (re)allocation either), and
getgroupmembership filters out duplicate groups, so different nss backend can
be called sequentially without introducing duplicate groups.

This function should work ok on NetBSD, where the "getgroupmembership"
function was initially created, though I'm not sure if it gets
registered there. It runs on FreeBSD with a patched libc (I'm still working on
cleaning up this patch to submit it to FreeBSD). It does not influence any
other OS (including unpatched FreeBSD).

I've attached the patch, but there are still a few question marks here. First,
the orginal NetBSD code uses a macro "MIN", which is defined somewhere. This
macro works ok when used inside libc on FreeBSD, but is apparently not defined
in any file included by samba. I've fixed this by manually defining it, but
would this be the right way? I could also find a file in which it is defined,
but it seems those are "regex/regcomp.c"...

Secondly, I'm not sure where to put this code. Both functions are now in
winbind_nss_freebsd.c, which seems okay since they are both mainly for
FreeBSD. On the other hand, they could also be used for NetBSD, but I'm not
sure how samba NetBSD works right now? 

Anyway, any comments on this code?

Gr.

Matthijs
-------------- next part --------------
--- work/samba-3.0.22/source/nsswitch/winbind_nss_freebsd.c	Fri Feb 25 18:59:30 2005
+++ work.patched/samba-3.0.22/source/nsswitch/winbind_nss_freebsd.c	Mon Jun  5 17:22:41 2006
@@ -4,8 +4,7 @@
    AIX loadable authentication module, providing identification 
    routines against Samba winbind/Windows NT Domain
 
-   Copyright (C) Aaron Collins 2003
-   
+   Copyright (C) Aaron Collins 2003 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
@@ -23,6 +22,7 @@
 */
 
 #include "winbind_client.h"
+#include <sys/param.h> /* For MIN() */
 
 /* Make sure that the module gets registered needed by freebsd 5.1 */
 
@@ -34,6 +34,7 @@
     size_t, int *);
 extern enum nss_status _nss_winbind_setgrent(void);
 extern enum nss_status _nss_winbind_endgrent(void);
+enum nss_status _nss_winbind_getgroupmembership(void *retval, void *mdata, va_list ap);
 
 extern enum nss_status _nss_winbind_getpwent_r(struct passwd *, char *, size_t,
     int *);
@@ -62,6 +63,7 @@
 { NSDB_GROUP, "getgrent_r", __nss_compat_getgrent_r, _nss_winbind_getgrent_r },
 { NSDB_GROUP, "endgrent",   __nss_compat_setgrent,   _nss_winbind_setgrent },
 { NSDB_GROUP, "setgrent",   __nss_compat_endgrent,   _nss_winbind_endgrent },
+{ NSDB_GROUP, "getgroupmembership",   _nss_winbind_getgroupmembership,   NULL },
 
 { NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, _nss_winbind_getpwnam_r },
 { NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, _nss_winbind_getpwuid_r },
@@ -79,3 +81,80 @@
         *unreg = NULL;
         return (methods);
 }
+
+
+/*
+ * __gr_addgid
+ *      Add gid to the groups array (of maxgrp size) at the position
+ *      indicated by *groupc, unless it already exists or *groupc is
+ *      past &groups[maxgrp].
+ *      Returns 1 upon success (including duplicate suppression), 0 otherwise.
+ * 
+ *      Taken from NetBSD's libc.
+ */
+static int
+__gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *groupc)
+{
+        int     ret, dupc;
+
+                                                /* skip duplicates */
+        for (dupc = 0; dupc < MINX(maxgrp, *groupc); dupc++) {
+                if (groups[dupc] == gid)
+                        return 1;
+        }
+
+        ret = 1;
+        if (*groupc < maxgrp)                   /* add this gid */
+                groups[*groupc] = gid;
+        else
+                ret = 0;
+        (*groupc)++;
+        return ret;
+}
+
+enum nss_status
+_nss_winbind_getgroupmembership(void *retval, void *mdata, va_list ap)
+{
+	enum nss_status ret;
+	int *err = va_arg(ap, int *);
+	const char *user = va_arg(ap, const char *);
+	gid_t group = va_arg(ap, gid_t);
+	gid_t *groups = va_arg(ap, gid_t *);
+	int limit = va_arg(ap, int);
+	int *size = va_arg(ap, int*);
+	int i;
+
+	struct winbindd_request request;
+	struct winbindd_response response;
+
+#ifdef DEBUG_NSS
+	fprintf(stderr, "[%5d]: getgroupmembership %s (%d)\n", getpid(),
+		user, group);
+#endif
+
+	ZERO_STRUCT(request);
+	ZERO_STRUCT(response);
+
+	strncpy(request.data.username, user, sizeof(request.data.username) - 1);
+
+	ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
+
+	if (ret == NSS_STATUS_SUCCESS) {
+		int num_gids = response.data.num_entries;
+		gid_t *gid_list = (gid_t *)response.extra_data;
+
+		/* Copy group list to client */
+
+		for (i = 0; i < num_gids; i++)
+			if (! __gr_addgid(gid_list[i], groups, limit, size))
+				*err = -1; 
+				/* The groups don't fit. Still, we keep trying
+				 * to add them so we can set size to the
+				 * correct value (with duplicate supression).
+				 */
+		ret = NSS_STATUS_NOTFOUND;
+	}
+	
+	return __nss_compat_result[ret]; /* Translate this to FreeBSD */
+}
+


More information about the samba-technical mailing list