summaryrefslogtreecommitdiff
path: root/server/providers/ldap
diff options
context:
space:
mode:
Diffstat (limited to 'server/providers/ldap')
-rw-r--r--server/providers/ldap/ldap_id.c1325
-rw-r--r--server/providers/ldap/sdap.c69
-rw-r--r--server/providers/ldap/sdap.h7
-rw-r--r--server/providers/ldap/sdap_async.c467
-rw-r--r--server/providers/ldap/sdap_async.h14
5 files changed, 1173 insertions, 709 deletions
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index 744f29ca..12180270 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -23,756 +23,791 @@
*/
#include <errno.h>
-#include <ldap.h>
+#include <time.h>
#include <sys/time.h>
-#include <security/pam_modules.h>
-
#include "util/util.h"
-#include "providers/dp_backend.h"
#include "db/sysdb.h"
-#include "../sss_client/sss_cli.h"
-
-struct sdap_conf_ctx {
- char *base_dn;
-
- char *usr_base_dn;
- int usr_search_scope;
- char *usr_search_filter;
-
- char *usr_objectclass;
- char *usr_attr_name;
- char *usr_attr_pwd;
- char *usr_attr_uidnum;
- char *usr_attr_gidnum;
- char *usr_attr_gecos;
- char *usr_attr_homedir;
- char *usr_attr_shell;
- char **usr_attr_others;
-
- char *grp_base_dn;
- int grp_search_scope;
- char *grp_search_filter;
-
- char *grp_objectclass;
- char *grp_attr_name;
- char *grp_attr_pwd;
- char *grp_attr_gidnum;
- char *grp_attr_member;
- char **grp_attr_others;
-
- enum sdap_schema {
- SDAP_SCHEMA_RFC2307,
- SDAP_SCHEMA_RFC2307BIS
- } schema;
+#include "providers/dp_backend.h"
+#include "providers/ldap/sdap_async.h"
+
+struct sdap_id_ctx {
+ struct sdap_options *opts;
+
+ /* global sdap handler */
+ struct sdap_handle *gsh;
+
+ time_t went_offline;
+ bool offline;
};
-struct sdap_ctx {
- char *ldap_uri;
+static void sdap_req_done(struct be_req *req, int ret, const char *err)
+{
+ return req->fn(req, ret, err);
+}
- char *bind_dn;
- char *auth_method;
- char *secret;
- int secret_size;
+static bool is_offline(struct sdap_id_ctx *ctx)
+{
+ time_t now = time(NULL);
- struct sdap_conf_ctx *conf;
+ if (ctx->went_offline + ctx->opts->offline_timeout < now) {
+ return false;
+ }
+ return ctx->offline;
+}
- LDAP *ldap;
- int network_timeout;
- int opt_timeout;
-};
+static void sdap_check_online(struct be_req *req)
+{
+ struct be_online_req *oreq;
+ struct sdap_id_ctx *ctx;
-#if 0
-struct sdap_id_req {
- struct be_req *req;
- struct sdap_srv_ctx *srvctx;
+ ctx = talloc_get_type(req->be_ctx->pvt_id_data, struct sdap_id_ctx);
+ oreq = talloc_get_type(req->req_data, struct be_online_req);
-
+ if (is_offline(ctx)) {
+ oreq->online = MOD_OFFLINE;
+ } else {
+ oreq->online = MOD_ONLINE;
+ }
+
+ sdap_req_done(req, EOK, NULL);
+}
+
+static int build_attrs_from_map(TALLOC_CTX *memctx,
+ struct sdap_id_map *map,
+ size_t size,
+ const char ***_attrs)
+{
+ char **attrs;
+ int i;
+
+ attrs = talloc_array(memctx, char *, size + 1);
+ if (!attrs) return ENOMEM;
+
+ /* first attribute is the objectclass value not the attribute name */
+ attrs[0] = talloc_strdup(memctx, "objectClass");
+ if (!attrs[0]) return ENOMEM;
+
+ /* add the others */
+ for (i = 1; i < size; i++) {
+ attrs[i] = map[i].name;
+ }
+ attrs[i] = NULL;
+
+ *_attrs = (const char **)attrs;
+
+ return EOK;
+}
+
+
+/* =Connection-handling-functions========================================= */
+
+static bool connected(struct sdap_id_ctx *ctx)
+{
+ if (ctx->gsh) {
+ return ctx->gsh->connected;
+ }
+
+ return false;
+}
+
+struct sdap_id_connect_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ bool use_start_tls;
+
+ struct sdap_handle *sh;
};
-static int schedule_next_task(struct sdap_id_req *lr, struct timeval tv,
- tevent_timer_handler_t task)
+static void sdap_id_connect_done(struct tevent_req *subreq);
+static void sdap_id_anon_bind_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_id_connect_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ bool use_start_tls)
{
- int ret;
- struct tevent_timer *te;
- struct timeval timeout;
+ struct tevent_req *req, *subreq;
+ struct sdap_id_connect_state *state;
- ret = gettimeofday(&timeout, NULL);
- if (ret == -1) {
- DEBUG(1, ("gettimeofday failed [%d][%s].\n", errno, strerror(errno)));
- return ret;
+ req = tevent_req_create(memctx, &state, struct sdap_id_connect_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->use_start_tls = use_start_tls;
+
+ subreq = sdap_connect_send(state, ev, opts, use_start_tls);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
}
- timeout.tv_sec += tv.tv_sec;
- timeout.tv_usec += tv.tv_usec;
+ tevent_req_set_callback(subreq, sdap_id_connect_done, req);
+ return req;
+}
- te = tevent_add_timer(lr->req->be_ctx->ev, lr, timeout, task, lr);
- if (te == NULL) {
- return EIO;
+static void sdap_id_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_id_connect_state *state = tevent_req_data(req,
+ struct sdap_id_connect_state);
+ int ret;
+
+ ret = sdap_connect_recv(subreq, state, &state->sh);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
}
- return EOK;
+ /* TODO: use authentication (SASL/GSSAPI) when necessary */
+ subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ tevent_req_set_callback(subreq, sdap_id_anon_bind_done, req);
}
-static int wait_for_fd(struct sdap_req *lr)
+static void sdap_id_anon_bind_done(struct tevent_req *subreq)
{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ enum sdap_result result;
int ret;
- int fd;
- struct tevent_fd *fde;
- ret = ldap_get_option(lr->ldap, LDAP_OPT_DESC, &fd);
- if (ret != LDAP_OPT_SUCCESS) {
- DEBUG(1, ("ldap_get_option failed.\n"));
- return ret;
+ ret = sdap_auth_recv(subreq, &result);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ if (result != SDAP_AUTH_SUCCESS) {
+ tevent_req_error(req, EACCES);
+ return;
}
- fde = tevent_add_fd(lr->req->be_ctx->ev, lr, fd, TEVENT_FD_READ, lr->next_task, lr);
- if (fde == NULL) {
+ tevent_req_done(req);
+}
+
+static int sdap_id_connect_recv(struct tevent_req *req,
+ TALLOC_CTX *memctx, struct sdap_handle **sh)
+{
+ struct sdap_id_connect_state *state = tevent_req_data(req,
+ struct sdap_id_connect_state);
+ enum tevent_req_state tstate;
+ uint64_t err;
+
+ if (tevent_req_is_error(req, &tstate, &err)) {
+ if (err) return err;
return EIO;
}
+ *sh = talloc_steal(memctx, state->sh);
+ if (!*sh) {
+ return ENOMEM;
+ }
return EOK;
}
-static int sdap_pam_chauthtok(struct sdap_req *lr)
+
+/* =Users-Related-Functions-(by-name,by-uid)============================== */
+
+struct users_get_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+
+ struct sss_domain_info *dom;
+ struct sysdb_ctx *sysdb;
+
+ char *filter;
+ const char **attrs;
+};
+
+static void users_get_connect_done(struct tevent_req *subreq);
+static void users_get_op_done(struct tevent_req *subreq);
+
+static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ struct be_ctx *bectx,
+ const char *wildcard,
+ int filter_type,
+ int attrs_type)
{
- BerElement *ber=NULL;
+ struct tevent_req *req, *subreq;
+ struct users_get_state *state;
+ const char *attr_name;
int ret;
- int pam_status=PAM_SUCCESS;
- struct berval *bv;
- int msgid;
- LDAPMessage *result=NULL;
- int ldap_ret;
-
- ber = ber_alloc_t( LBER_USE_DER );
- if (ber == NULL) {
- DEBUG(1, ("ber_alloc_t failed.\n"));
- return PAM_SYSTEM_ERR;
- }
-
- ret = ber_printf( ber, "{tststs}", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
- lr->user_dn,
- LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, lr->pd->authtok,
- LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, lr->pd->newauthtok);
- if (ret == -1) {
- DEBUG(1, ("ber_printf failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto cleanup;
- }
-
- ret = ber_flatten(ber, &bv);
- if (ret == -1) {
- DEBUG(1, ("ber_flatten failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto cleanup;
- }
-
- ret = ldap_extended_operation(lr->ldap, LDAP_EXOP_MODIFY_PASSWD, bv,
- NULL, NULL, &msgid);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_extended_operation failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto cleanup;
- }
-
- ret = ldap_result(lr->ldap, msgid, FALSE, NULL, &result);
- if (ret == -1) {
- DEBUG(1, ("ldap_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto cleanup;
- }
- ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, NULL, NULL,
- NULL, 0);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_parse_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto cleanup;
- }
- DEBUG(3, ("LDAP_EXOP_MODIFY_PASSWD result: [%d][%s]\n", ldap_ret,
- ldap_err2string(ldap_ret)));
-
- ldap_msgfree(result);
-
- if (ldap_ret != LDAP_SUCCESS) pam_status = PAM_SYSTEM_ERR;
-
-cleanup:
- ber_bvfree(bv);
- ber_free(ber, 1);
- return pam_status;
+
+ req = tevent_req_create(memctx, &state, struct users_get_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+ state->dom = bectx->domain;
+ state->sysdb = bectx->sysdb;
+
+ switch(filter_type) {
+ case BE_FILTER_NAME:
+ attr_name = ctx->opts->user_map[SDAP_AT_USER_NAME].name;
+ break;
+ case BE_FILTER_IDNUM:
+ attr_name = ctx->opts->user_map[SDAP_AT_USER_UID].name;
+ break;
+ default:
+ ret = EINVAL;
+ goto fail;
+ }
+
+ state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+ attr_name, wildcard,
+ ctx->opts->user_map[SDAP_OC_USER].name);
+ if (!state->filter) {
+ DEBUG(2, ("Failed to build filter\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ /* TODO: handle attrs_type */
+ ret = build_attrs_from_map(state, ctx->opts->user_map,
+ SDAP_OPTS_USER, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ if (!connected(ctx)) {
+
+ if (ctx->gsh) talloc_zfree(ctx->gsh);
+
+ /* FIXME: add option to decide if tls should be used
+ * or SASL/GSSAPI, etc ... */
+ subreq = sdap_id_connect_send(state, ev, ctx->opts, false);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, users_get_connect_done, req);
+
+ return req;
+ }
+
+ subreq = sdap_get_users_send(state, state->ev,
+ state->dom, bectx->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, users_get_op_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
}
-static int sdap_init(struct sdap_req *lr)
+static void users_get_connect_done(struct tevent_req *subreq)
{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct users_get_state *state = tevent_req_data(req,
+ struct users_get_state);
int ret;
- int status=EOK;
- int ldap_vers = LDAP_VERSION3;
- int msgid;
- struct timeval network_timeout;
- struct timeval opt_timeout;
-
- ret = ldap_initialize(&(lr->ldap), lr->sdap_ctx->ldap_uri);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_initialize failed: %s\n", strerror(errno)));
- return EIO;
+
+ ret = sdap_id_connect_recv(subreq, state->ctx, &state->ctx->gsh);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
}
- /* LDAPv3 is needed for TLS */
- ret = ldap_set_option(lr->ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_vers);
- if (ret != LDAP_OPT_SUCCESS) {
- DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret)));
- status = EIO;
- goto cleanup;
- }
-
- network_timeout.tv_sec = lr->sdap_ctx->network_timeout;
- network_timeout.tv_usec = 0;
- opt_timeout.tv_sec = lr->sdap_ctx->opt_timeout;
- opt_timeout.tv_usec = 0;
- ret = ldap_set_option(lr->ldap, LDAP_OPT_NETWORK_TIMEOUT, &network_timeout);
- if (ret != LDAP_OPT_SUCCESS) {
- DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret)));
- status = EIO;
- goto cleanup;
- }
- ret = ldap_set_option(lr->ldap, LDAP_OPT_TIMEOUT, &opt_timeout);
- if (ret != LDAP_OPT_SUCCESS) {
- DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret)));
- status = EIO;
- goto cleanup;
- }
-
- /* For now TLS is forced. Maybe it would be necessary to make this
- * configurable to allow people to expose their passwords over the
- * network. */
- ret = ldap_start_tls(lr->ldap, NULL, NULL, &msgid);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_start_tls failed: [%d][%s]\n", ret,
- ldap_err2string(ret)));
- if (ret == LDAP_SERVER_DOWN) {
- status = EAGAIN;
- } else {
- status = EIO;
- }
- goto cleanup;
+ subreq = sdap_get_users_send(state, state->ev,
+ state->dom, state->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
}
+ tevent_req_set_callback(subreq, users_get_op_done, req);
+}
- lr->msgid = msgid;
+static void users_get_op_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ int ret;
- return EOK;
+ ret = sdap_get_users_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static void users_get_done(struct tevent_req *req)
+{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ enum tevent_req_state tstate;
+ uint64_t err;
+ const char *error = NULL;
+ int ret = EOK;
+
+ if (tevent_req_is_error(req, &tstate, &err)) {
+ ret = err;
+ }
-cleanup:
- ldap_unbind_ext(lr->ldap, NULL, NULL);
- lr->ldap = NULL;
- return status;
+ if (ret) error = "Enum Users Failed";
+
+ return sdap_req_done(breq, ret, error);
}
-static int sdap_bind(struct sdap_req *lr)
+/* =Groups-Related-Functions-(by-name,by-uid)============================= */
+
+struct groups_get_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+
+ struct sss_domain_info *dom;
+ struct sysdb_ctx *sysdb;
+
+ char *filter;
+ const char **attrs;
+};
+
+static void groups_get_connect_done(struct tevent_req *subreq);
+static void groups_get_op_done(struct tevent_req *subreq);
+
+static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ struct be_ctx *bectx,
+ const char *wildcard,
+ int filter_type,
+ int attrs_type)
{
+ struct tevent_req *req, *subreq;
+ struct groups_get_state *state;
+ const char *attr_name;
int ret;
- int msgid;
- char *dn=NULL;
- struct berval pw;
- pw.bv_len = 0;
- pw.bv_val = NULL;
+ req = tevent_req_create(memctx, &state, struct groups_get_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+ state->dom = bectx->domain;
+ state->sysdb = bectx->sysdb;
+
+ switch(filter_type) {
+ case BE_FILTER_NAME:
+ attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
+ break;
+ case BE_FILTER_IDNUM:
+ attr_name = ctx->opts->group_map[SDAP_AT_GROUP_GID].name;
+ break;
+ default:
+ ret = EINVAL;
+ goto fail;
+ }
- if (lr->user_dn != NULL) {
- dn = lr->user_dn;
- pw.bv_len = lr->pd->authtok_size;
- pw.bv_val = (char *) lr->pd->authtok;
+ state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+ attr_name, wildcard,
+ ctx->opts->group_map[SDAP_OC_GROUP].name);
+ if (!state->filter) {
+ DEBUG(2, ("Failed to build filter\n"));
+ ret = ENOMEM;
+ goto fail;
}
- if (lr->user_dn == NULL && lr->sdap_ctx->default_bind_dn != NULL) {
- dn = lr->sdap_ctx->default_bind_dn;
- pw.bv_len = lr->sdap_ctx->default_authtok_size;
- pw.bv_val = lr->sdap_ctx->default_authtok;
+
+ /* TODO: handle attrs_type */
+ ret = build_attrs_from_map(state, ctx->opts->group_map,
+ SDAP_OPTS_GROUP, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ if (!connected(ctx)) {
+
+ if (ctx->gsh) talloc_zfree(ctx->gsh);
+
+ /* FIXME: add option to decide if tls should be used
+ * or SASL/GSSAPI, etc ... */
+ subreq = sdap_id_connect_send(state, ev, ctx->opts, false);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, groups_get_connect_done, req);
+
+ return req;
}
- DEBUG(3, ("Trying to bind as [%s][%*s]\n", dn, pw.bv_len, pw.bv_val));
- ret = ldap_sasl_bind(lr->ldap, dn, LDAP_SASL_SIMPLE, &pw, NULL, NULL,
- &msgid);
- if (ret == -1 || msgid == -1) {
- DEBUG(1, ("ldap_bind failed\n"));
- return LDAP_OTHER;
+ subreq = sdap_get_groups_send(state, state->ev,
+ state->dom, bectx->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
}
- lr->msgid = msgid;
- return LDAP_SUCCESS;
+ tevent_req_set_callback(subreq, groups_get_op_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
}
-static void sdap_pam_loop(struct tevent_context *ev, struct tevent_fd *te,
- uint16_t fd, void *pvt)
+static void groups_get_connect_done(struct tevent_req *subreq)
{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct users_get_state *state = tevent_req_data(req,
+ struct users_get_state);
int ret;
- int pam_status=PAM_SUCCESS;
- int ldap_ret;
- struct sdap_req *lr;
- struct pam_data *pd;
- struct be_req *req;
- LDAPMessage *result=NULL;
- LDAPMessage *msg=NULL;
- struct timeval no_timeout={0, 0};
- char *errmsgp = NULL;
-/* FIXME: user timeout form config */
- char *filter=NULL;
- char *attrs[] = { LDAP_NO_ATTRS, NULL };
-
- lr = talloc_get_type(pvt, struct sdap_req);
-
- switch (lr->next_step) {
- case SDAP_OP_INIT:
- ret = sdap_init(lr);
- if (ret != EOK) {
- DEBUG(1, ("sdap_init failed.\n"));
- lr->ldap = NULL;
- if (ret == EAGAIN) {
- pam_status = PAM_AUTHINFO_UNAVAIL;
- } else {
- pam_status = PAM_SYSTEM_ERR;
- }
- goto done;
- }
- case SDAP_CHECK_INIT_RESULT:
- ret = ldap_result(lr->ldap, lr->msgid, FALSE, &no_timeout, &result);
- if (ret == -1) {
- DEBUG(1, ("ldap_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- if (ret == 0) {
- DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
- lr->next_task = sdap_pam_loop;
- lr->next_step = SDAP_CHECK_INIT_RESULT;
- ret = wait_for_fd(lr);
- if (ret != EOK) {
- DEBUG(1, ("schedule_next_task failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- return;
- }
-
- ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, NULL, NULL, NULL, 0);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_parse_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- DEBUG(3, ("ldap_start_tls result: [%d][%s]\n", ldap_ret, ldap_err2string(ldap_ret)));
-
- if (ldap_ret != LDAP_SUCCESS) {
- DEBUG(1, ("setting up TLS failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
-/* FIXME: take care that ldap_install_tls might block */
- ret = ldap_install_tls(lr->ldap);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_install_tls failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
- ret = sdap_bind(lr);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("sdap_bind failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- case SDAP_CHECK_STD_BIND:
- ret = ldap_result(lr->ldap, lr->msgid, FALSE, &no_timeout, &result);
- if (ret == -1) {
- DEBUG(1, ("ldap_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- if (ret == 0) {
- DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
- lr->next_task = sdap_pam_loop;
- lr->next_step = SDAP_CHECK_STD_BIND;
- ret = wait_for_fd(lr);
- if (ret != EOK) {
- DEBUG(1, ("schedule_next_task failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- return;
- }
-
- ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, &errmsgp,
- NULL, NULL, 0);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_parse_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- DEBUG(3, ("Bind result: [%d][%s][%s]\n", ldap_ret,
- ldap_err2string(ldap_ret), errmsgp));
- if (ldap_ret != LDAP_SUCCESS) {
- DEBUG(1, ("bind failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
- filter = talloc_asprintf(lr->sdap_ctx,
- "(&(%s=%s)(objectclass=%s))",
- lr->sdap_ctx->user_name_attribute,
- lr->pd->user,
- lr->sdap_ctx->user_object_class);
-
- DEBUG(4, ("calling ldap_search_ext with [%s].\n", filter));
- ret = ldap_search_ext(lr->ldap,
- lr->sdap_ctx->user_search_base,
- LDAP_SCOPE_SUBTREE,
- filter,
- attrs,
- TRUE,
- NULL,
- NULL,
- NULL,
- 0,
- &(lr->msgid));
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_search_ext failed [%d][%s].\n", ret, ldap_err2string(ret)));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- case SDAP_CHECK_SEARCH_DN_RESULT:
- ret = ldap_result(lr->ldap, lr->msgid, TRUE, &no_timeout, &result);
- if (ret == -1) {
- DEBUG(1, ("ldap_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- if (ret == 0) {
- DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
- lr->next_task = sdap_pam_loop;
- lr->next_step = SDAP_CHECK_SEARCH_DN_RESULT;
- ret = wait_for_fd(lr);
- if (ret != EOK) {
- DEBUG(1, ("schedule_next_task failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- return;
- }
-
- msg = ldap_first_message(lr->ldap, result);
- if (msg == NULL) {
- DEBUG(1, ("ldap_first_message failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
- do {
- switch ( ldap_msgtype(msg) ) {
- case LDAP_RES_SEARCH_ENTRY:
- if (lr->user_dn != NULL) {
- DEBUG(1, ("Found more than one object with filter [%s].\n",
- filter));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- lr->user_dn = ldap_get_dn(lr->ldap, msg);
- if (lr->user_dn == NULL) {
- DEBUG(1, ("ldap_get_dn failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
- if ( *(lr->user_dn) == '\0' ) {
- DEBUG(1, ("No user found.\n"));
- pam_status = PAM_USER_UNKNOWN;
- goto done;
- }
- DEBUG(3, ("Found dn: %s\n",lr->user_dn));
-
- ldap_msgfree(result);
- result = NULL;
- break;
- default:
- DEBUG(3, ("ignoring message with type %d.\n", ldap_msgtype(msg)));
- }
- } while( (msg=ldap_next_message(lr->ldap, msg)) != NULL );
-
- switch (lr->pd->cmd) {
- case SSS_PAM_AUTHENTICATE:
- case SSS_PAM_CHAUTHTOK:
- break;
- case SSS_PAM_ACCT_MGMT:
- case SSS_PAM_SETCRED:
- case SSS_PAM_OPEN_SESSION:
- case SSS_PAM_CLOSE_SESSION:
- pam_status = PAM_SUCCESS;
- goto done;
- break;
- default:
- DEBUG(1, ("Unknown pam command %d.\n", lr->pd->cmd));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
- ret = sdap_bind(lr);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("sdap_bind failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- case SDAP_CHECK_USER_BIND:
- ret = ldap_result(lr->ldap, lr->msgid, FALSE, &no_timeout, &result);
- if (ret == -1) {
- DEBUG(1, ("ldap_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- if (ret == 0) {
- DEBUG(1, ("ldap_result not ready yet, waiting.\n"));
- lr->next_task = sdap_pam_loop;
- lr->next_step = SDAP_CHECK_USER_BIND;
- ret = wait_for_fd(lr);
- if (ret != EOK) {
- DEBUG(1, ("schedule_next_task failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- return;
- }
-
- ret = ldap_parse_result(lr->ldap, result, &ldap_ret, NULL, &errmsgp,
- NULL, NULL, 0);
- if (ret != LDAP_SUCCESS) {
- DEBUG(1, ("ldap_parse_result failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
- DEBUG(3, ("Bind result: [%d][%s][%s]\n", ldap_ret,
- ldap_err2string(ldap_ret), errmsgp));
- switch (ldap_ret) {
- case LDAP_SUCCESS:
- pam_status = PAM_SUCCESS;
- break;
- case LDAP_INVALID_CREDENTIALS:
- pam_status = PAM_CRED_INSUFFICIENT;
- goto done;
- break;
- default:
- pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
- switch (lr->pd->cmd) {
- case SSS_PAM_AUTHENTICATE:
- pam_status = PAM_SUCCESS;
- break;
- case SSS_PAM_CHAUTHTOK:
- pam_status = sdap_pam_chauthtok(lr);
- break;
- case SSS_PAM_ACCT_MGMT:
- case SSS_PAM_SETCRED:
- case SSS_PAM_OPEN_SESSION:
- case SSS_PAM_CLOSE_SESSION:
- pam_status = PAM_SUCCESS;
- break;
- default:
- DEBUG(1, ("Unknown pam command %d.\n", lr->pd->cmd));
- pam_status = PAM_SYSTEM_ERR;
- }
- break;
- default:
- DEBUG(1, ("Unknown ldap backend operation %d.\n", lr->next_step));
- pam_status = PAM_SYSTEM_ERR;
+
+ ret = sdap_id_connect_recv(subreq, state->ctx, &state->ctx->gsh);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
}
-done:
- ldap_memfree(errmsgp);
- ldap_msgfree(result);
- talloc_free(filter);
- if (lr->ldap != NULL) ldap_unbind_ext(lr->ldap, NULL, NULL);
- req = lr->req;
- pd = talloc_get_type(lr->req->req_data, struct pam_data);
- pd->pam_status = pam_status;
+ subreq = sdap_get_groups_send(state, state->ev,
+ state->dom, state->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, groups_get_op_done, req);
+}
+
+static void groups_get_op_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ int ret;
- talloc_free(lr);
+ ret = sdap_get_groups_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
- req->fn(req, pam_status, NULL);
+ tevent_req_done(req);
}
-static void sdap_start(struct tevent_context *ev, struct tevent_timer *te,
- struct timeval tv, void *pvt)
+static void groups_get_done(struct tevent_req *req)
{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ enum tevent_req_state tstate;
+ uint64_t err;
+ const char *error = NULL;
+ int ret = EOK;
+
+ if (tevent_req_is_error(req, &tstate, &err)) {
+ ret = err;
+ }
+
+ if (ret) error = "Enum Groups Failed";
+
+ return sdap_req_done(breq, ret, error);
+}
+
+/* =Get-Groups-for-User================================================== */
+
+struct groups_by_user_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+ struct sss_domain_info *dom;
+ struct sysdb_ctx *sysdb;
+ const char *name;
+ const char **attrs;
+};
+
+static void groups_by_user_connect_done(struct tevent_req *subreq);
+static void groups_by_user_op_done(struct tevent_req *subreq);
+
+static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ const char *name)
+{
+ struct tevent_req *req, *subreq;
+ struct groups_by_user_state *state;
int ret;
- int pam_status;
- struct sdap_req *lr;
- struct be_req *req;
- struct pam_data *pd;
- lr = talloc_get_type(pvt, struct sdap_req);
+ req = tevent_req_create(memctx, &state, struct groups_by_user_state);
+ if (!req) return NULL;
- ret = sdap_init(lr);
- if (ret != EOK) {
- DEBUG(1, ("sdap_init failed.\n"));
- lr->ldap = NULL;
- if (ret == EAGAIN) {
- pam_status = PAM_AUTHINFO_UNAVAIL;
- } else {
- pam_status = PAM_SYSTEM_ERR;
+ state->ev = ev;
+ state->ctx = ctx;
+ state->dom = dom;
+ state->sysdb = sysdb;
+ state->name = name;
+
+ ret = build_attrs_from_map(state, ctx->opts->group_map,
+ SDAP_OPTS_GROUP, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ if (!connected(ctx)) {
+
+ if (ctx->gsh) talloc_zfree(ctx->gsh);
+
+ /* FIXME: add option to decide if tls should be used
+ * or SASL/GSSAPI, etc ... */
+ subreq = sdap_id_connect_send(state, ev, ctx->opts, false);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
}
- goto done;
+
+ tevent_req_set_callback(subreq, groups_by_user_connect_done, req);
+
+ return req;
}
- lr->next_task = sdap_pam_loop;
- lr->next_step = SDAP_CHECK_INIT_RESULT;
- ret = wait_for_fd(lr);
- if (ret != EOK) {
- DEBUG(1, ("schedule_next_task failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
+ subreq = sdap_get_initgr_send(state, state->ev,
+ state->dom, state->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->name, state->attrs);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
}
- return;
+ tevent_req_set_callback(subreq, groups_by_user_op_done, req);
-done:
- if (lr->ldap != NULL ) ldap_unbind_ext(lr->ldap, NULL, NULL);
- req = lr->req;
- pd = talloc_get_type(lr->req->req_data, struct pam_data);
- pd->pam_status = pam_status;
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void groups_by_user_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct groups_by_user_state *state = tevent_req_data(req,
+ struct groups_by_user_state);
+ int ret;
- talloc_free(lr);
+ ret = sdap_id_connect_recv(subreq, state->ctx, &state->ctx->gsh);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
- req->fn(req, pam_status, NULL);
+ subreq = sdap_get_initgr_send(state, state->ev,
+ state->dom, state->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->name, state->attrs);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, groups_by_user_op_done, req);
}
-static void sdap_pam_handler(struct be_req *req)
+static void groups_by_user_op_done(struct tevent_req *subreq)
{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
int ret;
- int pam_status=PAM_SUCCESS;
- struct sdap_req *lr;
- struct sdap_ctx *sdap_ctx;
- struct pam_data *pd;
- struct timeval timeout;
- pd = talloc_get_type(req->req_data, struct pam_data);
+ ret = sdap_get_initgr_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
- sdap_ctx = talloc_get_type(req->be_ctx->pvt_auth_data, struct sdap_ctx);
+ tevent_req_done(req);
+}
- lr = talloc(req, struct sdap_req);
+static void groups_by_user_done(struct tevent_req *req)
+{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ enum tevent_req_state tstate;
+ uint64_t err;
+ const char *error = NULL;
+ int ret = EOK;
+
+ if (tevent_req_is_error(req, &tstate, &err)) {
+ ret = err;
+ }
- lr->ldap = NULL;
- lr->req = req;
- lr->pd = pd;
- lr->sdap_ctx = sdap_ctx;
- lr->user_dn = NULL;
- lr->next_task = NULL;
- lr->next_step = SDAP_NOOP;
+ if (ret) error = "Init Groups Failed";
- timeout.tv_sec=0;
- timeout.tv_usec=0;
- ret = schedule_next_task(lr, timeout, sdap_start);
- if (ret != EOK) {
- DEBUG(1, ("schedule_next_task failed.\n"));
- pam_status = PAM_SYSTEM_ERR;
- goto done;
+ return sdap_req_done(breq, ret, error);
+}
+
+
+
+/* =Get-Account-Info-Call================================================= */
+
+/* FIXME: embed this function in sssd_be and only call out
+ * specific functions from modules */
+static void sdap_get_account_info(struct be_req *breq)
+{
+ struct sdap_id_ctx *ctx;
+ struct be_acct_req *ar;
+ struct tevent_req *req;
+ const char *err = "Unknown Error";
+ int ret = EOK;
+
+ ctx = talloc_get_type(breq->be_ctx->pvt_id_data, struct sdap_id_ctx);
+
+ if (is_offline(ctx)) {
+ return sdap_req_done(breq, EAGAIN, "Offline");
}
- return;
+ ar = talloc_get_type(breq->req_data, struct be_acct_req);
-done:
- talloc_free(lr);
+ switch (ar->entry_type) {
+ case BE_REQ_USER: /* user */
+
+ req = users_get_send(breq, breq->be_ctx->ev,
+ ctx, breq->be_ctx,
+ ar->filter_value,
+ ar->filter_type,
+ ar->attr_type);
+ if (!req) {
+ return sdap_req_done(breq, ENOMEM, "Out of memory");
+ }
+
+ tevent_req_set_callback(req, users_get_done, breq);
+
+ break;
+
+ case BE_REQ_GROUP: /* group */
+
+ req = groups_get_send(breq, breq->be_ctx->ev,
+ ctx, breq->be_ctx,
+ ar->filter_value,
+ ar->filter_type,
+ ar->attr_type);
+ if (!req) {
+ return sdap_req_done(breq, ENOMEM, "Out of memory");
+ }
+
+ tevent_req_set_callback(req, groups_get_done, breq);
+
+ break;
+
+ case BE_REQ_INITGROUPS: /* init groups for user */
+ if (ar->filter_type != BE_FILTER_NAME) {
+ ret = EINVAL;
+ err = "Invalid filter type";
+ break;
+ }
+ if (ar->attr_type != BE_ATTR_CORE) {
+ ret = EINVAL;
+ err = "Invalid attr type";
+ break;
+ }
+ if (strchr(ar->filter_value, '*')) {
+ ret = EINVAL;
+ err = "Invalid filter value";
+ break;
+ }
+ req = groups_by_user_send(breq, breq->be_ctx->ev, ctx,
+ breq->be_ctx->domain, breq->be_ctx->sysdb,
+ ar->filter_value);
+ if (!req) ret = ENOMEM;
+ /* tevent_req_set_callback(req, groups_by_user_done, breq); */
+
+ tevent_req_set_callback(req, groups_by_user_done, breq);
+
+ break;
- pd->pam_status = pam_status;
- req->fn(req, pam_status, NULL);
+ default: /*fail*/
+ ret = EINVAL;
+ err = "Invalid request type";
+ }
+
+ if (ret != EOK) return sdap_req_done(breq, ret, err);
}
static void sdap_shutdown(struct be_req *req)
{
/* TODO: Clean up any internal data */
- req->fn(req, EOK, NULL);
+ sdap_req_done(req, EOK, NULL);
}
-struct be_auth_ops sdap_auth_ops = {
- .pam_handler = sdap_pam_handler,
+struct be_id_ops sdap_id_ops = {
+ .check_online = sdap_check_online,
+ .get_account_info = sdap_get_account_info,
.finalize = sdap_shutdown
};
-
int sssm_ldap_init(struct be_ctx *bectx,
- struct be_id_ops **ops, void **pvt_data)
+ struct be_id_ops **ops,
+ void **pvt_data)
{
- struct sdap_ctx *ctx;
-}
+ int ldap_opt_x_tls_require_cert;
+ struct sdap_id_ctx *ctx;
+ char *tls_reqcert;
+ int ret;
+ ctx = talloc_zero(bectx, struct sdap_id_ctx);
+ if (!ctx) return ENOMEM;
-{
- char *ldap_uri;
- char *default_bind_dn;
- char *default_authtok_type;
- char *default_authtok;
- char *user_search_base;
- char *user_name_attribute;
- char *user_object_class;
- int network_timeout;
- int opt_timeout;
- int ret;
+ ret = sdap_get_options(ctx, bectx->cdb, bectx->conf_path,
+ &ctx->opts);
- ctx = talloc(bectx, struct sdap_ctx);
- if (!ctx) {
- return ENOMEM;
+ tls_reqcert = ctx->opts->basic[SDAP_TLS_REQCERT].value;
+ if (tls_reqcert) {
+ if (strcasecmp(tls_reqcert, "never") == 0) {
+ ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_NEVER;
+ }
+ else if (strcasecmp(tls_reqcert, "allow") == 0) {
+ ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_ALLOW;
+ }
+ else if (strcasecmp(tls_reqcert, "try") == 0) {
+ ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_TRY;
+ }
+ else if (strcasecmp(tls_reqcert, "demand") == 0) {
+ ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_DEMAND;
+ }
+ else if (strcasecmp(tls_reqcert, "hard") == 0) {
+ ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_HARD;
+ }
+ else {
+ DEBUG(1, ("Unknown value for tls_reqcert.\n"));
+ ret = EINVAL;
+ goto done;
+ }
+ /* LDAP_OPT_X_TLS_REQUIRE_CERT has to be set as a global option,
+ * because the SSL/TLS context is initialized from this value. */
+ ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
+ &ldap_opt_x_tls_require_cert);
+ if (ret != LDAP_OPT_SUCCESS) {
+ DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret)));
+ ret = EIO;
+ goto done;
+ }
}
-/* TODO: add validation checks for ldapUri, user_search_base,
- * user_name_attribute, etc */
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- "ldapUri", "ldap://localhost", &ldap_uri);
- if (ret != EOK) goto done;
- ctx->ldap_uri = ldap_uri;
-
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- "defaultBindDn", NULL, &default_bind_dn);
- if (ret != EOK) goto done;
- ctx->default_bind_dn = default_bind_dn;
-
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- "defaultAuthtokType", NULL, &default_authtok_type);
- if (ret != EOK) goto done;
- ctx->default_authtok_type = default_authtok_type;
-
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- "userSearchBase", NULL, &user_search_base);
- if (ret != EOK) goto done;
- if (user_search_base == NULL) {
- DEBUG(1, ("missing userSearchBase.\n"));
- ret = EINVAL;
- goto done;
- }
- ctx->user_search_base = user_search_base;
-
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- "userNameAttribute", "uid", &user_name_attribute);
- if (ret != EOK) goto done;
- ctx->user_name_attribute = user_name_attribute;
-
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- "userObjectClass", "posixAccount",
- &user_object_class);
- if (ret != EOK) goto done;
- ctx->user_object_class = user_object_class;
-
-/* TODO: better to have a blob object than a string here */
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- "defaultAuthtok", NULL, &default_authtok);
- if (ret != EOK) goto done;
- ctx->default_authtok = default_authtok;
- ctx->default_authtok_size = (default_authtok==NULL?0:strlen(default_authtok));
-
- ret = confdb_get_int(bectx->cdb, ctx, bectx->conf_path,
- "network_timeout", 5, &network_timeout);
- if (ret != EOK) goto done;
- ctx->network_timeout = network_timeout;
-
- ret = confdb_get_int(bectx->cdb, ctx, bectx->conf_path,
- "opt_timeout", 5, &opt_timeout);
- if (ret != EOK) goto done;
- ctx->network_timeout = opt_timeout;
-
- *ops = &sdap_auth_ops;
+ *ops = &sdap_id_ops;
*pvt_data = ctx;
ret = EOK;
@@ -782,5 +817,3 @@ done:
}
return ret;
}
-
-#endif
diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index 9abcf566..ddba0ba5 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -110,6 +110,48 @@ int sdap_get_options(TALLOC_CTX *memctx,
opts->basic[i].opt_name, opts->basic[i].value));
}
+ /* re-read special options that are easier to be consumed after they are
+ * transformed */
+
+/* TODO: better to have a blob object than a string here */
+ ret = confdb_get_string(cdb, opts, conf_path,
+ "defaultAuthtok", NULL,
+ &opts->default_authtok);
+ if (ret != EOK) goto done;
+ if (opts->default_authtok) {
+ opts->default_authtok_size = strlen(opts->default_authtok);
+ }
+
+ ret = confdb_get_int(cdb, opts, conf_path,
+ "network_timeout", 5,
+ &opts->network_timeout);
+ if (ret != EOK) goto done;
+
+ ret = confdb_get_int(cdb, opts, conf_path,
+ "opt_timeout", 5,
+ &opts->opt_timeout);
+ if (ret != EOK) goto done;
+
+ ret = confdb_get_int(cdb, opts, conf_path,
+ "offline_timeout", 60,
+ &opts->offline_timeout);
+ if (ret != EOK) goto done;
+
+ /* schema type */
+ if (strcasecmp(opts->basic[SDAP_SCHEMA].value, "rfc2307") == 0) {
+ opts->schema_type = SDAP_SCHEMA_RFC2307;
+ } else
+ if (strcasecmp(opts->basic[SDAP_SCHEMA].value, "rfc2307bis") == 0) {
+ opts->schema_type = SDAP_SCHEMA_RFC2307BIS;
+ } else {
+ DEBUG(0, ("Unrecognized schema type: %s\n",
+ opts->basic[SDAP_SCHEMA].value));
+ ret = EINVAL;
+ goto done;
+ }
+
+
+/* FIXME: make defaults per schema type memberUid vs member, etc... */
for (i = 0; i < SDAP_OPTS_USER; i++) {
opts->user_map[i].opt_name = default_user_map[i].opt_name;
@@ -154,33 +196,6 @@ int sdap_get_options(TALLOC_CTX *memctx,
opts->group_map[i].opt_name, opts->group_map[i].name));
}
- /* re-read special options that are easier to be consumed after they are
- * transformed */
-
-/* TODO: better to have a blob object than a string here */
- ret = confdb_get_string(cdb, opts, conf_path,
- "defaultAuthtok", NULL,
- &opts->default_authtok);
- if (ret != EOK) goto done;
- if (opts->default_authtok) {
- opts->default_authtok_size = strlen(opts->default_authtok);
- }
-
- ret = confdb_get_int(cdb, opts, conf_path,
- "network_timeout", 5,
- &opts->network_timeout);
- if (ret != EOK) goto done;
-
- ret = confdb_get_int(cdb, opts, conf_path,
- "opt_timeout", 5,
- &opts->opt_timeout);
- if (ret != EOK) goto done;
-
- ret = confdb_get_int(cdb, opts, conf_path,
- "offline_timeout", 60,
- &opts->offline_timeout);
- if (ret != EOK) goto done;
-
ret = EOK;
*_opts = opts;
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index b3435c8b..85b17515 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -113,6 +113,13 @@ struct sdap_options {
int network_timeout;
int opt_timeout;
int offline_timeout;
+
+ /* supported schema types */
+ enum schema_type {
+ SDAP_SCHEMA_RFC2307 = 1, /* memberUid = uid */
+ SDAP_SCHEMA_RFC2307BIS = 2, /* member = dn */
+ SDAP_SCHEMA_IPA_V1 = 3 /* member/memberof with unrolling */
+ } schema_type;
};
int sdap_get_options(TALLOC_CTX *memctx,
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index 2aba33c1..b795e83d 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -85,6 +85,13 @@ static int get_fd_from_ldap(LDAP *ldap, int *fd)
return EOK;
}
+static bool valid_handle(struct sdap_handle *sh)
+{
+ if (!sh) return false;
+ if (sh->ldap) return true;
+ return false;
+}
+
/* ==Parse-Results-And-Handle-Disconnections============================== */
static enum sdap_result sdap_check_result(struct sdap_handle *sh,
@@ -117,6 +124,45 @@ static enum sdap_result sdap_check_result(struct sdap_handle *sh,
return SDAP_SUCCESS;
}
+/* ==LDAP-Operations-Helpers============================================== */
+
+struct ldap_operation_destructor_state {
+ struct sdap_handle *sh;
+ int msgid;
+};
+
+static int ldap_operation_destructor(void *mem)
+{
+ struct ldap_operation_destructor_state *state =
+ (struct ldap_operation_destructor_state *)mem;
+
+ if (valid_handle(state->sh)) {
+ /* we don't check the result here, if a message was really abandoned,
+ * hopefully the server will get an abandon.
+ * If the operation was already fully completed, this is going to be
+ * just a noop */
+ ldap_abandon_ext(state->sh->ldap, state->msgid, NULL, NULL);
+ }
+
+ return 0;
+}
+
+static int set_ldap_operation_destructor(TALLOC_CTX *parent,
+ struct sdap_handle *sh, int msgid)
+{
+ struct ldap_operation_destructor_state *state;
+
+ state = talloc(parent, struct ldap_operation_destructor_state);
+ if (!state) return ENOMEM;
+
+/* TODO: should we talloc_reference sdap_handle here ? */
+ state->sh = sh;
+ state->msgid = msgid;
+
+ talloc_set_destructor((TALLOC_CTX *)state, ldap_operation_destructor);
+
+ return EOK;
+}
/* ==Connect-to-LDAP-Server=============================================== */
@@ -862,6 +908,9 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
}
DEBUG(8, ("ldap_search_ext called, msgid = %d\n", state->msgid));
+ ret = set_ldap_operation_destructor(state, sh, state->msgid);
+ if (ret) goto fail;
+
subreq = sysdb_transaction_send(state, state->ev, sysdb);
if (!subreq) {
ret = ENOMEM;
@@ -1055,24 +1104,12 @@ static void sdap_fake_users_done(struct tevent_context *ev,
int sdap_get_users_recv(struct tevent_req *req)
{
- struct sdap_get_users_state *state = tevent_req_data(req,
- struct sdap_get_users_state);
enum tevent_req_state tstate;
uint64_t err;
if (tevent_req_is_error(req, &tstate, &err)) {
-
- /* FIXME: send abandon ?
- * read all to flush the read queue ?
- * close the connection ? */
-
- /* closing for now */
- ldap_unbind_ext(state->sh->ldap, NULL, NULL);
- state->sh->connected = false;
- state->sh->ldap = NULL;
- state->sh->fd = -1;
-
- return err;
+ if (err) return err;
+ return EIO;
}
return EOK;
@@ -1131,6 +1168,9 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
}
DEBUG(8, ("ldap_search_ext called, msgid = %d\n", state->msgid));
+ ret = set_ldap_operation_destructor(state, sh, state->msgid);
+ if (ret) goto fail;
+
subreq = sysdb_transaction_send(state, state->ev, sysdb);
if (!subreq) {
ret = ENOMEM;
@@ -1276,9 +1316,9 @@ static void sdap_get_groups_done(struct tevent_context *ev,
}
}
-static void sdap_fake_groups_done(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval tv, void *pvt);
+static void sdap_get_groups_fake_done(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *pvt);
static void sdap_get_groups_save_done(struct tevent_req *subreq)
{
@@ -1303,16 +1343,16 @@ static void sdap_get_groups_save_done(struct tevent_req *subreq)
* get a SDAP_RETRY it is fine. */
te = tevent_add_timer(state->ev, state, tv,
- sdap_fake_groups_done, req);
+ sdap_get_groups_fake_done, req);
if (!te) {
tevent_req_error(req, ENOMEM);
return;
}
}
-static void sdap_fake_groups_done(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval tv, void *pvt)
+static void sdap_get_groups_fake_done(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *pvt)
{
struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
struct sdap_get_groups_state *state = tevent_req_data(req,
@@ -1324,24 +1364,387 @@ static void sdap_fake_groups_done(struct tevent_context *ev,
int sdap_get_groups_recv(struct tevent_req *req)
{
- struct sdap_get_groups_state *state = tevent_req_data(req,
- struct sdap_get_groups_state);
enum tevent_req_state tstate;
uint64_t err;
if (tevent_req_is_error(req, &tstate, &err)) {
+ if (err) return err;
+ return EIO;
+ }
- /* FIXME: send abandon ?
- * read all to flush the read queue ?
- * close the connection ? */
+ return EOK;
+}
- /* closing for now */
- ldap_unbind_ext(state->sh->ldap, NULL, NULL);
- state->sh->connected = false;
- state->sh->ldap = NULL;
- state->sh->fd = -1;
+/* ==Initgr-call-(groups-a-user-is-member-of)============================= */
- return err;
+struct sdap_get_initgr_state {
+ struct tevent_context *ev;
+ struct sysdb_ctx *sysdb;
+ struct sdap_options *opts;
+ struct sss_domain_info *dom;
+ struct sdap_handle *sh;
+ const char *name;
+ const char **grp_attrs;
+
+ struct sysdb_handle *handle;
+ struct tevent_fd *fde;
+ int msgid;
+};
+
+static void sdap_get_initgr_process(struct tevent_req *subreq);
+static void sdap_get_initgr_transaction(struct tevent_req *subreq);
+static void sdap_get_initgr_done(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags, void *pvt);
+static void sdap_get_initgr_save_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_get_initgr_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 *name,
+ const char **grp_attrs)
+{
+ struct tevent_req *req, *subreq;
+ struct sdap_get_initgr_state *state;
+ struct timeval tv = {0, 0};
+ const char **attrs;
+ int ret;
+
+ req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sysdb = sysdb;
+ state->dom = dom;
+ state->sh = sh;
+ state->name = name;
+ state->grp_attrs = grp_attrs;
+
+ switch (opts->schema_type) {
+ case SDAP_SCHEMA_RFC2307:
+
+ subreq = tevent_wakeup_send(state, ev, tv);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, sdap_get_initgr_process, req);
+ break;
+
+ case SDAP_SCHEMA_RFC2307BIS:
+
+ attrs = talloc_array(state, const char *, 2);
+ if (!attrs) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ attrs[0] = SYSDB_ORIG_DN;
+ attrs[1] = NULL;
+
+ subreq = sysdb_search_user_by_name_send(state, ev, sysdb, NULL,
+ dom, name, attrs);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, sdap_get_initgr_process, req);
+ break;
+
+ default:
+ ret = EINVAL;
+ goto fail;
+ }
+
+ return req;
+
+fail:
+ tevent_req_error(req, EIO);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void sdap_get_initgr_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_initgr_state *state = tevent_req_data(req,
+ struct sdap_get_initgr_state);
+ struct ldb_message *msg;
+ const char *user_dn;
+ char *filter;
+ int ret;
+
+ switch (state->opts->schema_type) {
+ case SDAP_SCHEMA_RFC2307:
+
+ if (!tevent_wakeup_recv(subreq)) {
+ tevent_req_error(req, EFAULT);
+ return;
+ }
+ talloc_zfree(subreq);
+
+ filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+ state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
+ state->name,
+ state->opts->group_map[SDAP_OC_GROUP].name);
+ if (!filter) {
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ break;
+
+ case SDAP_SCHEMA_RFC2307BIS:
+
+ ret = sysdb_search_user_recv(subreq, state, &msg);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ user_dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL);
+ if (!user_dn) {
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+ state->opts->user_map[SDAP_AT_GROUP_MEMBER].name,
+ user_dn,
+ state->opts->user_map[SDAP_OC_GROUP].name);
+ if (!filter) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ talloc_free(msg);
+
+ break;
+
+ default:
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ DEBUG(5, ("calling ldap_search_ext with filter:[%s].\n", filter));
+
+
+ ret = ldap_search_ext(state->sh->ldap,
+ state->opts->basic[SDAP_GROUP_SEARCH_BASE].value,
+ LDAP_SCOPE_SUBTREE, filter,
+ discard_const(state->grp_attrs),
+ false, NULL, NULL, NULL, 0, &state->msgid);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(ret)));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ DEBUG(8, ("ldap_search_ext called, msgid = %d\n", state->msgid));
+
+ ret = set_ldap_operation_destructor(state, state->sh, state->msgid);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_get_initgr_transaction, req);
+}
+
+static void sdap_get_initgr_transaction(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_initgr_state *state = tevent_req_data(req,
+ struct sdap_get_initgr_state);
+ int ret;
+
+ ret = sysdb_transaction_recv(subreq, state, &state->handle);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->fde = tevent_add_fd(state->ev, state,
+ state->sh->fd, TEVENT_FD_READ,
+ sdap_get_initgr_done, req);
+ if (!state->fde) {
+ DEBUG(1, ("Failed to set up fd event!\n"));
+ tevent_req_error(req, ENOMEM);
+ }
+}
+
+static void sdap_get_initgr_done(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags, void *pvt)
+{
+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+ struct sdap_get_initgr_state *state = tevent_req_data(req,
+ struct sdap_get_initgr_state);
+ struct tevent_req *subreq;
+ LDAPMessage *msg = NULL;
+ struct sdap_msg *reply;
+ enum sdap_result res;
+ char *errmsg;
+ int restype;
+ int result;
+ int ret;
+
+ res = sdap_check_result(state->sh, state->msgid, false,
+ &msg, &restype);
+ if (res != SDAP_SUCCESS) {
+ if (res != SDAP_RETRY) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ /* make sure fd is readable so we can fetch the next result */
+ TEVENT_FD_READABLE(state->fde);
+ return;
+ }
+
+ if (!msg) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ reply = talloc_zero(state, struct sdap_msg);
+ if (!reply) {
+ ldap_msgfree(msg);
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ reply->msg = msg;
+ ret = sdap_msg_attach(reply, msg);
+ if (ret) {
+ DEBUG(1, ("Error appending memory: %s(%d)\n", strerror(ret), ret));
+ tevent_req_error(req, EFAULT);
+ return;
+ }
+
+ switch (restype) {
+ case LDAP_RES_SEARCH_REFERENCE:
+ /* ignore references for now */
+ ldap_msgfree(msg);
+ break;
+
+ case LDAP_RES_SEARCH_ENTRY:
+ /* FIXME: should we set a timeout tevent timed function ? */
+
+ /* stop reading until operation is done */
+ TEVENT_FD_NOT_READABLE(state->fde);
+
+ subreq = sdap_save_group_send(state, state->ev, state->handle,
+ state->opts, state->dom,
+ state->sh, reply);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ /* attach reply to subreq,
+ * will not be needed anymore once subreq is done */
+ talloc_steal(subreq, reply);
+
+ tevent_req_set_callback(subreq, sdap_get_initgr_save_done, req);
+ break;
+
+ case LDAP_RES_SEARCH_RESULT:
+ /* End of the story */
+
+ ret = ldap_parse_result(state->sh->ldap, reply->msg,
+ &result, NULL, &errmsg, NULL, NULL, 0);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(2, ("ldap_parse_result failed (%d)\n", state->msgid));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ DEBUG(3, ("Search result: %s(%d), %s\n",
+ ldap_err2string(result), result, errmsg));
+
+ subreq = sysdb_transaction_commit_send(state, state->ev,
+ state->handle);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ /* sysdb_transaction_complete will call tevent_req_done(req) */
+ tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
+ break;
+
+ default:
+ /* what is going on here !? */
+ tevent_req_error(req, EIO);
+ return;
+ }
+}
+
+static void sdap_get_initgr_fake_done(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *pvt);
+
+static void sdap_get_initgr_save_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_initgr_state *state = tevent_req_data(req,
+ struct sdap_get_initgr_state);
+ struct timeval tv = { 0, 0 };
+ struct tevent_timer *te;
+ int ret;
+
+ ret = sdap_save_group_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* unfortunately LDAP libraries consume everything sitting on the wire but
+ * do not give us a way to know if there is anything waiting to be read or
+ * or not. So schedule a fake fde event and wake up ourselves again. If we
+ * get a SDAP_RETRY it is fine. */
+
+ te = tevent_add_timer(state->ev, state, tv,
+ sdap_get_initgr_fake_done, req);
+ if (!te) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+}
+
+static void sdap_get_initgr_fake_done(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *pvt)
+{
+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+ struct sdap_get_initgr_state *state = tevent_req_data(req,
+ struct sdap_get_initgr_state);
+
+ sdap_get_initgr_done(state->ev, state->fde, 0, pvt);
+}
+
+
+int sdap_get_initgr_recv(struct tevent_req *req)
+{
+ enum tevent_req_state tstate;
+ uint64_t err;
+
+ if (tevent_req_is_error(req, &tstate, &err)) {
+ if (err) return err;
+ return EIO;
}
return EOK;
diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h
index 37c307a0..6ed95320 100644
--- a/server/providers/ldap/sdap_async.h
+++ b/server/providers/ldap/sdap_async.h
@@ -45,7 +45,6 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct sdap_options *opts,
bool use_start_tls);
-
int sdap_connect_recv(struct tevent_req *req,
TALLOC_CTX *memctx,
struct sdap_handle **sh);
@@ -58,7 +57,6 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
struct sdap_handle *sh,
const char **attrs,
const char *wildcard);
-
int sdap_get_users_recv(struct tevent_req *req);
struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
@@ -69,7 +67,6 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
struct sdap_handle *sh,
const char **attrs,
const char *wildcard);
-
int sdap_get_groups_recv(struct tevent_req *req);
struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
@@ -77,5 +74,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
struct sdap_handle *sh,
const char *user_dn,
const char *password);
-
int sdap_auth_recv(struct tevent_req *req, enum sdap_result *result);
+
+struct tevent_req *sdap_get_initgr_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 *name,
+ const char **grp_attrs);
+int sdap_get_initgr_recv(struct tevent_req *req);