1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00

r19456: Add an example application for ldb using the tdb backend

This commit is contained in:
Simo Sorce 2006-10-22 21:18:43 +00:00 committed by Gerald (Jerry) Carter
parent 2b770885cd
commit 778198f279
6 changed files with 1598 additions and 3 deletions

View File

@ -18,7 +18,7 @@ SLAPD = @SLAPD@
EXTRA_OBJ=@EXTRA_OBJ@
TESTS=test-tdb.sh @TESTS@
CFLAGS=-I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \
CFLAGS=-g -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \
@POPT_CFLAGS@ -I@tallocdir@ -I@tdbdir@/include -I@libreplacedir@ \
-DLIBDIR=\"$(libdir)\" -DSHLIBEXT=\"@SHLIBEXT@\" -DUSE_MMAP=1 @CFLAGS@
@ -41,6 +41,10 @@ MODULES_OBJ=$(MODDIR)/operational.o $(MODDIR)/schema.o $(MODDIR)/rdn_name.o \
$(MODDIR)/objectclass.o \
$(MODDIR)/paged_results.o $(MODDIR)/sort.o $(MODDIR)/asq.o
NSSDIR=nssldb
NSS_OBJ= $(NSSDIR)/ldb-nss.o $(NSSDIR)/ldb-pwd.o $(NSSDIR)/ldb-grp.o
NSS_LIB = lib/libnss_ldb.so.2
OBJS = $(MODULES_OBJ) $(COMMON_OBJ) $(LDB_TDB_OBJ) @TDBOBJ@ @TALLOCOBJ@ @POPTOBJ@ @LIBREPLACEOBJ@ $(EXTRA_OBJ)
LDB_LIB = lib/libldb.a
@ -53,7 +57,7 @@ EXAMPLES = examples/ldbreader examples/ldifreader
DIRS = lib bin common ldb_tdb ldb_ldap ldb_sqlite3 modules tools examples
all: showflags dirs $(OBJS) $(LDB_LIB) $(BINS) $(EXAMPLES) manpages
all: showflags dirs $(OBJS) $(LDB_LIB) $(BINS) $(EXAMPLES) manpages $(NSS_LIB)
showflags:
@echo 'ldb will be compiled with flags:'
@ -72,6 +76,9 @@ lib/libldb.a: $(OBJS)
ar -rv $@ $(OBJS)
@-ranlib $@
lib/libnss_ldb.so.2: $(NSS_OBJ) $(LIBS)
$(CC) -shared -Wl,-soname,libnss_ldb.so.2 -o lib/libnss_ldb.so.2 $(NSS_OBJ) $(OBJS) $(LIB_FLAGS)
bin/ldbadd: tools/ldbadd.o tools/cmdline.o $(LIBS)
$(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o $(LIB_FLAGS)
@ -112,7 +119,7 @@ doxygen:
clean:
rm -f *.o */*.o *.gcov */*.gc?? tdbtest.ldb*
rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LIB)
rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LIB) $(NSS_LIB)
rm -f man/*.1 man/*.3 man/*.html
rm -f $(EXAMPLES)
rm -rf apidocs/

View File

@ -0,0 +1,427 @@
/*
LDB nsswitch module
Copyright (C) Simo Sorce 2006
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
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "ldb-nss.h"
extern struct _ldb_nss_context *_ldb_nss_ctx;
const char *_ldb_nss_gr_attrs[] = {
"cn",
"userPassword",
"gidNumber",
NULL
};
const char *_ldb_nss_mem_attrs[] = {
"uid",
NULL
};
#define _NSS_LDB_ENOMEM(amem) \
do { \
if ( ! amem) { \
errno = ENOMEM; \
talloc_free(memctx); \
return NSS_STATUS_UNAVAIL; \
} \
} while(0)
/* This setgrent, getgrent, endgrent is not very efficient */
NSS_STATUS _nss_ldb_setgrent(void)
{
int ret;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
_ldb_nss_ctx->gr_cur = 0;
if (_ldb_nss_ctx->gr_res != NULL) {
talloc_free(_ldb_nss_ctx->gr_res);
_ldb_nss_ctx->gr_res = NULL;
}
ret = ldb_search(_ldb_nss_ctx->ldb,
_ldb_nss_ctx->base,
LDB_SCOPE_SUBTREE,
_LDB_NSS_GRENT_FILTER,
_ldb_nss_gr_attrs,
&_ldb_nss_ctx->gr_res);
if (ret != LDB_SUCCESS) {
return NSS_STATUS_UNAVAIL;
}
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _nss_ldb_endgrent(void)
{
int ret;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
_ldb_nss_ctx->gr_cur = 0;
if (_ldb_nss_ctx->gr_res) {
talloc_free(_ldb_nss_ctx->gr_res);
_ldb_nss_ctx->gr_res = NULL;
}
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _nss_ldb_getgrent_r(struct group *result_buf, char *buffer, size_t buflen, int *errnop)
{
int ret;
struct ldb_result *res;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
*errnop = 0;
if (_ldb_nss_ctx->gr_cur >= _ldb_nss_ctx->gr_res->count) {
/* already returned all entries */
return NSS_STATUS_NOTFOUND;
}
res = talloc_zero(_ldb_nss_ctx->gr_res, struct ldb_result);
if ( ! res) {
errno = *errnop = ENOMEM;
_ldb_nss_ctx->gr_cur++; /* skip this entry */
return NSS_STATUS_UNAVAIL;
}
ret = _ldb_nss_group_request(&res,
_ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur]->dn,
_ldb_nss_mem_attrs,
"member");
if (ret != NSS_STATUS_SUCCESS) {
*errnop = errno;
talloc_free(res);
_ldb_nss_ctx->gr_cur++; /* skip this entry */
return ret;
}
ret = _ldb_nss_fill_group(result_buf,
buffer,
buflen,
errnop,
_ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur],
res);
talloc_free(res);
if (ret != NSS_STATUS_SUCCESS) {
if (ret != NSS_STATUS_TRYAGAIN) {
_ldb_nss_ctx->gr_cur++; /* skip this entry */
}
return ret;
}
/* this entry is ok, increment counter to nex entry */
_ldb_nss_ctx->gr_cur++;
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _nss_ldb_getgrnam_r(const char *name, struct group *result_buf, char *buffer, size_t buflen, int *errnop)
{
int ret;
char *filter;
TALLOC_CTX *ctx;
struct ldb_result *gr_res;
struct ldb_result *mem_res;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
ctx = talloc_new(_ldb_nss_ctx->ldb);
if ( ! ctx) {
*errnop = errno = ENOMEM;
return NSS_STATUS_UNAVAIL;
}
/* build the filter for this uid */
filter = talloc_asprintf(ctx, _LDB_NSS_GRNAM_FILTER, name);
if (filter == NULL) {
/* this is a fatal error */
*errnop = errno = ENOMEM;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* search the entry */
ret = ldb_search(_ldb_nss_ctx->ldb,
_ldb_nss_ctx->base,
LDB_SCOPE_SUBTREE,
filter,
_ldb_nss_gr_attrs,
&gr_res);
if (ret != LDB_SUCCESS) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
talloc_steal(ctx, gr_res);
/* if none found return */
if (gr_res->count == 0) {
*errnop = errno = ENOENT;
ret = NSS_STATUS_NOTFOUND;
goto done;
}
if (gr_res->count != 1) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
mem_res = talloc_zero(ctx, struct ldb_result);
if ( ! mem_res) {
errno = *errnop = ENOMEM;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
ret = _ldb_nss_group_request(&mem_res,
gr_res->msgs[0]->dn,
_ldb_nss_mem_attrs,
"member");
if (ret != NSS_STATUS_SUCCESS) {
*errnop = errno;
goto done;
}
ret = _ldb_nss_fill_group(result_buf,
buffer,
buflen,
errnop,
gr_res->msgs[0],
mem_res);
if (ret != NSS_STATUS_SUCCESS) {
goto done;
}
ret = NSS_STATUS_SUCCESS;
done:
talloc_free(ctx);
return ret;
}
NSS_STATUS _nss_ldb_getgrgid_r(gid_t gid, struct group *result_buf, char *buffer, size_t buflen, int *errnop)
{
int ret;
char *filter;
TALLOC_CTX *ctx;
struct ldb_result *gr_res;
struct ldb_result *mem_res;
if (gid == 0) { /* we don't serve root gid by policy */
*errnop = errno = ENOENT;
return NSS_STATUS_NOTFOUND;
}
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
ctx = talloc_new(_ldb_nss_ctx->ldb);
if ( ! ctx) {
*errnop = errno = ENOMEM;
return NSS_STATUS_UNAVAIL;
}
/* build the filter for this uid */
filter = talloc_asprintf(ctx, _LDB_NSS_GRGID_FILTER, gid);
if (filter == NULL) {
/* this is a fatal error */
*errnop = errno = ENOMEM;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* search the entry */
ret = ldb_search(_ldb_nss_ctx->ldb,
_ldb_nss_ctx->base,
LDB_SCOPE_SUBTREE,
filter,
_ldb_nss_gr_attrs,
&gr_res);
if (ret != LDB_SUCCESS) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
talloc_steal(ctx, gr_res);
/* if none found return */
if (gr_res->count == 0) {
*errnop = errno = ENOENT;
ret = NSS_STATUS_NOTFOUND;
goto done;
}
if (gr_res->count != 1) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
mem_res = talloc_zero(ctx, struct ldb_result);
if ( ! mem_res) {
errno = *errnop = ENOMEM;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
ret = _ldb_nss_group_request(&mem_res,
gr_res->msgs[0]->dn,
_ldb_nss_mem_attrs,
"member");
if (ret != NSS_STATUS_SUCCESS) {
*errnop = errno;
goto done;
}
ret = _ldb_nss_fill_group(result_buf,
buffer,
buflen,
errnop,
gr_res->msgs[0],
mem_res);
if (ret != NSS_STATUS_SUCCESS) {
goto done;
}
ret = NSS_STATUS_SUCCESS;
done:
talloc_free(ctx);
return ret;
}
NSS_STATUS _nss_ldb_initgroups_dyn(const char *user, gid_t group, long int *start, long int *size, gid_t **groups, long int limit, int *errnop)
{
int ret;
char *filter;
const char * attrs[] = { "uidNumber", "gidNumber", NULL };
struct ldb_result *uid_res;
struct ldb_result *mem_res;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
mem_res = talloc_zero(_ldb_nss_ctx, struct ldb_result);
if ( ! mem_res) {
errno = *errnop = ENOMEM;
return NSS_STATUS_UNAVAIL;
}
/* build the filter for this name */
filter = talloc_asprintf(mem_res, _LDB_NSS_PWNAM_FILTER, user);
if (filter == NULL) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* search the entry */
ret = ldb_search(_ldb_nss_ctx->ldb,
_ldb_nss_ctx->base,
LDB_SCOPE_SUBTREE,
filter,
attrs,
&uid_res);
if (ret != LDB_SUCCESS) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
talloc_steal(mem_res, uid_res);
/* if none found return */
if (uid_res->count == 0) {
*errnop = errno = ENOENT;
ret = NSS_STATUS_NOTFOUND;
goto done;
}
if (uid_res->count != 1) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
ret = _ldb_nss_group_request(&mem_res,
uid_res->msgs[0]->dn,
attrs,
"memberOf");
if (ret != NSS_STATUS_SUCCESS) {
*errnop = errno;
goto done;
}
ret = _ldb_nss_fill_initgr(group,
limit,
start,
size,
groups,
errnop,
mem_res);
if (ret != NSS_STATUS_SUCCESS) {
goto done;
}
ret = NSS_STATUS_SUCCESS;
done:
talloc_free(mem_res);
return ret;
}

View File

@ -0,0 +1,401 @@
/*
LDB nsswitch module
Copyright (C) Simo Sorce 2006
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
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "ldb-nss.h"
struct _ldb_nss_context *_ldb_nss_ctx = NULL;
NSS_STATUS _ldb_nss_init(void)
{
int ret;
pid_t mypid = getpid();
if (_ldb_nss_ctx != NULL) {
if (_ldb_nss_ctx->pid == mypid) {
/* already initialized */
return NSS_STATUS_SUCCESS;
} else {
/* we are in a forked child now, reinitialize */
talloc_free(_ldb_nss_ctx);
_ldb_nss_ctx = NULL;
}
}
_ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid);
if (_ldb_nss_ctx == NULL) {
return NSS_STATUS_UNAVAIL;
}
_ldb_nss_ctx->pid = mypid;
ret = ldb_global_init();
if (ret != 0) {
goto failed;
}
_ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx);
if (_ldb_nss_ctx->ldb == NULL) {
goto failed;
}
ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL);
if (ret != LDB_SUCCESS) {
goto failed;
}
_ldb_nss_ctx->base = ldb_dn_explode(_ldb_nss_ctx, _LDB_NSS_BASEDN);
if (_ldb_nss_ctx->base == NULL) {
goto failed;
}
_ldb_nss_ctx->pw_cur = 0;
_ldb_nss_ctx->pw_res = NULL;
_ldb_nss_ctx->gr_cur = 0;
_ldb_nss_ctx->gr_res = NULL;
return NSS_STATUS_SUCCESS;
failed:
/* talloc_free(_ldb_nss_ctx); */
_ldb_nss_ctx = NULL;
return NSS_STATUS_UNAVAIL;
}
NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
char *buffer,
int buflen,
int *errnop,
struct ldb_message *msg)
{
int len;
int bufpos;
const char *tmp;
bufpos = 0;
/* get username */
tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL);
if (tmp == NULL) {
/* this is a fatal error */
*errnop = errno = ENOENT;
return NSS_STATUS_UNAVAIL;
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->pw_name = &buffer[bufpos];
bufpos += len;
/* get userPassword */
tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL);
if (tmp == NULL) {
tmp = "LDB";
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->pw_passwd = &buffer[bufpos];
bufpos += len;
/* this backend never serves an uid 0 user */
result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0);
if (result->pw_uid == 0) {
/* this is a fatal error */
*errnop = errno = ENOENT;
return NSS_STATUS_UNAVAIL;
}
result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0);
if (result->pw_gid == 0) {
/* this is a fatal error */
*errnop = errno = ENOENT;
return NSS_STATUS_UNAVAIL;
}
/* get gecos */
tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL);
if (tmp == NULL) {
tmp = "";
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->pw_gecos = &buffer[bufpos];
bufpos += len;
/* get homeDirectory */
tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL);
if (tmp == NULL) {
tmp = "";
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->pw_dir = &buffer[bufpos];
bufpos += len;
/* get shell */
tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL);
if (tmp == NULL) {
tmp = "";
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->pw_shell = &buffer[bufpos];
bufpos += len;
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _ldb_nss_fill_group(struct group *result,
char *buffer,
int buflen,
int *errnop,
struct ldb_message *group,
struct ldb_result *members)
{
const char *tmp;
size_t len;
size_t bufpos;
size_t lsize;
int i;
bufpos = 0;
/* get group name */
tmp = ldb_msg_find_attr_as_string(group, "cn", NULL);
if (tmp == NULL) {
/* this is a fatal error */
*errnop = errno = ENOENT;
return NSS_STATUS_UNAVAIL;
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->gr_name = &buffer[bufpos];
bufpos += len;
/* get userPassword */
tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL);
if (tmp == NULL) {
tmp = "LDB";
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->gr_passwd = &buffer[bufpos];
bufpos += len;
result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0);
if (result->gr_gid == 0) {
/* this is a fatal error */
*errnop = errno = ENOENT;
return NSS_STATUS_UNAVAIL;
}
/* check if there is enough memory for the list of pointers */
lsize = (members->count + 1) * sizeof(char *);
/* align buffer on pointer boundary */
bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*)));
if ((buflen - bufpos) < lsize) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
result->gr_mem = (char **)&buffer[bufpos];
bufpos += lsize;
for (i = 0; i < members->count; i++) {
tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL);
if (tmp == NULL) {
/* this is a fatal error */
*errnop = errno = ENOENT;
return NSS_STATUS_UNAVAIL;
}
len = strlen(tmp)+1;
if (bufpos + len > buflen) {
/* buffer too small */
*errnop = errno = EAGAIN;
return NSS_STATUS_TRYAGAIN;
}
memcpy(&buffer[bufpos], tmp, len);
result->gr_mem[i] = &buffer[bufpos];
bufpos += len;
}
result->gr_mem[i] = NULL;
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
long int limit,
long int *start,
long int *size,
gid_t **groups,
int *errnop,
struct ldb_result *grlist)
{
NSS_STATUS ret;
int i;
for (i = 0; i < grlist->count; i++) {
if (limit && (*start > limit)) {
/* TODO: warn no all groups were reported */
*errnop = 0;
ret = NSS_STATUS_SUCCESS;
goto done;
}
if (*start == *size) {
/* buffer full, enlarge it */
long int gs;
gid_t *gm;
gs = (*size) + 32;
if (limit && (gs > limit)) {
gs = limit;
}
gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t));
if ( ! gm) {
*errnop = ENOMEM;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
*groups = gm;
*size = gs;
}
(*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0);
if ((*groups)[*start] == 0 || (*groups)[*start] == group) {
/* skip root group or primary group */
continue;
}
(*start)++;
}
*errnop = 0;
ret = NSS_STATUS_SUCCESS;
done:
return ret;
}
#define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0)
NSS_STATUS _ldb_nss_group_request(struct ldb_result **res,
struct ldb_dn *group_dn,
const char * const *attrs,
const char *mattr)
{
struct ldb_control **ctrls;
struct ldb_control *ctrl;
struct ldb_asq_control *asqc;
struct ldb_request *req;
int ret;
ctrls = talloc_array(*res, struct ldb_control *, 2);
_LDB_NSS_ALLOC_CHECK(ctrls);
ctrl = talloc(ctrls, struct ldb_control);
_LDB_NSS_ALLOC_CHECK(ctrl);
asqc = talloc(ctrl, struct ldb_asq_control);
_LDB_NSS_ALLOC_CHECK(asqc);
asqc->source_attribute = talloc_strdup(asqc, mattr);
_LDB_NSS_ALLOC_CHECK(asqc->source_attribute);
asqc->request = 1;
asqc->src_attr_len = strlen(asqc->source_attribute);
ctrl->oid = LDB_CONTROL_ASQ_OID;
ctrl->critical = 1;
ctrl->data = asqc;
ctrls[0] = ctrl;
ctrls[1] = NULL;
ret = ldb_build_search_req(
&req,
_ldb_nss_ctx->ldb,
*res,
group_dn,
LDB_SCOPE_BASE,
"(objectClass=*)",
attrs,
ctrls,
res,
ldb_search_default_callback);
if (ret != LDB_SUCCESS) {
errno = ENOENT;
return NSS_STATUS_UNAVAIL;
}
ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0);
ret = ldb_request(_ldb_nss_ctx->ldb, req);
if (ret == LDB_SUCCESS) {
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
} else {
talloc_free(req);
return NSS_STATUS_UNAVAIL;
}
talloc_free(req);
return NSS_STATUS_SUCCESS;
}

