From 40b2779eab3a91e6e1f131bbb1b85facaf3c4eaf Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sun, 12 Oct 2008 16:37:55 -0400 Subject: Implement getgrnam() --- server/nss/nss_ldb.h | 8 +++ server/nss/nsssrv_cmd.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++-- server/nss/nsssrv_ldb.c | 169 ++++++++++++++++++++++++++++++++++++++++++--- server/nss/nsssrv_ldb.h | 11 +++ 4 files changed, 354 insertions(+), 14 deletions(-) (limited to 'server/nss') diff --git a/server/nss/nss_ldb.h b/server/nss/nss_ldb.h index 64ac592bd..3dbe70d93 100644 --- a/server/nss/nss_ldb.h +++ b/server/nss/nss_ldb.h @@ -3,12 +3,20 @@ #define NSS_LDB_PATH "/var/lib/sss/db/sssd.ldb" #define NSS_USER_BASE "cn=users,cn=local" +#define NSS_GROUP_BASE "cn=groups,cn=local" #define NSS_PWNAM_FILTER "(&(objectclass=user)(uid=%s))" #define NSS_PWUID_FILTER "(&(objectclass=user)(uidNumber=%llu))" #define NSS_PWENT_FILTER "(objectclass=user)" +#define NSS_GRNAM_FILTER "(&(objectclass=group)(gid=%s))" +#define NSS_GRNA2_FILTER "(&(objectclass=user)(memberof=%s))" +#define NSS_GRUID_FILTER "(&(objectclass=group)(gidNumber=%llu))" +#define NSS_GRENT_FILTER "(objectclass=group)" + #define NSS_PW_ATTRS {NSS_PW_NAME, NSS_PW_UIDNUM, NSS_PW_GIDNUM, \ NSS_PW_FULLNAME, NSS_PW_HOMEDIR, NSS_PW_SHELL, \ NULL} +#define NSS_GRNAM_ATTRS {NSS_GR_NAME, NSS_GR_GIDNUM, NULL} +#define NSS_GRPW_ATTRS {NSS_PW_NAME, NULL} diff --git a/server/nss/nsssrv_cmd.c b/server/nss/nsssrv_cmd.c index 666766134..b8183e005 100644 --- a/server/nss/nsssrv_cmd.c +++ b/server/nss/nsssrv_cmd.c @@ -78,6 +78,10 @@ static int nss_cmd_get_version(struct cli_ctx *cctx) return EOK; } +/**************************************************************************** + * PASSWD db related functions + ***************************************************************************/ + static int fill_pwent(struct nss_packet *packet, struct ldb_message **msgs, int count) @@ -92,12 +96,13 @@ static int fill_pwent(struct nss_packet *packet, uint64_t gid; size_t rsize, rp, blen; size_t s1, s2, s3, s4; - int i, ret, num = 0; + int i, ret, num; - /* first 2 fieldss (len and reserved), filled up later */ + /* first 2 fields (len and reserved), filled up later */ ret = nss_packet_grow(packet, 2*sizeof(uint32_t)); rp = 2*sizeof(uint32_t); + num = 0; for (i = 0; i < count; i++) { msg = msgs[i]; @@ -109,7 +114,7 @@ static int fill_pwent(struct nss_packet *packet, gid = ldb_msg_find_attr_as_uint64(msg, NSS_PW_GIDNUM, 0); if (!name || !fullname || !homedir || !shell || !uid || !gid) { - DEBUG(1, ("Incomplede user object for %s[%llu]! Skipping\n", + DEBUG(1, ("Incomplete user object for %s[%llu]! Skipping\n", name?name:"", (unsigned long long int)uid)); continue; } @@ -176,7 +181,7 @@ static int nss_cmd_getpw_callback(void *ptr, int status, if (res->count != 1) { if (res->count > 1) { - DEBUG(1, ("getpwnam call returned more than oine result !?!\n")); + DEBUG(1, ("getpwnam call returned more than one result !?!\n")); } if (res->count == 0) { DEBUG(2, ("No results for getpwnam call")); @@ -468,6 +473,172 @@ done: return EOK; } +/**************************************************************************** + * GROUP db related functions + ***************************************************************************/ + +static int fill_grent(struct nss_packet *packet, + struct ldb_message **msgs, + int count) +{ + struct ldb_message *msg; + uint8_t *body; + const char *name; + uint64_t gid; + size_t rsize, rp, blen, mnump; + int i, ret, num, memnum; + bool get_group = true; + + /* first 2 fields (len and reserved), filled up later */ + ret = nss_packet_grow(packet, 2*sizeof(uint32_t)); + rp = 2*sizeof(uint32_t); + + num = 0; + for (i = 0; i < count; i++) { + msg = msgs[i]; + + if (get_group) { + /* find group name/gid */ + name = ldb_msg_find_attr_as_string(msg, NSS_GR_NAME, NULL); + gid = ldb_msg_find_attr_as_uint64(msg, NSS_GR_GIDNUM, 0); + if (!name || !gid) { + DEBUG(1, ("Incomplete group object for %s[%llu]! Aborting\n", + name?name:"", (unsigned long long int)gid)); + num = 0; + goto done; + } + + /* fill in gid and name and set pointer for number of members */ + rsize = sizeof(uint64_t) + sizeof(uint32_t) + strlen(name)+1 +2; + ret = nss_packet_grow(packet, rsize); + nss_packet_get_body(packet, &body, &blen); + rp = blen - rsize; + ((uint64_t *)(&body[rp]))[0] = gid; + rp += sizeof(uint64_t); + ((uint32_t *)(&body[rp]))[0] = 0; /* init members num to 0 */ + mnump = rp; /* keep around pointer to set members num later */ + rp += sizeof(uint32_t); + memcpy(&body[rp], name, strlen(name)+1); + body[blen-2] = 'x'; /* group passwd field */ + body[blen-1] = '\0'; + + get_group = false; + memnum = 0; + num++; + continue; + } + + name = ldb_msg_find_attr_as_string(msg, NSS_PW_NAME, NULL); + + if (!name) { + /* last member of previous group found, or error. + * set next element to be a group, and eventually + * fail there if here start bogus entries */ + get_group = true; + nss_packet_get_body(packet, &body, &blen); + ((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */ + continue; + } + + rsize = strlen(name) + 1; + + ret = nss_packet_grow(packet, rsize); + if (ret != EOK) { + num = 0; + goto done; + } + nss_packet_get_body(packet, &body, &blen); + rp = blen - rsize; + memcpy(&body[rp], name, rsize); + + memnum++; + } + + /* fill in the last group member count */ + nss_packet_get_body(packet, &body, &blen); + ((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */ + +done: + nss_packet_get_body(packet, &body, &blen); + ((uint32_t *)body)[0] = num; /* num results */ + ((uint32_t *)body)[1] = 0; /* reserved */ + + return EOK; +} + +static int nss_cmd_getgr_callback(void *ptr, int status, + struct ldb_result *res) +{ + struct nss_cmd_ctx *nctx = talloc_get_type(ptr, struct nss_cmd_ctx); + struct cli_ctx *cctx = nctx->cctx; + uint8_t *body; + size_t blen; + int ret; + + /* create response packet */ + ret = nss_packet_new(cctx->creq, 0, + nss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + return ret; + } + + if (status != LDB_SUCCESS) { + nss_packet_set_error(cctx->creq->out, status); + goto done; + } + + if (res->count == 0) { + DEBUG(2, ("No results for getpwnam call")); + + ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t), + nss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + return ret; + } + nss_packet_get_body(cctx->creq->out, &body, &blen); + ((uint32_t *)body)[0] = 0; /* 0 results */ + ((uint32_t *)body)[1] = 0; /* reserved */ + goto done; + } + + ret = fill_grent(cctx->creq->out, res->msgs, res->count); + nss_packet_set_error(cctx->creq->out, ret); + +done: + nss_cmd_done(nctx); + return EOK; +} + +static int nss_cmd_getgrnam(struct cli_ctx *cctx) +{ + struct nss_cmd_ctx *nctx; + uint8_t *body; + size_t blen; + int ret; + const char *name; + + /* get user name to query */ + nss_packet_get_body(cctx->creq->in, &body, &blen); + name = (const char *)body; + /* if not terminated fail */ + if (name[blen -1] != '\0') { + return EINVAL; + } + + nctx = talloc(cctx, struct nss_cmd_ctx); + if (!nctx) { + return ENOMEM; + } + nctx->cctx = cctx; + + ret = nss_ldb_getgrnam(nctx, cctx->ev, cctx->ldb, name, + nss_cmd_getgr_callback, nctx); + + return ret; +} + struct nss_cmd_table nss_cmds[] = { {SSS_NSS_GET_VERSION, nss_cmd_get_version}, {SSS_NSS_GETPWNAM, nss_cmd_getpwnam}, @@ -475,6 +646,7 @@ struct nss_cmd_table nss_cmds[] = { {SSS_NSS_SETPWENT, nss_cmd_setpwent}, {SSS_NSS_GETPWENT, nss_cmd_getpwent}, {SSS_NSS_ENDPWENT, nss_cmd_endpwent}, + {SSS_NSS_GETGRNAM, nss_cmd_getgrnam}, {SSS_NSS_NULL, NULL} }; diff --git a/server/nss/nsssrv_ldb.c b/server/nss/nsssrv_ldb.c index a54bc6a50..04225e007 100644 --- a/server/nss/nsssrv_ldb.c +++ b/server/nss/nsssrv_ldb.c @@ -27,6 +27,7 @@ #include "nss/nss_ldb.h" struct nss_ldb_search_ctx { + struct ldb_context *ldb; nss_ldb_callback_t callback; void *ptr; struct ldb_result *res; @@ -49,8 +50,8 @@ static int request_done(struct nss_ldb_search_ctx *sctx) return sctx->callback(sctx->ptr, EOK, sctx->res); } -static int getpw_callback(struct ldb_request *req, - struct ldb_reply *ares) +static int get_gen_callback(struct ldb_request *req, + struct ldb_reply *ares) { struct nss_ldb_search_ctx *sctx; struct ldb_result *res; @@ -109,6 +110,7 @@ static int getpw_callback(struct ldb_request *req, } static struct nss_ldb_search_ctx *init_sctx(TALLOC_CTX *mem_ctx, + struct ldb_context *ldb, nss_ldb_callback_t fn, void *ptr) { struct nss_ldb_search_ctx *sctx; @@ -117,6 +119,7 @@ static struct nss_ldb_search_ctx *init_sctx(TALLOC_CTX *mem_ctx, if (!sctx) { return NULL; } + sctx->ldb = ldb; sctx->callback = fn; sctx->ptr = ptr; sctx->res = talloc_zero(sctx, struct ldb_result); @@ -128,7 +131,7 @@ static struct nss_ldb_search_ctx *init_sctx(TALLOC_CTX *mem_ctx, return sctx; } -static int do_search(struct nss_ldb_search_ctx *sctx, +static int pwd_search(struct nss_ldb_search_ctx *sctx, struct ldb_context *ldb, const char *expression) { @@ -140,7 +143,7 @@ static int do_search(struct nss_ldb_search_ctx *sctx, ldb_dn_new(sctx, ldb, NSS_USER_BASE), LDB_SCOPE_SUBTREE, expression, attrs, NULL, - sctx, getpw_callback, + sctx, get_gen_callback, NULL); if (ret != LDB_SUCCESS) { return nss_ldb_error_to_errno(ret); @@ -163,7 +166,7 @@ int nss_ldb_getpwnam(TALLOC_CTX *mem_ctx, struct nss_ldb_search_ctx *sctx; char *expression; - sctx = init_sctx(mem_ctx, fn, ptr); + sctx = init_sctx(mem_ctx, ldb, fn, ptr); if (!sctx) { return ENOMEM; } @@ -174,7 +177,7 @@ int nss_ldb_getpwnam(TALLOC_CTX *mem_ctx, return ENOMEM; } - return do_search(sctx, ldb, expression); + return pwd_search(sctx, ldb, expression); } int nss_ldb_getpwuid(TALLOC_CTX *mem_ctx, @@ -187,7 +190,7 @@ int nss_ldb_getpwuid(TALLOC_CTX *mem_ctx, unsigned long long int filter_uid = uid; char *expression; - sctx = init_sctx(mem_ctx, fn, ptr); + sctx = init_sctx(mem_ctx, ldb, fn, ptr); if (!sctx) { return ENOMEM; } @@ -198,7 +201,7 @@ int nss_ldb_getpwuid(TALLOC_CTX *mem_ctx, return ENOMEM; } - return do_search(sctx, ldb, expression); + return pwd_search(sctx, ldb, expression); } int nss_ldb_enumpwent(TALLOC_CTX *mem_ctx, @@ -208,14 +211,160 @@ int nss_ldb_enumpwent(TALLOC_CTX *mem_ctx, { struct nss_ldb_search_ctx *sctx; - sctx = init_sctx(mem_ctx, fn, ptr); + sctx = init_sctx(mem_ctx, ldb, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + return pwd_search(sctx, ldb, NSS_PWENT_FILTER); +} + + + +static int get_grp_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct nss_ldb_search_ctx *sctx; + struct ldb_result *res; + int n; + + sctx = talloc_get_type(req->context, struct nss_ldb_search_ctx); + res = sctx->res; + + if (!ares) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return request_error(sctx, ares->error); + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + res->count++; + break; + + case LDB_REPLY_REFERRAL: + if (res->refs) { + for (n = 0; res->refs[n]; n++) /*noop*/ ; + } else { + n = 0; + } + + res->refs = talloc_realloc(res, res->refs, char *, n + 2); + if (! res->refs) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + res->refs[n] = talloc_steal(res->refs, ares->referral); + res->refs[n + 1] = NULL; + break; + + case LDB_REPLY_DONE: + res->controls = talloc_steal(res, ares->controls); + + /* no results, return */ + if (res->count == 0) { + return request_done(sctx); + } + /* 1 result, let's search for members now and append results */ + if (res->count == 1) { + static const char *attrs[] = NSS_GRPW_ATTRS; + struct ldb_request *ureq; + const char *expression; + int ret; + + expression = talloc_asprintf(sctx, NSS_GRNA2_FILTER, + ldb_dn_get_linearized(res->msgs[0]->dn)); + if (!expression) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + ret = ldb_build_search_req(&ureq, sctx->ldb, sctx, + ldb_dn_new(sctx, sctx->ldb, NSS_USER_BASE), + LDB_SCOPE_SUBTREE, + expression, attrs, NULL, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_error(sctx, ret); + } + + ret = ldb_request(sctx->ldb, ureq); + if (ret != LDB_SUCCESS) { + return request_error(sctx, ret); + } + + return LDB_SUCCESS; + } + + /* anything else is an error */ + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + talloc_free(ares); + return LDB_SUCCESS; +} + +static int grp_search(struct nss_ldb_search_ctx *sctx, + struct ldb_context *ldb, + const char *expression) +{ + static const char *attrs[] = NSS_GRNAM_ATTRS; + struct ldb_request *req; + int ret; + + ret = ldb_build_search_req(&req, ldb, sctx, + ldb_dn_new(sctx, ldb, NSS_GROUP_BASE), + LDB_SCOPE_SUBTREE, + expression, attrs, NULL, + sctx, get_grp_callback, + NULL); + if (ret != LDB_SUCCESS) { + return nss_ldb_error_to_errno(ret); + } + + ret = ldb_request(ldb, req); + if (ret != LDB_SUCCESS) { + return nss_ldb_error_to_errno(ret); + } + + return EOK; +} + +int nss_ldb_getgrnam(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct ldb_context *ldb, + const char *name, + nss_ldb_callback_t fn, void *ptr) +{ + struct nss_ldb_search_ctx *sctx; + char *expression; + + sctx = init_sctx(mem_ctx, ldb, fn, ptr); if (!sctx) { return ENOMEM; } - return do_search(sctx, ldb, NSS_PWENT_FILTER); + expression = talloc_asprintf(sctx, NSS_GRNAM_FILTER, name); + if (!expression) { + talloc_free(sctx); + return ENOMEM; + } + + return grp_search(sctx, ldb, expression); } + int nss_ldb_init(TALLOC_CTX *mem_ctx, struct event_context *ev, struct ldb_context **ldbp) diff --git a/server/nss/nsssrv_ldb.h b/server/nss/nsssrv_ldb.h index a57a91198..9998714aa 100644 --- a/server/nss/nsssrv_ldb.h +++ b/server/nss/nsssrv_ldb.h @@ -6,6 +6,10 @@ #define NSS_PW_HOMEDIR "HomeDirectory" #define NSS_PW_SHELL "loginShell" +#define NSS_GR_NAME "gid" +#define NSS_GR_GIDNUM "gidNumber" +#define NSS_GR_MEMBER "member" + typedef int (*nss_ldb_callback_t)(void *, int, struct ldb_result *); int nss_ldb_init(TALLOC_CTX *mem_ctx, @@ -28,3 +32,10 @@ int nss_ldb_enumpwent(TALLOC_CTX *mem_ctx, struct event_context *ev, struct ldb_context *ldb, nss_ldb_callback_t fn, void *ptr); + +int nss_ldb_getgrnam(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct ldb_context *ldb, + const char *name, + nss_ldb_callback_t fn, void *ptr); + -- cgit