From feb09e4b9ab708951a96e388c044b07c12866104 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 17 Sep 2009 11:12:36 +0200 Subject: added generic LDAP search sdap_get_generic_send/_recv --- server/providers/ldap/sdap.c | 85 ++++++++++++++++ server/providers/ldap/sdap.h | 5 + server/providers/ldap/sdap_async.c | 201 +++++++++++++++++++++++++++++++++++++ server/providers/ldap/sdap_async.h | 13 +++ 4 files changed, 304 insertions(+) diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c index 7eaa1e9dc..926869259 100644 --- a/server/providers/ldap/sdap.c +++ b/server/providers/ldap/sdap.c @@ -191,6 +191,91 @@ fail: return ret; } +int sdap_parse_generic_entry(TALLOC_CTX *memctx, + struct sdap_handle *sh, + struct sdap_msg *sm, + struct sysdb_attrs **_attrs) +{ + struct sysdb_attrs *attrs; + BerElement *ber = NULL; + struct berval **vals; + struct ldb_val v; + char *str; + int lerrno; + int i; + int ret; + + lerrno = 0; + ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + + attrs = sysdb_new_attrs(memctx); + if (!attrs) return ENOMEM; + + str = ldap_get_dn(sh->ldap, sm->msg); + if (!str) { + ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + DEBUG(1, ("ldap_get_dn failed: %d(%s)\n", + lerrno, ldap_err2string(lerrno))); + ret = EIO; + goto fail; + } + + DEBUG(9, ("OriginalDN: [%s].\n", str)); + ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, str); + if (ret) goto fail; + ldap_memfree(str); + + str = ldap_first_attribute(sh->ldap, sm->msg, &ber); + if (!str) { + ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + DEBUG(9, ("Entry has no attributes [%d(%s)]!?\n", + lerrno, ldap_err2string(lerrno))); + } + while (str) { + vals = ldap_get_values_len(sh->ldap, sm->msg, str); + if (!vals) { + ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + DEBUG(1, ("LDAP Library error: %d(%s)", + lerrno, ldap_err2string(lerrno))); + ret = EIO; + goto fail; + } + if (!vals[0]) { + DEBUG(1, ("Missing value after ldap_get_values() ??\n")); + ret = EINVAL; + goto fail; + } + for (i = 0; vals[i]; i++) { + v.data = (uint8_t *) vals[i]->bv_val; + v.length = vals[i]->bv_len; + + ret = sysdb_attrs_add_val(attrs, str, &v); + if (ret) goto fail; + } + ldap_value_free_len(vals); + + ldap_memfree(str); + str = ldap_next_attribute(sh->ldap, sm->msg, ber); + } + ber_free(ber, 0); + + ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + if (lerrno) { + DEBUG(1, ("LDAP Library error: %d(%s)", + lerrno, ldap_err2string(lerrno))); + ret = EIO; + goto fail; + } + + *_attrs = attrs; + return EOK; + +fail: + if (ber) ber_free(ber, 0); + talloc_free(attrs); + return ret; +} + /* This function converts an ldap message into a sysdb_attrs structure. * It converts only known user attributes, the rest are ignored. * If the entry is not that of an user an error is returned. diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h index 31c728959..3abe2d661 100644 --- a/server/providers/ldap/sdap.h +++ b/server/providers/ldap/sdap.h @@ -203,6 +203,11 @@ int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts, struct sdap_handle *sh, struct sdap_msg *sm, struct sysdb_attrs **_attrs, char **_dn); +int sdap_parse_generic_entry(TALLOC_CTX *memctx, + struct sdap_handle *sh, + struct sdap_msg *sm, + struct sysdb_attrs **_attrs); + int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh, struct sdap_msg *sm, char **_dn); diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c index f088e517d..6350433b7 100644 --- a/server/providers/ldap/sdap_async.c +++ b/server/providers/ldap/sdap_async.c @@ -30,6 +30,8 @@ #define LDAP_X_SSSD_PASSWORD_EXPIRED 0x555D +#define REPLY_REALLOC_INCREMENT 10 + static void make_realm_upper_case(const char *upn) { char *c; @@ -3020,3 +3022,202 @@ int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx, } return EOK; } + +/* ==Generic Search============================================ */ + +struct sdap_get_generic_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_handle *sh; + struct sss_domain_info *dom; + const char **attrs; + const char *filter; + const char *search_base; + struct sysdb_attrs **reply; + size_t reply_max; + size_t reply_count; + + struct sysdb_handle *handle; + struct sdap_op *op; +}; + +static errno_t add_to_reply(TALLOC_CTX *memctx, + struct sdap_get_generic_state *state, + struct sysdb_attrs *msg); + +static void sdap_get_generic_done(struct sdap_op *op, + struct sdap_msg *reply, + int error, void *pvt); + +struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sss_domain_info *dom, + struct sysdb_ctx *sysdb, + struct sdap_options *opts, + struct sdap_handle *sh, + const char **attrs, + const char *filter, + const char *search_base) +{ + struct tevent_req *req = NULL; + struct sdap_get_generic_state *state = NULL; + int lret; + int ret; + int msgid; + + req = tevent_req_create(memctx, &state, struct sdap_get_generic_state); + if (!req) return NULL; + + state->ev = ev; + state->opts = opts; + state->dom = dom; + state->sh = sh; + state->filter = filter; + state->attrs = attrs; + state->search_base = search_base; + state->reply = NULL; + state->reply_max = 0; + state->reply_count = 0; + state->op = NULL; + state->handle = NULL; + + DEBUG(7, ("calling ldap_search_ext with [%s][%s].\n", state->filter, + state->search_base)); + if (debug_level >= 7) { + int i; + + for (i = 0; state->attrs[i]; i++) { + DEBUG(7, ("Requesting attrs: [%s]\n", state->attrs[i])); + } + } + + lret = ldap_search_ext(state->sh->ldap, state->search_base, + LDAP_SCOPE_SUBTREE, state->filter, + discard_const(state->attrs), + false, NULL, NULL, NULL, 0, &msgid); + if (lret != LDAP_SUCCESS) { + DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(lret))); + ret = EIO; + goto fail; + } + DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid)); + + ret = sdap_op_add(state, state->ev, state->sh, msgid, + sdap_get_generic_done, req, + dp_opt_get_int(state->opts->basic,SDAP_SEARCH_TIMEOUT), + &state->op); + if (ret != EOK) { + DEBUG(1, ("Failed to set up operation!\n")); + goto fail; + } + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + + +static void sdap_get_generic_done(struct sdap_op *op, + struct sdap_msg *reply, + int error, void *pvt) +{ + struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); + struct sdap_get_generic_state *state = tevent_req_data(req, + struct sdap_get_generic_state); + int ret; + struct sysdb_attrs *attrs; + + if (error) { + tevent_req_error(req, error); + return; + } + + switch (ldap_msgtype(reply->msg)) { + case LDAP_RES_SEARCH_REFERENCE: + /* ignore references for now */ + talloc_free(reply); + + /* unlock the operation so that we can proceed with the next result */ + sdap_unlock_next_reply(state->op); + break; + + case LDAP_RES_SEARCH_ENTRY: + ret = sdap_parse_generic_entry(state, state->sh, reply, &attrs); + if (ret != EOK) { + DEBUG(1, ("sdap_parse_generic_entry failed.\n")); + tevent_req_error(req, ENOMEM); + return; + } + + ret = add_to_reply(state, state, attrs); + if (ret != EOK) { + DEBUG(1, ("add_to_reply failed.\n")); + tevent_req_error(req, ret); + return; + } + + sdap_unlock_next_reply(state->op); + break; + case LDAP_RES_SEARCH_RESULT: + tevent_req_done(req); + return; + + break; + default: + /* what is going on here !? */ + tevent_req_error(req, EIO); + return; + } + + return; +} + +int sdap_get_generic_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *reply_count, + struct sysdb_attrs ***reply) +{ + struct sdap_get_generic_state *state = tevent_req_data(req, + struct sdap_get_generic_state); + enum tevent_req_state tstate; + uint64_t err; + int i; + + if (tevent_req_is_error(req, &tstate, &err)) { + if (err) return err; + return EIO; + } + + *reply_count = state->reply_count; + *reply = talloc_steal(mem_ctx, state->reply); + for (i = 0; i < state->reply_count; i++) { + talloc_steal(mem_ctx, state->reply[i]); + } + + return EOK; +} + +static errno_t add_to_reply(TALLOC_CTX *memctx, + struct sdap_get_generic_state *state, + struct sysdb_attrs *msg) +{ + struct sysdb_attrs **dummy; + + if (state->reply == NULL || state->reply_max == state->reply_count) { + state->reply_max += REPLY_REALLOC_INCREMENT; + dummy = talloc_realloc(memctx, state->reply, struct sysdb_attrs *, + state->reply_max); + if (dummy == NULL) { + DEBUG(1, ("talloc_realloc failed.\n")); + return ENOMEM; + } + state->reply = dummy; + } + + state->reply[state->reply_count++] = talloc_steal(state->reply, msg); + + return EOK; +} diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h index c50133c82..8410f3d1a 100644 --- a/server/providers/ldap/sdap_async.h +++ b/server/providers/ldap/sdap_async.h @@ -95,3 +95,16 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, struct sdap_options *opts); int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx, struct sdap_handle **gsh); + +struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sss_domain_info *dom, + struct sysdb_ctx *sysdb, + struct sdap_options *opts, + struct sdap_handle *sh, + const char **attrs, + const char *filter, + const char *search_base); +int sdap_get_generic_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, size_t *reply_count, + struct sysdb_attrs ***reply_list); -- cgit