diff options
Diffstat (limited to 'ldb/nssldb')
-rw-r--r-- | ldb/nssldb/README.txt | 34 | ||||
-rw-r--r-- | ldb/nssldb/ldb-grp.c | 425 | ||||
-rw-r--r-- | ldb/nssldb/ldb-nss.c | 395 | ||||
-rw-r--r-- | ldb/nssldb/ldb-nss.h | 84 | ||||
-rw-r--r-- | ldb/nssldb/ldb-pwd.c | 239 |
5 files changed, 1177 insertions, 0 deletions
diff --git a/ldb/nssldb/README.txt b/ldb/nssldb/README.txt new file mode 100644 index 00000000..ddba62b3 --- /dev/null +++ b/ldb/nssldb/README.txt @@ -0,0 +1,34 @@ + +This test code requires a tdb that is configured for to use the asq module. +You can do that adding the following record to a tdb: + +dn: @MODULES +@LIST: asq + +Other modules can be used as well (like rdn_name for example) + +The uidNumber 0 and the gidNumber 0 are considered invalid. + +The user records should contain the followin attributes: +uid (required) the user name +userPassword (optional) the user password (if not present "LDB" is + returned in the password field) +uidNumber (required) the user uid +gidNumber (required) the user primary gid +gecos (optional) the GECOS +homeDirectory (required) the home directory +loginShell (required) the login shell +memberOf (required) all the groups the user is member of should + be reported here using their DNs. The + primary group as well. + +The group accounts should contain the following attributes: +cn (required) the group name +uesrPassword (optional) the group password (if not present "LDB" is + returned in the password field) +gidNumber (required) the group gid +member (optional) the DNs of the member users, also the ones + that have this group as primary + + +SSS diff --git a/ldb/nssldb/ldb-grp.c b/ldb/nssldb/ldb-grp.c new file mode 100644 index 00000000..71e27a91 --- /dev/null +++ b/ldb/nssldb/ldb-grp.c @@ -0,0 +1,425 @@ +/* + 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 Lesser General Public + License as published by the Free Software Foundation; either + version 3 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 Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#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; +} diff --git a/ldb/nssldb/ldb-nss.c b/ldb/nssldb/ldb-nss.c new file mode 100644 index 00000000..8f732103 --- /dev/null +++ b/ldb/nssldb/ldb-nss.c @@ -0,0 +1,395 @@ +/* + 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 Lesser General Public + License as published by the Free Software Foundation; either + version 3 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 Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#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; + + _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx, NULL); + 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_new(_ldb_nss_ctx, _ldb_nss_ctx->ldb, _LDB_NSS_BASEDN); + if ( ! ldb_dn_validate(_ldb_nss_ctx->base)) { + 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; + struct ldb_result *res = *_res; + + 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; +} + diff --git a/ldb/nssldb/ldb-nss.h b/ldb/nssldb/ldb-nss.h new file mode 100644 index 00000000..583876fe --- /dev/null +++ b/ldb/nssldb/ldb-nss.h @@ -0,0 +1,84 @@ +/* + 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 Lesser General Public + License as published by the Free Software Foundation; either + version 3 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 Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#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; + 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 */ diff --git a/ldb/nssldb/ldb-pwd.c b/ldb/nssldb/ldb-pwd.c new file mode 100644 index 00000000..44b0ab21 --- /dev/null +++ b/ldb/nssldb/ldb-pwd.c @@ -0,0 +1,239 @@ +/* + 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 Lesser General Public + License as published by the Free Software Foundation; either + version 3 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 Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#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; +} + |