diff options
Diffstat (limited to 'examples/nss/nss_winbind.c')
-rw-r--r-- | examples/nss/nss_winbind.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/examples/nss/nss_winbind.c b/examples/nss/nss_winbind.c new file mode 100644 index 0000000000..968cc7addd --- /dev/null +++ b/examples/nss/nss_winbind.c @@ -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; +} + |