View File

@ -0,0 +1,86 @@
/*
LDB nsswitch module
Copyright (C) Simo Sorce 2006
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
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#ifndef _LDB_NSS
#define _LDB_NSS
#include "includes.h"
#include "ldb/include/includes.h"
#include <nss.h>
#include <pwd.h>
#include <grp.h>
#define _LDB_NSS_URL "etc/users.ldb"
#define _LDB_NSS_BASEDN "CN=Users,CN=System"
#define _LDB_NSS_PWENT_FILTER "(&(objectClass=posixAccount)(!(uidNumber=0))(!(gidNumber=0)))"
#define _LDB_NSS_PWUID_FILTER "(&(objectClass=posixAccount)(uidNumber=%d)(!(gidNumber=0)))"
#define _LDB_NSS_PWNAM_FILTER "(&(objectClass=posixAccount)(uid=%s)(!(uidNumber=0))(!(gidNumber=0)))"
#define _LDB_NSS_GRENT_FILTER "(&(objectClass=posixGroup)(!(gidNumber=0)))"
#define _LDB_NSS_GRGID_FILTER "(&(objectClass=posixGroup)(gidNumber=%d)))"
#define _LDB_NSS_GRNAM_FILTER "(&(objectClass=posixGroup)(cn=%s)(!(gidNumber=0)))"
typedef enum nss_status NSS_STATUS;
struct _ldb_nss_context {
pid_t pid;
struct ldb_context *ldb;
const struct ldb_dn *base;
int pw_cur;
struct ldb_result *pw_res;
int gr_cur;
struct ldb_result *gr_res;
};
NSS_STATUS _ldb_nss_init(void);
NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
char *buffer,
int buflen,
int *errnop,
struct ldb_message *msg);
NSS_STATUS _ldb_nss_fill_group(struct group *result,
char *buffer,
int buflen,
int *errnop,
struct ldb_message *group,
struct ldb_result *members);
NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
long int limit,
long int *start,
long int *size,
gid_t **groups,
int *errnop,
struct ldb_result *grlist);
NSS_STATUS _ldb_nss_group_request(struct ldb_result **res,
struct ldb_dn *group_dn,
const char * const *attrs,
const char *mattr);
#endif /* _LDB_NSS */

