Commit sid<->[ug]id extensions to libnss_winbind.so on Linux, as well as a
authorVolker Lendecke <vlendec@samba.org>
Fri, 16 Jan 2004 13:11:01 +0000 (13:11 +0000)
committerVolker Lendecke <vlendec@samba.org>
Fri, 16 Jan 2004 13:11:01 +0000 (13:11 +0000)
factored-out nss_winbind.[ch]. I took tridge's public domain license comment
for the nss_winbind.[ch].

This is probably not the last word on that extension, but as it is quite
non-intrusive to the main samba code, I would like to give it a start.

Volker

examples/nss/nss_winbind.c [new file with mode: 0644]
examples/nss/nss_winbind.h [new file with mode: 0644]
examples/nss/wbtest.c
source/nsswitch/winbind_nss_linux.c

diff --git a/examples/nss/nss_winbind.c b/examples/nss/nss_winbind.c
new file mode 100644 (file)
index 0000000..968cc7a
--- /dev/null
@@ -0,0 +1,422 @@
+/* 
+   nss sample code for extended winbindd functionality
+
+   Copyright (C) Andrew Tridgell (tridge@samba.org)   
+
+   you are free to use this code in any way you see fit, including
+   without restriction, using this code in your own products. You do
+   not need to give any attribution.
+*/
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <nss.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "nss_winbind.h"
+
+/*
+  find a function in the nss library
+*/
+static void *find_fn(struct nss_state *nss, const char *name)
+{
+       void *res;
+       char *s = NULL;
+
+       asprintf(&s, "_nss_%s_%s", nss->nss_name, name);
+       if (!s) {
+               errno = ENOMEM;
+               return NULL;
+       }
+       res = dlsym(nss->dl_handle, s);
+       free(s);
+       if (!res) {
+               errno = ENOENT;
+               return NULL;
+       }
+       return res;
+}
+
+/*
+  establish a link to the nss library
+  Return 0 on success and -1 on error
+*/
+int nss_open(struct nss_state *nss, const char *nss_path)
+{
+       char *p;
+       p = strrchr(nss_path, '_');
+       if (!p) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       nss->nss_name = strdup(p+1);
+       p = strchr(nss->nss_name, '.');
+       if (p) *p = 0;
+
+       nss->dl_handle = dlopen(nss_path, RTLD_LAZY);
+       if (!nss->dl_handle) {
+               free(nss->nss_name);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  close and cleanup a nss state
+*/
+void nss_close(struct nss_state *nss)
+{
+       free(nss->nss_name);
+       dlclose(nss->dl_handle);
+}
+
+/*
+  make a getpwnam call. 
+  Return 0 on success and -1 on error
+*/
+int nss_getpwent(struct nss_state *nss, struct passwd *pwd)
+{
+       enum nss_status (*_nss_getpwent_r)(struct passwd *, char *, 
+                                          size_t , int *);
+       enum nss_status status;
+       int nss_errno = 0;
+
+       _nss_getpwent_r = find_fn(nss, "getpwent_r");
+
+       if (!_nss_getpwent_r) {
+               return -1;
+       }
+
+       status = _nss_getpwent_r(pwd, nss->pwnam_buf, sizeof(nss->pwnam_buf),
+                                &nss_errno);
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               return -1;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = nss_errno;
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  make a setpwent call. 
+  Return 0 on success and -1 on error
+*/
+int nss_setpwent(struct nss_state *nss)
+{
+       enum nss_status (*_nss_setpwent)(void) = find_fn(nss, "setpwent");
+       enum nss_status status;
+       if (!_nss_setpwent) {
+               return -1;
+       }
+       status = _nss_setpwent();
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = EINVAL;
+               return -1;
+       }
+       return 0;
+}
+
+/*
+  make a endpwent call. 
+  Return 0 on success and -1 on error
+*/
+int nss_endpwent(struct nss_state *nss)
+{
+       enum nss_status (*_nss_endpwent)(void) = find_fn(nss, "endpwent");
+       enum nss_status status;
+       if (!_nss_endpwent) {
+               return -1;
+       }
+       status = _nss_endpwent();
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = EINVAL;
+               return -1;
+       }
+       return 0;
+}
+
+
+/*
+  convert a name to a SID
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_nametosid(struct nss_state *nss, const char *name, char **sid)
+{
+       enum nss_status (*_nss_nametosid)(const char *, char **, char *,
+                                         size_t, int *);
+       enum nss_status status;
+       int nss_errno = 0;
+       char buf[200];
+
+       _nss_nametosid = find_fn(nss, "nametosid");
+
+       if (!_nss_nametosid) {
+               return -1;
+       }
+
+       status = _nss_nametosid(name, sid, buf, sizeof(buf), &nss_errno);
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               return -1;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = nss_errno;
+               return -1;
+       }
+
+       *sid = strdup(*sid);
+
+       return 0;
+}
+
+/*
+  convert a SID to a name
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_sidtoname(struct nss_state *nss, const char *sid, char **name)
+{
+       enum nss_status (*_nss_sidtoname)(const char *, char **, char *,
+                                         size_t, int *);
+       enum nss_status status;
+       int nss_errno = 0;
+       char buf[200];
+
+       _nss_sidtoname = find_fn(nss, "sidtoname");
+
+       if (!_nss_sidtoname) {
+               return -1;
+       }
+
+       status = _nss_sidtoname(sid, name, buf, sizeof(buf), &nss_errno);
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               return -1;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = nss_errno;
+               return -1;
+       }
+
+       *name = strdup(*name);
+
+       return 0;
+}
+
+/*
+  return a list of group SIDs for a user SID
+  the returned list is NULL terminated
+  Return 0 on success and -1 on error
+*/
+int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids)
+{
+       enum nss_status (*_nss_getusersids)(const char *, char **, int *,
+                                           char *, size_t, int *);
+       enum nss_status status;
+       int nss_errno = 0;
+       char *s;
+       int i, num_groups = 0;
+       unsigned bufsize = 10;
+       char *buf;
+
+       _nss_getusersids = find_fn(nss, "getusersids");
+
+       if (!_nss_getusersids) {
+               return -1;
+       }
+
+again:
+       buf = malloc(bufsize);
+       if (!buf) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       status = _nss_getusersids(user_sid, &s, &num_groups, buf, bufsize,
+                                 &nss_errno);
+
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               free(buf);
+               return -1;
+       }
+       
+       if (status == NSS_STATUS_TRYAGAIN) {
+               bufsize *= 2;
+               free(buf);
+               goto again;
+       }
+
+       if (status != NSS_STATUS_SUCCESS) {
+               free(buf);
+               errno = nss_errno;
+               return -1;
+       }
+
+       if (num_groups == 0) {
+               free(buf);
+               return 0;
+       }
+
+       *sids = (char **)malloc(sizeof(char *) * (num_groups+1));
+       if (! *sids) {
+               errno = ENOMEM;
+               free(buf);
+               return -1;
+       }
+
+       for (i=0;i<num_groups;i++) {
+               (*sids)[i] = strdup(s);
+               s += strlen(s) + 1;
+       }
+       (*sids)[i] = NULL;
+
+       free(buf);
+
+       return 0;
+}
+
+/*
+  convert a sid to a uid
+  Return 0 on success and -1 on error
+*/
+int nss_sidtouid(struct nss_state *nss, const char *sid, uid_t *uid)
+{
+       enum nss_status (*_nss_sidtouid)(const char*, uid_t *, int*);
+
+       enum nss_status status;
+       int nss_errno = 0;
+
+       _nss_sidtouid = find_fn(nss, "sidtouid");
+
+       if (!_nss_sidtouid) {
+               return -1;
+       }
+
+       status = _nss_sidtouid(sid, uid, &nss_errno);
+
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = nss_errno;
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  convert a sid to a gid
+  Return 0 on success and -1 on error
+*/
+int nss_sidtogid(struct nss_state *nss, const char *sid, gid_t *gid)
+{
+       enum nss_status (*_nss_sidtogid)(const char*, gid_t *, int*);
+
+       enum nss_status status;
+       int nss_errno = 0;
+
+       _nss_sidtogid = find_fn(nss, "sidtogid");
+
+       if (!_nss_sidtogid) {
+               return -1;
+       }
+
+       status = _nss_sidtogid(sid, gid, &nss_errno);
+
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = nss_errno;
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  convert a uid to a sid
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_uidtosid(struct nss_state *nss, uid_t uid, char **sid)
+{
+       enum nss_status (*_nss_uidtosid)(uid_t, char **, char *,
+                                        size_t, int *);
+       enum nss_status status;
+       int nss_errno = 0;
+       char buf[200];
+
+       _nss_uidtosid = find_fn(nss, "uidtosid");
+
+       if (!_nss_uidtosid) {
+               return -1;
+       }
+
+       status = _nss_uidtosid(uid, sid, buf, sizeof(buf), &nss_errno);
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               return -1;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = nss_errno;
+               return -1;
+       }
+
+       *sid = strdup(*sid);
+
+       return 0;
+}
+
+/*
+  convert a gid to a sid
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_gidtosid(struct nss_state *nss, gid_t gid, char **sid)
+{
+       enum nss_status (*_nss_gidtosid)(gid_t, char **, char *,
+                                        size_t, int *);
+       enum nss_status status;
+       int nss_errno = 0;
+       char buf[200];
+
+       _nss_gidtosid = find_fn(nss, "gidtosid");
+
+       if (!_nss_gidtosid) {
+               return -1;
+       }
+
+       status = _nss_gidtosid(gid, sid, buf, sizeof(buf), &nss_errno);
+       if (status == NSS_STATUS_NOTFOUND) {
+               errno = ENOENT;
+               return -1;
+       }
+       if (status != NSS_STATUS_SUCCESS) {
+               errno = nss_errno;
+               return -1;
+       }
+
+       *sid = strdup(*sid);
+
+       return 0;
+}
+
diff --git a/examples/nss/nss_winbind.h b/examples/nss/nss_winbind.h
new file mode 100644 (file)
index 0000000..5a124a5
--- /dev/null
@@ -0,0 +1,97 @@
+/* 
+   nss sample code for extended winbindd functionality
+
+   Copyright (C) Andrew Tridgell (tridge@samba.org)   
+   Copyright (C) Volker Lendecke (vl@samba.org)
+
+   you are free to use this code in any way you see fit, including
+   without restriction, using this code in your own products. You do
+   not need to give any attribution.
+*/
+
+#define _GNU_SOURCE
+
+#include <pwd.h>
+#include <grp.h>
+
+struct nss_state {
+       void *dl_handle;
+       char *nss_name;
+       char pwnam_buf[512];
+};
+
+/*
+  establish a link to the nss library
+  Return 0 on success and -1 on error
+*/
+int nss_open(struct nss_state *nss, const char *nss_path);
+
+/*
+  close and cleanup a nss state
+*/
+void nss_close(struct nss_state *nss);
+
+/*
+  make a getpwnam call. 
+  Return 0 on success and -1 on error
+*/
+int nss_getpwent(struct nss_state *nss, struct passwd *pwd);
+
+/*
+  make a setpwent call. 
+  Return 0 on success and -1 on error
+*/
+int nss_setpwent(struct nss_state *nss);
+
+/*
+  make a endpwent call. 
+  Return 0 on success and -1 on error
+*/
+int nss_endpwent(struct nss_state *nss);
+
+/*
+  convert a name to a SID
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_nametosid(struct nss_state *nss, const char *name, char **sid);
+
+/*
+  convert a SID to a name
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_sidtoname(struct nss_state *nss, const char *sid, char **name);
+
+/*
+  return a list of group SIDs for a user SID
+  the returned list is NULL terminated
+  Return 0 on success and -1 on error
+*/
+int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids);
+
+/*
+  convert a sid to a uid
+  Return 0 on success and -1 on error
+*/
+int nss_sidtouid(struct nss_state *nss, const char *sid, uid_t *uid);
+
+/*
+  convert a sid to a gid
+  Return 0 on success and -1 on error
+*/
+int nss_sidtogid(struct nss_state *nss, const char *sid, gid_t *gid);
+
+/*
+  convert a uid to a sid
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_uidtosid(struct nss_state *nss, uid_t uid, char **sid);
+
+/*
+  convert a gid to a sid
+  caller frees
+  Return 0 on success and -1 on error
+*/
+int nss_gidtosid(struct nss_state *nss, gid_t gid, char **sid);
index fc8f575ef061151faf56c084f53470f40eba0fe4..14265bd54c1ad57f9bb78dc917ac2e06c672615f 100644 (file)
@@ -11,7 +11,7 @@
 /*
    compile like this:
 
-      cc -o wbtest wbtest.c -ldl
+      cc -o wbtest wbtest.c nss_winbind.c -ldl
 
    and run like this:
 
 #include <string.h>
 #include <sys/types.h>
 
-typedef enum nss_status NSS_STATUS;
-
-struct nss_state {
-       void *dl_handle;
-       char *nss_name;
-       char pwnam_buf[512];
-};
-
-/*
-  find a function in the nss library
-*/
-static void *find_fn(struct nss_state *nss, const char *name)
-{
-       void *res;
-       char *s = NULL;
-
-       asprintf(&s, "_nss_%s_%s", nss->nss_name, name);
-       if (!s) {
-               errno = ENOMEM;
-               return NULL;
-       }
-       res = dlsym(nss->dl_handle, s);
-       free(s);
-       if (!res) {
-               errno = ENOENT;
-               return NULL;
-       }
-       return res;
-}
-
-/*
-  establish a link to the nss library
-  Return 0 on success and -1 on error
-*/
-int nss_open(struct nss_state *nss, const char *nss_path)
-{
-       char *p;
-       p = strrchr(nss_path, '_');
-       if (!p) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       nss->nss_name = strdup(p+1);
-       p = strchr(nss->nss_name, '.');
-       if (p) *p = 0;
-
-       nss->dl_handle = dlopen(nss_path, RTLD_LAZY);
-       if (!nss->dl_handle) {
-               free(nss->nss_name);
-               return -1;
-       }
-
-       return 0;
-}
-
-/*
-  close and cleanup a nss state
-*/
-void nss_close(struct nss_state *nss)
-{
-       free(nss->nss_name);
-       dlclose(nss->dl_handle);
-}
-
-/*
-  make a getpwnam call. 
-  Return 0 on success and -1 on error
-*/
-int nss_getpwent(struct nss_state *nss, struct passwd *pwd)
-{
-       NSS_STATUS (*_nss_getpwent_r)(struct passwd *, char *, 
-                                     size_t , int *) = find_fn(nss, "getpwent_r");
-       NSS_STATUS status;
-       int nss_errno = 0;
-
-       if (!_nss_getpwent_r) {
-               return -1;
-       }
-
-       status = _nss_getpwent_r(pwd, nss->pwnam_buf, sizeof(nss->pwnam_buf), &nss_errno);
-       if (status == NSS_STATUS_NOTFOUND) {
-               errno = ENOENT;
-               return -1;
-       }
-       if (status != NSS_STATUS_SUCCESS) {
-               errno = nss_errno;
-               return -1;
-       }
-
-       return 0;
-}
-
-/*
-  make a setpwent call. 
-  Return 0 on success and -1 on error
-*/
-int nss_setpwent(struct nss_state *nss)
-{
-       NSS_STATUS (*_nss_setpwent)(void) = find_fn(nss, "setpwent");
-       NSS_STATUS status;
-       if (!_nss_setpwent) {
-               return -1;
-       }
-       status = _nss_setpwent();
-       if (status != NSS_STATUS_SUCCESS) {
-               errno = EINVAL;
-               return -1;
-       }
-       return 0;
-}
-
-/*
-  make a endpwent call. 
-  Return 0 on success and -1 on error
-*/
-int nss_endpwent(struct nss_state *nss)
-{
-       NSS_STATUS (*_nss_endpwent)(void) = find_fn(nss, "endpwent");
-       NSS_STATUS status;
-       if (!_nss_endpwent) {
-               return -1;
-       }
-       status = _nss_endpwent();
-       if (status != NSS_STATUS_SUCCESS) {
-               errno = EINVAL;
-               return -1;
-       }
-       return 0;
-}
-
-
-/*
-  convert a name to a SID
-  caller frees
-  Return 0 on success and -1 on error
-*/
-int nss_nametosid(struct nss_state *nss, const char *name, char **sid)
-{
-       NSS_STATUS (*_nss_nametosid)(const char *, char **, char *, size_t, int *) = 
-               find_fn(nss, "nametosid");
-       NSS_STATUS status;
-       int nss_errno = 0;
-       char buf[200];
-
-       if (!_nss_nametosid) {
-               return -1;
-       }
-
-       status = _nss_nametosid(name, sid, buf, sizeof(buf), &nss_errno);
-       if (status == NSS_STATUS_NOTFOUND) {
-               errno = ENOENT;
-               return -1;
-       }
-       if (status != NSS_STATUS_SUCCESS) {
-               errno = nss_errno;
-               return -1;
-       }
-
-       *sid = strdup(*sid);
-
-       return 0;
-}
-
-/*
-  convert a SID to a name
-  caller frees
-  Return 0 on success and -1 on error
-*/
-int nss_sidtoname(struct nss_state *nss, char *sid, char **name)
-{
-       NSS_STATUS (*_nss_sidtoname)(const char *, char **, char *, size_t, int *) = 
-               find_fn(nss, "sidtoname");
-       NSS_STATUS status;
-       int nss_errno = 0;
-       char buf[200];
-
-       if (!_nss_sidtoname) {
-               return -1;
-       }
-
-       status = _nss_sidtoname(sid, name, buf, sizeof(buf), &nss_errno);
-       if (status == NSS_STATUS_NOTFOUND) {
-               errno = ENOENT;
-               return -1;
-       }
-       if (status != NSS_STATUS_SUCCESS) {
-               errno = nss_errno;
-               return -1;
-       }
-
-       *name = strdup(*name);
-
-       return 0;
-}
-
-/*
-  return a list of group SIDs for a user SID
-  the returned list is NULL terminated
-  Return 0 on success and -1 on error
-*/
-int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids)
-{
-       NSS_STATUS (*_nss_getusersids)(const char *, char **, int *, char *, size_t, int *) = 
-               find_fn(nss, "getusersids");
-       NSS_STATUS status;
-       int nss_errno = 0;
-       char *s;
-       int i, num_groups = 0;
-       unsigned bufsize = 10;
-       char *buf;
-
-       if (!_nss_getusersids) {
-               return -1;
-       }
-
-again:
-       buf = malloc(bufsize);
-       if (!buf) {
-               errno = ENOMEM;
-               return -1;
-       }
-
-       status = _nss_getusersids(user_sid, &s, &num_groups, buf, bufsize, &nss_errno);
-       if (status == NSS_STATUS_NOTFOUND) {
-               errno = ENOENT;
-               free(buf);
-               return -1;
-       }
-       
-       if (status == NSS_STATUS_TRYAGAIN) {
-               bufsize *= 2;
-               free(buf);
-               goto again;
-       }
-
-       if (status != NSS_STATUS_SUCCESS) {
-               free(buf);
-               errno = nss_errno;
-               return -1;
-       }
-
-       if (num_groups == 0) {
-               free(buf);
-               return 0;
-       }
-
-       *sids = (char **)malloc(sizeof(char *) * (num_groups+1));
-       if (! *sids) {
-               errno = ENOMEM;
-               free(buf);
-               return -1;
-       }
-
-       for (i=0;i<num_groups;i++) {
-               (*sids)[i] = strdup(s);
-               s += strlen(s) + 1;
-       }
-       (*sids)[i] = NULL;
-
-       free(buf);
-
-       return 0;
-}
-
+#include "nss_winbind.h"
 
 static int nss_test_users(struct nss_state *nss)
 {
index ac4a861ff1b8f643ea3c4e9c54f0f5923026f987..362047f62b10c83938ba5b18eaec765e35b086a6 100644 (file)
@@ -1009,3 +1009,141 @@ failed:
        free_response(&response);
        return ret;
 }