View File

@ -0,0 +1,241 @@
/*
LDB nsswitch module
Copyright (C) Simo Sorce 2006
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
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "ldb-nss.h"
extern struct _ldb_nss_context *_ldb_nss_ctx;
const char *_ldb_nss_pw_attrs[] = {
"uid",
"userPassword",
"uidNumber",
"gidNumber",
"gecos",
"homeDirectory",
"loginShell",
NULL
};
NSS_STATUS _nss_ldb_setpwent(void)
{
int ret;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
_ldb_nss_ctx->pw_cur = 0;
if (_ldb_nss_ctx->pw_res != NULL) {
talloc_free(_ldb_nss_ctx->pw_res);
_ldb_nss_ctx->pw_res = NULL;
}
ret = ldb_search(_ldb_nss_ctx->ldb,
_ldb_nss_ctx->base,
LDB_SCOPE_SUBTREE,
_LDB_NSS_PWENT_FILTER,
_ldb_nss_pw_attrs,
&_ldb_nss_ctx->pw_res);
if (ret != LDB_SUCCESS) {
return NSS_STATUS_UNAVAIL;
}
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _nss_ldb_endpwent(void)
{
int ret;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
_ldb_nss_ctx->pw_cur = 0;
if (_ldb_nss_ctx->pw_res) {
talloc_free(_ldb_nss_ctx->pw_res);
_ldb_nss_ctx->pw_res = NULL;
}
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _nss_ldb_getpwent_r(struct passwd *result_buf,
char *buffer,
int buflen,
int *errnop)
{
int ret;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
*errnop = 0;
if (_ldb_nss_ctx->pw_cur >= _ldb_nss_ctx->pw_res->count) {
/* already returned all entries */
return NSS_STATUS_NOTFOUND;
}
ret = _ldb_nss_fill_passwd(result_buf,
buffer,
buflen,
errnop,
_ldb_nss_ctx->pw_res->msgs[_ldb_nss_ctx->pw_cur]);
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
_ldb_nss_ctx->pw_cur++;
return NSS_STATUS_SUCCESS;
}
NSS_STATUS _nss_ldb_getpwuid_r(uid_t uid, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop)
{
int ret;
char *filter;
struct ldb_result *res;
if (uid == 0) { /* we don't serve root uid by policy */
*errnop = errno = ENOENT;
return NSS_STATUS_NOTFOUND;
}
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
/* build the filter for this uid */
filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWUID_FILTER, uid);
if (filter == NULL) {
/* this is a fatal error */
*errnop = errno = ENOMEM;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* search the entry */
ret = ldb_search(_ldb_nss_ctx->ldb,
_ldb_nss_ctx->base,
LDB_SCOPE_SUBTREE,
filter,
_ldb_nss_pw_attrs,
&res);
if (ret != LDB_SUCCESS) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* if none found return */
if (res->count == 0) {
*errnop = errno = ENOENT;
ret = NSS_STATUS_NOTFOUND;
goto done;
}
if (res->count != 1) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* fill in the passwd struct */
ret = _ldb_nss_fill_passwd(result_buf,
buffer,
buflen,
errnop,
res->msgs[0]);
done:
talloc_free(filter);
talloc_free(res);
return ret;
}
NSS_STATUS _nss_ldb_getpwnam_r(const char *name, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop)
{
int ret;
char *filter;
struct ldb_result *res;
ret = _ldb_nss_init();
if (ret != NSS_STATUS_SUCCESS) {
return ret;
}
/* build the filter for this name */
filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWNAM_FILTER, name);
if (filter == NULL) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* search the entry */
ret = ldb_search(_ldb_nss_ctx->ldb,
_ldb_nss_ctx->base,
LDB_SCOPE_SUBTREE,
filter,
_ldb_nss_pw_attrs,
&res);
if (ret != LDB_SUCCESS) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* if none found return */
if (res->count == 0) {
*errnop = errno = ENOENT;
ret = NSS_STATUS_NOTFOUND;
goto done;
}
if (res->count != 1) {
/* this is a fatal error */
*errnop = errno = ENOENT;
ret = NSS_STATUS_UNAVAIL;
goto done;
}
/* fill in the passwd struct */
ret = _ldb_nss_fill_passwd(result_buf,
buffer,
buflen,
errnop,
res->msgs[0]);
done:
talloc_free(filter);
talloc_free(res);
return ret;
}

View File

@ -0,0 +1,433 @@
/*
Unix SMB/CIFS implementation.
nss tester
Copyright (C) Andrew Tridgell 2001-2004
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <nss.h>
#include <dlfcn.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include <sys/types.h>
typedef enum nss_status NSS_STATUS;
static const char *so_path = "lib/libnss_ldb.so.2";
static char *nss_name;
static int nss_errno;
static NSS_STATUS last_error;
static int total_errors;
static void *find_fn(const char *name)
{
char s[1024];
static void *h;
void *res;
snprintf(s,sizeof(s), "_nss_%s_%s", nss_name, name);
if (!h) {
h = dlopen(so_path, RTLD_LAZY);
}
if (!h) {
printf("Can't open shared library %s : %s\n", so_path, dlerror());
exit(1);
}
res = dlsym(h, s);
if (!res) {
printf("Can't find function %s : %s\n", s, dlerror());
return NULL;
}
return res;
}
static void report_nss_error(const char *who, NSS_STATUS status)
{
last_error = status;
total_errors++;
printf("ERROR %s: NSS_STATUS=%d %d (nss_errno=%d)\n",
who, status, NSS_STATUS_SUCCESS, nss_errno);
}
static struct passwd *nss_getpwent(void)
{
NSS_STATUS (*_nss_getpwent_r)(struct passwd *, char *,
size_t , int *) = find_fn("getpwent_r");
static struct passwd pwd;
static char buf[1000];
NSS_STATUS status;
status = _nss_getpwent_r(&pwd, buf, sizeof(buf), &nss_errno);
if (status == NSS_STATUS_NOTFOUND) {
return NULL;
}
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("getpwent", status);
return NULL;
}
return &pwd;
}
static struct passwd *nss_getpwnam(const char *name)
{
NSS_STATUS (*_nss_getpwnam_r)(const char *, struct passwd *, char *,
size_t , int *) = find_fn("getpwnam_r");
static struct passwd pwd;
static char buf[1000];
NSS_STATUS status;
status = _nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &nss_errno);
if (status == NSS_STATUS_NOTFOUND) {
return NULL;
}
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("getpwnam", status);
return NULL;
}
return &pwd;
}
static struct passwd *nss_getpwuid(uid_t uid)
{
NSS_STATUS (*_nss_getpwuid_r)(uid_t , struct passwd *, char *,
size_t , int *) = find_fn("getpwuid_r");
static struct passwd pwd;
static char buf[1000];
NSS_STATUS status;
status = _nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &nss_errno);
if (status == NSS_STATUS_NOTFOUND) {
return NULL;
}
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("getpwuid", status);
return NULL;
}
return &pwd;
}
static void nss_setpwent(void)
{
NSS_STATUS (*_nss_setpwent)(void) = find_fn("setpwent");
NSS_STATUS status;
status = _nss_setpwent();
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("setpwent", status);
}
}
static void nss_endpwent(void)
{
NSS_STATUS (*_nss_endpwent)(void) = find_fn("endpwent");
NSS_STATUS status;
status = _nss_endpwent();
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("endpwent", status);
}
}
static struct group *nss_getgrent(void)
{
NSS_STATUS (*_nss_getgrent_r)(struct group *, char *,
size_t , int *) = find_fn("getgrent_r");
static struct group grp;
static char *buf;
static int buflen = 1024;
NSS_STATUS status;
if (!buf) buf = malloc(buflen);
again:
status = _nss_getgrent_r(&grp, buf, buflen, &nss_errno);
if (status == NSS_STATUS_TRYAGAIN) {
buflen *= 2;
buf = realloc(buf, buflen);
goto again;
}
if (status == NSS_STATUS_NOTFOUND) {
return NULL;
}
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("getgrent", status);
return NULL;
}
return &grp;
}
static struct group *nss_getgrnam(const char *name)
{
NSS_STATUS (*_nss_getgrnam_r)(const char *, struct group *, char *,
size_t , int *) = find_fn("getgrnam_r");
static struct group grp;
static char *buf;
static int buflen = 1000;
NSS_STATUS status;
if (!buf) buf = malloc(buflen);
again:
status = _nss_getgrnam_r(name, &grp, buf, buflen, &nss_errno);
if (status == NSS_STATUS_TRYAGAIN) {
buflen *= 2;
buf = realloc(buf, buflen);
goto again;
}
if (status == NSS_STATUS_NOTFOUND) {
return NULL;
}
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("getgrnam", status);
return NULL;
}
return &grp;
}
static struct group *nss_getgrgid(gid_t gid)
{
NSS_STATUS (*_nss_getgrgid_r)(gid_t , struct group *, char *,
size_t , int *) = find_fn("getgrgid_r");
static struct group grp;
static char *buf;
static int buflen = 1000;
NSS_STATUS status;
if (!buf) buf = malloc(buflen);
again:
status = _nss_getgrgid_r(gid, &grp, buf, buflen, &nss_errno);
if (status == NSS_STATUS_TRYAGAIN) {
buflen *= 2;
buf = realloc(buf, buflen);
goto again;
}
if (status == NSS_STATUS_NOTFOUND) {
return NULL;
}
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("getgrgid", status);
return NULL;
}
return &grp;
}
static void nss_setgrent(void)
{
NSS_STATUS (*_nss_setgrent)(void) = find_fn("setgrent");
NSS_STATUS status;
status = _nss_setgrent();
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("setgrent", status);
}
}
static void nss_endgrent(void)
{
NSS_STATUS (*_nss_endgrent)(void) = find_fn("endgrent");
NSS_STATUS status;
status = _nss_endgrent();
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("endgrent", status);
}
}
static int nss_initgroups(char *user, gid_t group, gid_t **groups, long int *start, long int *size)
{
NSS_STATUS (*_nss_initgroups)(char *, gid_t , long int *,
long int *, gid_t **, long int , int *) =
find_fn("initgroups_dyn");
NSS_STATUS status;
if (!_nss_initgroups) return NSS_STATUS_UNAVAIL;
status = _nss_initgroups(user, group, start, size, groups, 0, &nss_errno);
if (status != NSS_STATUS_SUCCESS) {
report_nss_error("initgroups", status);
}
return status;
}
static void print_passwd(struct passwd *pwd)
{
printf("%s:%s:%d:%d:%s:%s:%s\n",
pwd->pw_name,
pwd->pw_passwd,
pwd->pw_uid,
pwd->pw_gid,
pwd->pw_gecos,
pwd->pw_dir,
pwd->pw_shell);
}
static void print_group(struct group *grp)
{
int i;
printf("%s:%s:%d: ",
grp->gr_name,
grp->gr_passwd,
grp->gr_gid);
if (!grp->gr_mem[0]) {
printf("\n");
return;
}
for (i=0; grp->gr_mem[i+1]; i++) {
printf("%s, ", grp->gr_mem[i]);
}
printf("%s\n", grp->gr_mem[i]);
}
static void nss_test_initgroups(char *name, gid_t gid)
{
long int size = 16;
long int start = 1;
gid_t *groups = NULL;
int i;
NSS_STATUS status;
groups = (gid_t *)malloc(size * sizeof(gid_t));
groups[0] = gid;
status = nss_initgroups(name, gid, &groups, &start, &size);
if (status == NSS_STATUS_UNAVAIL) {
printf("No initgroups fn\n");
return;
}
for (i=0; i<start-1; i++) {
printf("%d, ", groups[i]);
}
printf("%d\n", groups[i]);
}
static void nss_test_users(void)
{
struct passwd *pwd;
nss_setpwent();
/* loop over all users */
while ((pwd = nss_getpwent())) {
printf("Testing user %s\n", pwd->pw_name);
printf("getpwent: "); print_passwd(pwd);
pwd = nss_getpwuid(pwd->pw_uid);
if (!pwd) {
total_errors++;
printf("ERROR: can't getpwuid\n");
continue;
}
printf("getpwuid: "); print_passwd(pwd);
pwd = nss_getpwnam(pwd->pw_name);
if (!pwd) {
total_errors++;
printf("ERROR: can't getpwnam\n");
continue;
}
printf("getpwnam: "); print_passwd(pwd);
printf("initgroups: "); nss_test_initgroups(pwd->pw_name, pwd->pw_gid);
printf("\n");
}
nss_endpwent();
}
static void nss_test_groups(void)
{
struct group *grp;
nss_setgrent();
/* loop over all groups */
while ((grp = nss_getgrent())) {
printf("Testing group %s\n", grp->gr_name);
printf("getgrent: "); print_group(grp);
grp = nss_getgrnam(grp->gr_name);
if (!grp) {
total_errors++;
printf("ERROR: can't getgrnam\n");
continue;
}
printf("getgrnam: "); print_group(grp);
grp = nss_getgrgid(grp->gr_gid);
if (!grp) {
total_errors++;
printf("ERROR: can't getgrgid\n");
continue;
}
printf("getgrgid: "); print_group(grp);
printf("\n");
}
nss_endgrent();
}
static void nss_test_errors(void)
{
struct passwd *pwd;
struct group *grp;
pwd = getpwnam("nosuchname");
if (pwd || last_error != NSS_STATUS_NOTFOUND) {
total_errors++;
printf("ERROR Non existant user gave error %d\n", last_error);
}
pwd = getpwuid(0xFFF0);
if (pwd || last_error != NSS_STATUS_NOTFOUND) {
total_errors++;
printf("ERROR Non existant uid gave error %d\n", last_error);
}
grp = getgrnam("nosuchgroup");
if (grp || last_error != NSS_STATUS_NOTFOUND) {
total_errors++;
printf("ERROR Non existant group gave error %d\n", last_error);
}
grp = getgrgid(0xFFF0);
if (grp || last_error != NSS_STATUS_NOTFOUND) {
total_errors++;
printf("ERROR Non existant gid gave error %d\n", last_error);
}
}
int main(int argc, char *argv[])
{
char *p;
if (argc > 1) so_path = argv[1];
p = strrchr(so_path, '_');
if (!p) {
printf("Badly formed name for .so - must be libnss_FOO.so\n");
exit(1);
}
nss_name = strdup(p+1);
p = strchr(nss_name, '.');
if (p) *p = 0;
printf("so_path=%s nss_name=%s\n\n", so_path, nss_name);
nss_test_users();
nss_test_groups();
nss_test_errors();
printf("total_errors=%d\n", total_errors);
return total_errors;
}