+
+/* map a sid to a uid */
+NSS_STATUS
+_nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop)
+{
+       NSS_STATUS ret;
+       struct winbindd_response response;
+       struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+       fprintf(stderr, "[%5d]: sidtouid %s\n", getpid(), sid);
+#endif
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
+       request.data.sid[sizeof(request.data.sid) - 1] = '\0';
+
+       ret = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
+       if (ret != NSS_STATUS_SUCCESS) {
+               *errnop = errno = EINVAL;
+               goto failed;
+       }
+
+       *uid = response.data.uid;
+
+failed:
+       return ret;
+}
+
+/* map a sid to a gid */
+NSS_STATUS
+_nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop)
+{
+       NSS_STATUS ret;
+       struct winbindd_response response;
+       struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+       fprintf(stderr, "[%5d]: sidtogid %s\n", getpid(), sid);
+#endif
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
+       request.data.sid[sizeof(request.data.sid) - 1] = '\0';
+
+       ret = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
+       if (ret != NSS_STATUS_SUCCESS) {
+               *errnop = errno = EINVAL;
+               goto failed;
+       }
+
+       *gid = response.data.gid;
+
+failed:
+       return ret;
+}
+
+/* map a uid to a SID string */
+NSS_STATUS
+_nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
+                     size_t buflen, int *errnop)
+{
+       NSS_STATUS ret;
+       struct winbindd_response response;
+       struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+       fprintf(stderr, "[%5d]: uidtosid %s\n", getpid(), name);
+#endif
+
+       ZERO_STRUCT(response);
+       ZERO_STRUCT(request);
+
+       request.data.uid = uid;
+
+       ret = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
+       if (ret != NSS_STATUS_SUCCESS) {
+               *errnop = errno = EINVAL;
+               goto failed;
+       }
+
+       if (buflen < strlen(response.data.sid.sid)+1) {
+               ret = NSS_STATUS_TRYAGAIN;
+               *errnop = errno = ERANGE;
+               goto failed;
+       }
+
+       *errnop = errno = 0;
+       *sid = buffer;
+       strcpy(*sid, response.data.sid.sid);
+
+failed:
+       free_response(&response);
+       return ret;
+}
+
+/* map a gid to a SID string */
+NSS_STATUS
+_nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
+                     size_t buflen, int *errnop)
+{
+       NSS_STATUS ret;
+       struct winbindd_response response;
+       struct winbindd_request request;
+
+#ifdef DEBUG_NSS
+       fprintf(stderr, "[%5d]: gidtosid %s\n", getpid(), name);
+#endif
+
+       ZERO_STRUCT(response);
+       ZERO_STRUCT(request);
+
+       request.data.gid = gid;
+
+       ret = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
+       if (ret != NSS_STATUS_SUCCESS) {
+               *errnop = errno = EINVAL;
+               goto failed;
+       }
+
+       if (buflen < strlen(response.data.sid.sid)+1) {
+               ret = NSS_STATUS_TRYAGAIN;
+               *errnop = errno = ERANGE;
+               goto failed;
+       }
+
+       *errnop = errno = 0;
+       *sid = buffer;
+       strcpy(*sid, response.data.sid.sid);
+
+failed:
+       free_response(&response);
+       return ret;
+}