diff options
Diffstat (limited to 'server/providers/ipa')
-rw-r--r-- | server/providers/ipa/ipa_access.c | 1823 | ||||
-rw-r--r-- | server/providers/ipa/ipa_access.h | 66 | ||||
-rw-r--r-- | server/providers/ipa/ipa_auth.c | 313 | ||||
-rw-r--r-- | server/providers/ipa/ipa_auth.h | 32 | ||||
-rw-r--r-- | server/providers/ipa/ipa_common.c | 597 | ||||
-rw-r--r-- | server/providers/ipa/ipa_common.h | 83 | ||||
-rw-r--r-- | server/providers/ipa/ipa_init.c | 293 | ||||
-rw-r--r-- | server/providers/ipa/ipa_timerules.c | 1186 | ||||
-rw-r--r-- | server/providers/ipa/ipa_timerules.h | 56 |
9 files changed, 0 insertions, 4449 deletions
diff --git a/server/providers/ipa/ipa_access.c b/server/providers/ipa/ipa_access.c deleted file mode 100644 index 7dfe1fd9..00000000 --- a/server/providers/ipa/ipa_access.c +++ /dev/null @@ -1,1823 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Access control - - Authors: - Sumit Bose <sbose@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <sys/param.h> -#include <security/pam_modules.h> - -#include "util/util.h" -#include "providers/ldap/sdap_async.h" -#include "providers/ipa/ipa_common.h" -#include "providers/ipa/ipa_access.h" -#include "providers/ipa/ipa_timerules.h" - -#define IPA_HOST_MEMBEROF "memberOf" -#define IPA_HOST_SERVERHOSTNAME "serverHostName" -#define IPA_HOST_FQDN "fqdn" -#define IPA_ACCESS_RULE_TYPE "accessRuleType" -#define IPA_MEMBER_USER "memberUser" -#define IPA_USER_CATEGORY "userCategory" -#define IPA_SERVICE_NAME "serviceName" -#define IPA_SOURCE_HOST "sourceHost" -#define IPA_SOURCE_HOST_CATEGORY "sourceHostCategory" -#define IPA_EXTERNAL_HOST "externalHost" -#define IPA_ACCESS_TIME "accessTime" -#define IPA_UNIQUE_ID "ipauniqueid" -#define IPA_ENABLED_FLAG "ipaenabledflag" -#define IPA_MEMBER_HOST "memberHost" -#define IPA_HOST_CATEGORY "hostCategory" -#define IPA_CN "cn" - -#define IPA_HOST_BASE_TMPL "cn=computers,cn=accounts,dc=%s" -#define IPA_HBAC_BASE_TMPL "cn=hbac,dc=%s" - -#define SYSDB_HBAC_BASE_TMPL "cn=hbac,"SYSDB_TMPL_CUSTOM_BASE - -#define HBAC_RULES_SUBDIR "hbac_rules" -#define HBAC_HOSTS_SUBDIR "hbac_hosts" - -static errno_t msgs2attrs_array(TALLOC_CTX *mem_ctx, size_t count, - struct ldb_message **msgs, - struct sysdb_attrs ***attrs) -{ - int i; - struct sysdb_attrs **a; - - a = talloc_array(mem_ctx, struct sysdb_attrs *, count); - if (a == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - return ENOMEM; - } - - for (i = 0; i < count; i++) { - a[i] = talloc(a, struct sysdb_attrs); - if (a[i] == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - talloc_free(a); - return ENOMEM; - } - a[i]->num = msgs[i]->num_elements; - a[i]->a = talloc_steal(a[i], msgs[i]->elements); - } - - *attrs = a; - - return EOK; -} - -static void ipa_access_reply(struct be_req *be_req, int pam_status) -{ - struct pam_data *pd; - pd = talloc_get_type(be_req->req_data, struct pam_data); - pd->pam_status = pam_status; - - if (pam_status == PAM_SUCCESS) { - be_req->fn(be_req, DP_ERR_OK, pam_status, NULL); - } else { - be_req->fn(be_req, DP_ERR_FATAL, pam_status, NULL); - } -} - -struct hbac_get_user_info_state { - struct tevent_context *ev; - struct be_ctx *be_ctx;; - struct sysdb_handle *handle; - - const char *user; - const char *user_orig_dn; - struct ldb_dn *user_dn; - size_t groups_count; - const char **groups; -}; - -static void search_user_done(struct tevent_req *subreq); -static void search_groups_done(struct tevent_req *subreq); - -struct tevent_req *hbac_get_user_info_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct be_ctx *be_ctx, - const char *user) -{ - struct tevent_req *req = NULL; - struct tevent_req *subreq = NULL; - struct hbac_get_user_info_state *state; - int ret; - const char **attrs; - - req = tevent_req_create(memctx, &state, struct hbac_get_user_info_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - state->be_ctx = be_ctx; - state->handle = NULL; - state->user = user; - state->user_orig_dn = NULL; - state->user_dn = NULL; - state->groups_count = 0; - state->groups = NULL; - - attrs = talloc_array(state, const char *, 2); - if (attrs == NULL) { - ret = ENOMEM; - goto fail; - } - - attrs[0] = SYSDB_ORIG_DN; - attrs[1] = NULL; - - subreq = sysdb_search_user_by_name_send(state, ev, be_ctx->sysdb, NULL, - be_ctx->domain, user, attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_search_user_by_name_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, search_user_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void search_user_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_user_info_state *state = tevent_req_data(req, - struct hbac_get_user_info_state); - int ret; - const char **attrs; - const char *dummy; - struct ldb_message *user_msg; - - - ret = sysdb_search_user_recv(subreq, state, &user_msg); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - DEBUG(9, ("Found user info for user [%s].\n", state->user)); - state->user_dn = talloc_steal(state, user_msg->dn); - dummy = ldb_msg_find_attr_as_string(user_msg, SYSDB_ORIG_DN, NULL); - if (dummy == NULL) { - DEBUG(1, ("Original DN of user [%s] not available.\n", state->user)); - ret = EINVAL; - goto failed; - } - state->user_orig_dn = talloc_strdup(state, dummy); - if (state->user_dn == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; - goto failed; - } - DEBUG(9, ("Found original DN [%s] for user [%s].\n", state->user_orig_dn, - state->user)); - - attrs = talloc_array(state, const char *, 2); - if (attrs == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - ret = ENOMEM; - goto failed; - } - attrs[0] = SYSDB_ORIG_DN; - attrs[1] = NULL; - - subreq = sysdb_asq_search_send(state, state->ev, state->be_ctx->sysdb, NULL, - state->be_ctx->domain, state->user_dn, NULL, - SYSDB_MEMBEROF, attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_asq_search_send failed.\n")); - ret = ENOMEM; - goto failed; - } - - tevent_req_set_callback(subreq, search_groups_done, req); - return; - -failed: - tevent_req_error(req, ret); - return; -} - -static void search_groups_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_user_info_state *state = tevent_req_data(req, - struct hbac_get_user_info_state); - int ret; - int i; - struct ldb_message **msg; - - ret = sysdb_asq_search_recv(subreq, state, &state->groups_count, &msg); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - if (state->groups_count == 0) { - tevent_req_done(req); - return; - } - - state->groups = talloc_array(state, const char *, state->groups_count); - if (state->groups == NULL) { - DEBUG(1, ("talloc_groups failed.\n")); - ret = ENOMEM; - goto failed; - } - - for(i = 0; i < state->groups_count; i++) { - if (msg[i]->num_elements != 1) { - DEBUG(1, ("Unexpected number of elements.\n")); - ret = EINVAL; - goto failed; - } - - if (msg[i]->elements[0].num_values != 1) { - DEBUG(1, ("Unexpected number of values.\n")); - ret = EINVAL; - goto failed; - } - - state->groups[i] = talloc_strndup(state->groups, - (const char *) msg[i]->elements[0].values[0].data, - msg[i]->elements[0].values[0].length); - if (state->groups[i] == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto failed; - } - - DEBUG(9, ("Found group [%s].\n", state->groups[i])); - } - - tevent_req_done(req); - return; - -failed: - talloc_free(state->groups); - tevent_req_error(req, ret); - return; -} - -static int hbac_get_user_info_recv(struct tevent_req *req, TALLOC_CTX *memctx, - const char **user_dn, size_t *groups_count, - const char ***groups) -{ - struct hbac_get_user_info_state *state = tevent_req_data(req, - struct hbac_get_user_info_state); - int i; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *user_dn = talloc_steal(memctx, state->user_orig_dn); - *groups_count = state->groups_count; - for (i = 0; i < state->groups_count; i++) { - talloc_steal(memctx, state->groups[i]); - } - *groups = talloc_steal(memctx, state->groups); - - return EOK; -} - - -struct hbac_get_host_info_state { - struct tevent_context *ev; - struct sdap_id_ctx *sdap_ctx; - struct sysdb_ctx *sysdb; - struct sysdb_handle *handle; - bool offline; - - char *host_filter; - char *host_search_base; - const char **host_attrs; - - struct sysdb_attrs **host_reply_list; - size_t host_reply_count; - size_t current_item; - struct hbac_host_info **hbac_host_info; -}; - -static void hbac_get_host_info_connect_done(struct tevent_req *subreq); -static void hbac_get_host_memberof_done(struct tevent_req *subreq); -static void hbac_get_host_info_sysdb_transaction_started(struct tevent_req *subreq); -static void hbac_get_host_info_store_prepare(struct tevent_req *req); -static void hbac_get_host_info_store_done(struct tevent_req *subreq); - -static struct tevent_req *hbac_get_host_info_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - bool offline, - struct sdap_id_ctx *sdap_ctx, - struct sysdb_ctx *sysdb, - const char *ipa_domain, - const char **hostnames) -{ - struct tevent_req *req = NULL; - struct tevent_req *subreq = NULL; - struct hbac_get_host_info_state *state; - int ret; - int i; - - if (hostnames == NULL || ipa_domain == NULL) { - DEBUG(1, ("Missing hostnames or domain.\n")); - return NULL; - } - - req = tevent_req_create(memctx, &state, struct hbac_get_host_info_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - state->sdap_ctx = sdap_ctx; - state->sysdb = sysdb; - state->handle = NULL; - state->offline = offline; - - state->host_reply_list = NULL; - state->host_reply_count = 0; - state->current_item = 0; - state->hbac_host_info = NULL; - - state->host_filter = talloc_asprintf(state, "(|"); - if (state->host_filter == NULL) { - DEBUG(1, ("Failed to create filter.\n")); - ret = ENOMEM; - goto fail; - } - for (i = 0; hostnames[i] != NULL; i++) { - state->host_filter = talloc_asprintf_append(state->host_filter, - "(&(objectclass=ipaHost)" - "(|(fqdn=%s)(serverhostname=%s)))", - hostnames[i], hostnames[i]); - if (state->host_filter == NULL) { - ret = ENOMEM; - goto fail; - } - } - state->host_filter = talloc_asprintf_append(state->host_filter, ")"); - if (state->host_filter == NULL) { - ret = ENOMEM; - goto fail; - } - - state->host_search_base = talloc_asprintf(state, IPA_HOST_BASE_TMPL, - ipa_domain); - if (state->host_search_base == NULL) { - DEBUG(1, ("Failed to create host search base.\n")); - ret = ENOMEM; - goto fail; - } - - state->host_attrs = talloc_array(state, const char *, 7); - if (state->host_attrs == NULL) { - DEBUG(1, ("Failed to allocate host attribute list.\n")); - ret = ENOMEM; - goto fail; - } - state->host_attrs[0] = IPA_HOST_MEMBEROF; - state->host_attrs[1] = IPA_HOST_SERVERHOSTNAME; - state->host_attrs[2] = IPA_HOST_FQDN; - state->host_attrs[3] = "objectClass"; - state->host_attrs[4] = SYSDB_ORIG_DN; - state->host_attrs[5] = SYSDB_ORIG_MEMBEROF; - state->host_attrs[6] = NULL; - - if (offline) { - subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL, - state->sdap_ctx->be->domain, - state->host_filter, HBAC_HOSTS_SUBDIR, - state->host_attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_search_custom_send.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_memberof_done, req); - - return req; - } - - if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) { - if (sdap_ctx->gsh != NULL) { - talloc_zfree(sdap_ctx->gsh); - } - - subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts, - sdap_ctx->be, sdap_ctx->service, NULL); - if (!subreq) { - DEBUG(1, ("sdap_cli_connect_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_info_connect_done, req); - - return req; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->host_search_base, - LDAP_SCOPE_SUB, - state->host_filter, - state->host_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_memberof_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void hbac_get_host_info_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh, - NULL); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->host_search_base, - LDAP_SCOPE_SUB, - state->host_filter, - state->host_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_memberof_done, req); - - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_get_host_memberof_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - int i; - int v; - struct ldb_message_element *el; - struct hbac_host_info **hhi; - struct ldb_message **msgs; - - if (state->offline) { - ret = sysdb_search_custom_recv(subreq, state, &state->host_reply_count, - &msgs); - } else { - ret = sdap_get_generic_recv(subreq, state, &state->host_reply_count, - &state->host_reply_list); - } - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - if (state->host_reply_count == 0) { - DEBUG(1, ("No hosts not found in IPA server.\n")); - ret = ENOENT; - goto fail; - } - - if (state->offline) { - ret = msgs2attrs_array(state, state->host_reply_count, msgs, - &state->host_reply_list); - talloc_zfree(msgs); - if (ret != EOK) { - DEBUG(1, ("msgs2attrs_array failed.\n")); - goto fail; - } - } - - hhi = talloc_array(state, struct hbac_host_info *, state->host_reply_count + 1); - if (hhi == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - ret = ENOMEM; - goto fail; - } - memset(hhi, 0, - sizeof(struct hbac_host_info *) * (state->host_reply_count + 1)); - - for (i = 0; i < state->host_reply_count; i++) { - hhi[i] = talloc_zero(hhi, struct hbac_host_info); - if (hhi[i] == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], SYSDB_ORIG_DN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - DEBUG(9, ("OriginalDN: [%.*s].\n", el->values[0].length, - (char *)el->values[0].data)); - hhi[i]->dn = talloc_strndup(hhi, (char *)el->values[0].data, - el->values[0].length); - if (hhi[i]->dn == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], - IPA_HOST_SERVERHOSTNAME, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - DEBUG(9, ("ServerHostName: [%.*s].\n", el->values[0].length, - (char *)el->values[0].data)); - hhi[i]->serverhostname = talloc_strndup(hhi, (char *)el->values[0].data, - el->values[0].length); - if (hhi[i]->serverhostname == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], - IPA_HOST_FQDN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - DEBUG(9, ("FQDN: [%.*s].\n", el->values[0].length, - (char *)el->values[0].data)); - hhi[i]->fqdn = talloc_strndup(hhi, (char *)el->values[0].data, - el->values[0].length); - if (hhi[i]->fqdn == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], - state->offline ? SYSDB_ORIG_MEMBEROF : - IPA_HOST_MEMBEROF, - &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - - hhi[i]->memberof = talloc_array(hhi, const char *, el->num_values + 1); - if (hhi[i]->memberof == NULL) { - ret = ENOMEM; - goto fail; - } - memset(hhi[i]->memberof, 0, - sizeof(const char *) * (el->num_values + 1)); - - for(v = 0; v < el->num_values; v++) { - DEBUG(9, ("%s: [%.*s].\n", IPA_HOST_MEMBEROF, el->values[v].length, - (const char *)el->values[v].data)); - hhi[i]->memberof[v] = talloc_strndup(hhi, - (const char *)el->values[v].data, - el->values[v].length); - if (hhi[i]->memberof[v] == NULL) { - ret = ENOMEM; - goto fail; - } - } - } - - state->hbac_host_info = hhi; - - if (state->offline) { - tevent_req_done(req); - return; - } - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, hbac_get_host_info_sysdb_transaction_started, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_get_host_info_sysdb_transaction_started( - struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item = 0; - hbac_get_host_info_store_prepare(req); - return; -} - -static void hbac_get_host_info_store_prepare(struct tevent_req *req) -{ - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - char *object_name; - struct ldb_message_element *el; - struct tevent_req *subreq; - - if (state->current_item < state->host_reply_count) { - ret = sysdb_attrs_get_el(state->host_reply_list[state->current_item], - IPA_HOST_FQDN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - object_name = talloc_strndup(state, (const char *)el->values[0].data, - el->values[0].length); - if (object_name == NULL) { - ret = ENOMEM; - goto fail; - } - DEBUG(9, ("Fqdn [%s].\n", object_name)); - - - ret = sysdb_attrs_replace_name( - state->host_reply_list[state->current_item], - IPA_HOST_MEMBEROF, SYSDB_ORIG_MEMBEROF); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_replace_name failed.\n")); - goto fail; - } - - subreq = sysdb_store_custom_send(state, state->ev, - state->handle, - state->sdap_ctx->be->domain, - object_name, - HBAC_HOSTS_SUBDIR, - state->host_reply_list[state->current_item]); - - if (subreq == NULL) { - DEBUG(1, ("sysdb_store_custom_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_info_store_done, req); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_commit_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_get_host_info_store_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - - ret = sysdb_store_custom_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item++; - hbac_get_host_info_store_prepare(req); -} - -static int hbac_get_host_info_recv(struct tevent_req *req, TALLOC_CTX *memctx, - struct hbac_host_info ***hhi) -{ - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *hhi = talloc_steal(memctx, state->hbac_host_info); - return EOK; -} - - -struct hbac_get_rules_state { - struct tevent_context *ev; - struct sdap_id_ctx *sdap_ctx; - struct sysdb_ctx *sysdb; - struct sysdb_handle *handle; - bool offline; - - const char *host_dn; - const char **memberof; - char *hbac_filter; - char *hbac_search_base; - const char **hbac_attrs; - - struct ldb_message *old_rules; - struct sysdb_attrs **hbac_reply_list; - size_t hbac_reply_count; - int current_item; -}; - -static void hbac_get_rules_connect_done(struct tevent_req *subreq); -static void hbac_rule_get_done(struct tevent_req *subreq); -static void hbac_rule_sysdb_transaction_started(struct tevent_req *subreq); -static void hbac_rule_sysdb_delete_done(struct tevent_req *subreq); -static void hbac_rule_store_prepare(struct tevent_req *req); -static void hbac_rule_store_done(struct tevent_req *subreq); - -static struct tevent_req *hbac_get_rules_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - bool offline, - struct sdap_id_ctx *sdap_ctx, - struct sysdb_ctx *sysdb, - const char *ipa_domain, - const char *host_dn, - const char **memberof) -{ - struct tevent_req *req = NULL; - struct tevent_req *subreq = NULL; - struct hbac_get_rules_state *state; - int ret; - int i; - - if (host_dn == NULL || ipa_domain == NULL) { - DEBUG(1, ("Missing host_dn or domain.\n")); - return NULL; - } - - req = tevent_req_create(memctx, &state, struct hbac_get_rules_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - state->offline = offline; - state->sdap_ctx = sdap_ctx; - state->sysdb = sysdb; - state->handle = NULL; - state->host_dn = host_dn; - state->memberof = memberof; - - state->old_rules = NULL; - state->hbac_reply_list = NULL; - state->hbac_reply_count = 0; - state->current_item = 0; - - state->hbac_search_base = talloc_asprintf(state, IPA_HBAC_BASE_TMPL, - ipa_domain); - if (state->hbac_search_base == NULL) { - DEBUG(1, ("Failed to create HBAC search base.\n")); - ret = ENOMEM; - goto fail; - } - - state->hbac_attrs = talloc_array(state, const char *, 16); - if (state->hbac_attrs == NULL) { - DEBUG(1, ("Failed to allocate HBAC attribute list.\n")); - ret = ENOMEM; - goto fail; - } - state->hbac_attrs[0] = IPA_ACCESS_RULE_TYPE; - state->hbac_attrs[1] = IPA_MEMBER_USER; - state->hbac_attrs[2] = IPA_USER_CATEGORY; - state->hbac_attrs[3] = IPA_SERVICE_NAME; - state->hbac_attrs[4] = IPA_SOURCE_HOST; - state->hbac_attrs[5] = IPA_SOURCE_HOST_CATEGORY; - state->hbac_attrs[6] = IPA_EXTERNAL_HOST; - state->hbac_attrs[7] = IPA_ACCESS_TIME; - state->hbac_attrs[8] = IPA_UNIQUE_ID; - state->hbac_attrs[9] = IPA_ENABLED_FLAG; - state->hbac_attrs[10] = IPA_CN; - state->hbac_attrs[11] = "objectclass"; - state->hbac_attrs[12] = IPA_MEMBER_HOST; - state->hbac_attrs[13] = IPA_HOST_CATEGORY; - state->hbac_attrs[14] = SYSDB_ORIG_DN; - state->hbac_attrs[15] = NULL; - - state->hbac_filter = talloc_asprintf(state, - "(&(objectclass=ipaHBACRule)" - "(|(%s=%s)(%s=%s)", - IPA_HOST_CATEGORY, "all", - IPA_MEMBER_HOST, host_dn); - if (state->hbac_filter == NULL) { - ret = ENOMEM; - goto fail; - } - for (i = 0; memberof[i] != NULL; i++) { - state->hbac_filter = talloc_asprintf_append(state->hbac_filter, - "(%s=%s)", - IPA_MEMBER_HOST, - memberof[i]); - if (state->hbac_filter == NULL) { - ret = ENOMEM; - goto fail; - } - } - state->hbac_filter = talloc_asprintf_append(state->hbac_filter, "))"); - if (state->hbac_filter == NULL) { - ret = ENOMEM; - goto fail; - } - - DEBUG(9, ("HBAC rule filter: [%s].\n", state->hbac_filter)); - - if (offline) { - subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL, - state->sdap_ctx->be->domain, - state->hbac_filter, HBAC_RULES_SUBDIR, - state->hbac_attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_search_custom_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_get_done, req); - - return req; - } - - if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) { - if (sdap_ctx->gsh != NULL) { - talloc_zfree(sdap_ctx->gsh); - } - - subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts, - sdap_ctx->be, sdap_ctx->service, NULL); - if (!subreq) { - DEBUG(1, ("sdap_cli_connect_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_rules_connect_done, req); - - return req; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->hbac_search_base, - LDAP_SCOPE_SUB, - state->hbac_filter, - state->hbac_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_get_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void hbac_get_rules_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh, - NULL); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->hbac_search_base, - LDAP_SCOPE_SUB, - state->hbac_filter, - state->hbac_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_get_done, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_get_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - int i; - struct ldb_message_element *el; - struct ldb_message **msgs; - - if (state->offline) { - ret = sysdb_search_custom_recv(subreq, state, &state->hbac_reply_count, - &msgs); - } else { - ret = sdap_get_generic_recv(subreq, state, &state->hbac_reply_count, - &state->hbac_reply_list); - } - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - if (state->offline) { - ret = msgs2attrs_array(state, state->hbac_reply_count, msgs, - &state->hbac_reply_list); - talloc_zfree(msgs); - if (ret != EOK) { - DEBUG(1, ("msgs2attrs_array failed.\n")); - goto fail; - } - } - - for (i = 0; i < state->hbac_reply_count; i++) { - ret = sysdb_attrs_get_el(state->hbac_reply_list[i], SYSDB_ORIG_DN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - DEBUG(1, ("Missing original DN.\n")); - ret = EINVAL; - goto fail; - } - DEBUG(9, ("OriginalDN: [%s].\n", (const char *)el->values[0].data)); - } - - if (state->hbac_reply_count == 0 || state->offline) { - tevent_req_done(req); - return; - } - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, hbac_rule_sysdb_transaction_started, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_sysdb_transaction_started(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - struct ldb_dn *hbac_base_dn; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - hbac_base_dn = sysdb_custom_subtree_dn(state->sysdb, state, - state->sdap_ctx->be->domain->name, - HBAC_RULES_SUBDIR); - if (hbac_base_dn == NULL) { - ret = ENOMEM; - goto fail; - } - subreq = sysdb_delete_recursive_send(state, state->ev, state->handle, - hbac_base_dn, true); - if (subreq == NULL) { - DEBUG(1, ("sysdb_delete_recursive_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, hbac_rule_sysdb_delete_done, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_sysdb_delete_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - - ret = sysdb_delete_recursive_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item = 0; - hbac_rule_store_prepare(req); -} - -static void hbac_rule_store_prepare(struct tevent_req *req) -{ - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - struct ldb_message_element *el; - struct tevent_req *subreq; - char *object_name; - - if (state->current_item < state->hbac_reply_count) { - - ret = sysdb_attrs_get_el(state->hbac_reply_list[state->current_item], - IPA_UNIQUE_ID, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - object_name = talloc_strndup(state, (const char *)el->values[0].data, - el->values[0].length); - if (object_name == NULL) { - ret = ENOMEM; - goto fail; - } - DEBUG(9, ("IPAUniqueId: [%s].\n", object_name)); - - subreq = sysdb_store_custom_send(state, state->ev, - state->handle, - state->sdap_ctx->be->domain, - object_name, - HBAC_RULES_SUBDIR, - state->hbac_reply_list[state->current_item]); - - if (subreq == NULL) { - DEBUG(1, ("sysdb_store_custom_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_store_done, req); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_commit_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_store_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - - ret = sysdb_store_custom_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item++; - hbac_rule_store_prepare(req); -} - -static int hbac_get_rules_recv(struct tevent_req *req, TALLOC_CTX *memctx, - size_t *hbac_rule_count, - struct sysdb_attrs ***hbac_rule_list) -{ - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int i; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *hbac_rule_count = state->hbac_reply_count; - *hbac_rule_list = talloc_steal(memctx, state->hbac_reply_list); - for (i = 0; i < state->hbac_reply_count; i++) { - talloc_steal(memctx, state->hbac_reply_list[i]); - } - return EOK; -} - -enum hbac_result { - HBAC_ALLOW = 1, - HBAC_DENY, - HBAC_NOT_APPLICABLE -}; - -enum check_result { - RULE_APPLICABLE = 0, - RULE_NOT_APPLICABLE, - RULE_ERROR -}; - -enum check_result check_service(struct pam_data *pd, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - struct ldb_message_element *el; - - if (pd->service == NULL) { - DEBUG(1, ("No service in pam data, assuming error.\n")); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_SERVICE_NAME, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("No services in rule specified, assuming rule applies.\n")); - return RULE_APPLICABLE; - } else { - for (i = 0; i < el->num_values; i++) { - if (strncasecmp(pd->service, (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("Service [%s] found, rule applies.\n", - pd->service)); - return RULE_APPLICABLE; - } - } - DEBUG(9, ("No matching service found, rule does not apply.\n")); - return RULE_NOT_APPLICABLE; - } - - return RULE_ERROR; -} - -enum check_result check_access_time(struct time_rules_ctx *tr_ctx, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - TALLOC_CTX *tmp_ctx = NULL; - struct ldb_message_element *el; - char *rule; - time_t now; - bool result; - - now = time(NULL); - if (now == (time_t) -1) { - DEBUG(1, ("time failed [%d][%s].\n", errno, strerror(errno))); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESS_TIME, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("No access time specified, assuming rule applies.\n")); - return RULE_APPLICABLE; - } else { - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(1, ("talloc_new failed.\n")); - return RULE_ERROR; - } - - for (i = 0; i < el->num_values; i++) { - rule = talloc_strndup(tmp_ctx, (const char *) el->values[i].data, - el->values[i].length); - ret = check_time_rule(tmp_ctx, tr_ctx, rule, now, &result); - if (ret != EOK) { - DEBUG(1, ("check_time_rule failed.\n")); - ret = RULE_ERROR; - goto done; - } - - if (result) { - DEBUG(9, ("Current time [%d] matches rule [%s].\n", now, rule)); - ret = RULE_APPLICABLE; - goto done; - } - } - } - - ret = RULE_NOT_APPLICABLE; - -done: - talloc_free(tmp_ctx); - return ret; -} - -enum check_result check_user(struct hbac_ctx *hbac_ctx, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - int g; - struct ldb_message_element *el; - - if (hbac_ctx->user_dn == NULL) { - DEBUG(1, ("No user DN available, this should never happen.\n")); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_USER_CATEGORY, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("USer category is not set.\n")); - } else { - for (i = 0; i < el->num_values; i++) { - if (strncasecmp("all", (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("User category is set to 'all', rule applies.\n")); - return RULE_APPLICABLE; - } - DEBUG(9, ("Unsupported user category [%.*s].\n", - el->values[i].length, - (char *) el->values[i].data)); - } - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_MEMBER_USER, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("No user specified, rule does not apply.\n")); - return RULE_APPLICABLE; - } else { - for (i = 0; i < el->num_values; i++) { - DEBUG(9, ("Searching matches for [%.*s].\n", el->values[i].length, - (const char *) el->values[i].data)); - DEBUG(9, ("Checking user [%s].\n", hbac_ctx->user_dn)); - if (strncmp(hbac_ctx->user_dn, (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("User [%s] found, rule applies.\n", - hbac_ctx->user_dn)); - return RULE_APPLICABLE; - } - - for (g = 0; g < hbac_ctx->groups_count; g++) { - DEBUG(9, ("Checking group [%s].\n", hbac_ctx->groups[g])); - if (strncmp(hbac_ctx->groups[g], - (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("Group [%s] found, rule applies.\n", - hbac_ctx->groups[g])); - return RULE_APPLICABLE; - } - } - } - DEBUG(9, ("No matching user found, rule does not apply.\n")); - return RULE_NOT_APPLICABLE; - } - - return RULE_ERROR; -} - -enum check_result check_remote_hosts(const char *rhost, - struct hbac_host_info *hhi, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - int m; - struct ldb_message_element *cat_el; - struct ldb_message_element *src_el; - struct ldb_message_element *ext_el; - - if (hhi == NULL && (rhost == NULL || *rhost == '\0')) { - DEBUG(1, ("No remote host information specified, assuming error.\n")); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_SOURCE_HOST_CATEGORY, &cat_el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (cat_el->num_values == 0) { - DEBUG(9, ("Source host category not set.\n")); - } else { - for(i = 0; i < cat_el->num_values; i++) { - if (strncasecmp("all", (const char *) cat_el->values[i].data, - cat_el->values[i].length) == 0) { - DEBUG(9, ("Source host category is set to 'all', " - "rule applies.\n")); - return RULE_APPLICABLE; - } - DEBUG(9, ("Unsupported source hosts category [%.*s].\n", - cat_el->values[i].length, - (char *) cat_el->values[i].data)); - } - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_SOURCE_HOST, &src_el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - ret = sysdb_attrs_get_el(rule_attrs, IPA_EXTERNAL_HOST, &ext_el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - - if (src_el->num_values == 0 && ext_el->num_values == 0) { - DEBUG(9, ("No remote host specified in rule, rule does not apply.\n")); - return RULE_NOT_APPLICABLE; - } else { - if (hhi != NULL) { - for (i = 0; i < src_el->num_values; i++) { - if (strncasecmp(hhi->dn, (const char *) src_el->values[i].data, - src_el->values[i].length) == 0) { - DEBUG(9, ("Source host [%s] found, rule applies.\n", - hhi->dn)); - return RULE_APPLICABLE; - } - for (m = 0; hhi->memberof[m] != NULL; m++) { - if (strncasecmp(hhi->memberof[m], - (const char *) src_el->values[i].data, - src_el->values[i].length) == 0) { - DEBUG(9, ("Source host group [%s] found, rule applies.\n", - hhi->memberof[m])); - return RULE_APPLICABLE; - } - } - } - } - - if (rhost != NULL && *rhost != '\0') { - for (i = 0; i < ext_el->num_values; i++) { - if (strncasecmp(rhost, (const char *) ext_el->values[i].data, - ext_el->values[i].length) == 0) { - DEBUG(9, ("External host [%s] found, rule applies.\n", - rhost)); - return RULE_APPLICABLE; - } - } - } - DEBUG(9, ("No matching remote host found.\n")); - return RULE_NOT_APPLICABLE; - } - - return RULE_ERROR; -} - -static errno_t check_if_rule_applies(enum hbac_result *result, - struct hbac_ctx *hbac_ctx, - struct sysdb_attrs *rule_attrs) { - int ret; - struct ldb_message_element *el; - enum hbac_result rule_type; - char *rule_name; - struct pam_data *pd = hbac_ctx->pd; - - ret = sysdb_attrs_get_el(rule_attrs, IPA_CN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return ret; - } - if (el->num_values == 0) { - DEBUG(4, ("rule has no name, assuming '(none)'.\n")); - rule_name = talloc_strdup(rule_attrs, "(none)"); - } else { - rule_name = talloc_strndup(rule_attrs, (const char*) el->values[0].data, - el->values[0].length); - } - if (rule_name == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - return ENOMEM; - } - DEBUG(9, ("Processsing rule [%s].\n", rule_name)); - - /* rule type */ - ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESS_RULE_TYPE, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return ret; - } - if (el->num_values == 0) { - DEBUG(4, ("rule has no type, assuming 'deny'.\n")); - rule_type = HBAC_DENY; - } else if (el->num_values == 1) { - if (strncasecmp((const char *) el->values[0].data, "allow", - el->values[0].length) == 0) { - rule_type = HBAC_ALLOW; - } else { - rule_type = HBAC_DENY; - } - } else { - DEBUG(1, ("rule has an unsupported number of values [%d].\n", - el->num_values)); - return EINVAL; - } - - ret = check_service(pd, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - ret = check_user(hbac_ctx, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - ret = check_access_time(hbac_ctx->tr_ctx, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - ret = check_remote_hosts(pd->rhost, hbac_ctx->remote_hhi, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - *result = rule_type; - - return EOK; - -not_applicable: - if (ret == RULE_NOT_APPLICABLE) { - *result = HBAC_NOT_APPLICABLE; - } else { - *result = HBAC_DENY; - } - return EOK; -} - -static int evaluate_ipa_hbac_rules(struct hbac_ctx *hbac_ctx, - bool *access_allowed) -{ - bool allow_matched = false; - enum hbac_result result; - int ret; - int i; - - *access_allowed = false; - - for (i = 0; i < hbac_ctx->hbac_rule_count ; i++) { - - ret = check_if_rule_applies(&result, hbac_ctx, - hbac_ctx->hbac_rule_list[i]); - if (ret != EOK) { - DEBUG(1, ("check_if_rule_applies failed.\n")); - return ret; - } - - switch (result) { - case HBAC_DENY: - DEBUG(3, ("Access denied by single rule.\n")); - return EOK; - break; - case HBAC_ALLOW: - allow_matched = true; - DEBUG(9, ("Current rule allows access.\n")); - break; - default: - DEBUG(9, ("Current rule does not apply.\n")); - } - - } - - *access_allowed = allow_matched; - - return EOK; -} - -static void hbac_get_host_info_done(struct tevent_req *req); -static void hbac_get_rules_done(struct tevent_req *req); -static void hbac_get_user_info_done(struct tevent_req *req); - -void ipa_access_handler(struct be_req *be_req) -{ - struct tevent_req *req; - struct pam_data *pd; - struct hbac_ctx *hbac_ctx; - int pam_status = PAM_SYSTEM_ERR; - struct ipa_access_ctx *ipa_access_ctx; - const char *hostlist[3]; - - pd = talloc_get_type(be_req->req_data, struct pam_data); - - hbac_ctx = talloc_zero(be_req, struct hbac_ctx); - if (hbac_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - goto fail; - } - hbac_ctx->be_req = be_req; - hbac_ctx->pd = pd; - ipa_access_ctx = talloc_get_type( - be_req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data, - struct ipa_access_ctx); - hbac_ctx->sdap_ctx = ipa_access_ctx->sdap_ctx; - hbac_ctx->ipa_options = ipa_access_ctx->ipa_options; - hbac_ctx->tr_ctx = ipa_access_ctx->tr_ctx; - hbac_ctx->offline = be_is_offline(be_req->be_ctx); - - DEBUG(9, ("Connection status is [%s].\n", hbac_ctx->offline ? "offline" : - "online")); - - - hostlist[0] = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME); - if (hostlist[0] == NULL) { - DEBUG(1, ("ipa_hostname not available.\n")); - goto fail; - } - if (pd->rhost != NULL && *pd->rhost != '\0') { - hostlist[1] = pd->rhost; - } else { - hostlist[1] = NULL; - pd->rhost = dp_opt_get_string(hbac_ctx->ipa_options, IPA_HOSTNAME); - if (pd->rhost == NULL) { - DEBUG(1, ("ipa_hostname not available.\n")); - goto fail; - } - } - hostlist[2] = NULL; - - req = hbac_get_host_info_send(hbac_ctx, be_req->be_ctx->ev, - hbac_ctx->offline, - hbac_ctx->sdap_ctx, be_req->be_ctx->sysdb, - dp_opt_get_string(hbac_ctx->ipa_options, - IPA_DOMAIN), - hostlist); - if (req == NULL) { - DEBUG(1, ("hbac_get_host_info_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, hbac_get_host_info_done, hbac_ctx); - return; - -fail: - ipa_access_reply(be_req, pam_status); -} - -static void hbac_get_host_info_done(struct tevent_req *req) -{ - struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx); - struct be_req *be_req = hbac_ctx->be_req; - int ret; - int pam_status = PAM_SYSTEM_ERR; - const char *ipa_hostname; - struct hbac_host_info *local_hhi = NULL; - int i; - - ret = hbac_get_host_info_recv(req, hbac_ctx, &hbac_ctx->hbac_host_info); - talloc_zfree(req); - if (ret != EOK) { - goto fail; - } - - ipa_hostname = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME); - if (ipa_hostname == NULL) { - DEBUG(1, ("Missing ipa_hostname, this should never happen.\n")); - ret = EINVAL; - goto fail; - } - - for (i = 0; hbac_ctx->hbac_host_info[i] != NULL; i++) { - if (strcmp(hbac_ctx->hbac_host_info[i]->fqdn, ipa_hostname) == 0 || - strcmp(hbac_ctx->hbac_host_info[i]->serverhostname, - ipa_hostname) == 0) { - local_hhi = hbac_ctx->hbac_host_info[i]; - } - if (hbac_ctx->pd->rhost != NULL && *hbac_ctx->pd->rhost != '\0') { - if (strcmp(hbac_ctx->hbac_host_info[i]->fqdn, - hbac_ctx->pd->rhost) == 0 || - strcmp(hbac_ctx->hbac_host_info[i]->serverhostname, - hbac_ctx->pd->rhost) == 0) { - hbac_ctx->remote_hhi = hbac_ctx->hbac_host_info[i]; - } - } - } - if (local_hhi == NULL) { - DEBUG(1, ("Missing host info for [%s].\n", ipa_hostname)); - ret = EINVAL; - goto fail; - } - req = hbac_get_rules_send(hbac_ctx, be_req->be_ctx->ev, hbac_ctx->offline, - hbac_ctx->sdap_ctx, be_req->be_ctx->sysdb, - dp_opt_get_string(hbac_ctx->ipa_options, - IPA_DOMAIN), - local_hhi->dn, local_hhi->memberof); - if (req == NULL) { - DEBUG(1, ("hbac_get_rules_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, hbac_get_rules_done, hbac_ctx); - return; - -fail: - ipa_access_reply(be_req, pam_status); -} - -static void hbac_get_rules_done(struct tevent_req *req) -{ - struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx); - struct pam_data *pd = hbac_ctx->pd; - struct be_req *be_req = hbac_ctx->be_req; - int ret; - int pam_status = PAM_SYSTEM_ERR; - - ret = hbac_get_rules_recv(req, hbac_ctx, &hbac_ctx->hbac_rule_count, - &hbac_ctx->hbac_rule_list); - talloc_zfree(req); - if (ret != EOK) { - goto fail; - } - - req = hbac_get_user_info_send(hbac_ctx, be_req->be_ctx->ev, be_req->be_ctx, - pd->user); - if (req == NULL) { - DEBUG(1, ("hbac_get_user_info_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, hbac_get_user_info_done, hbac_ctx); - return; - -fail: - ipa_access_reply(be_req, pam_status); -} - -static void hbac_get_user_info_done(struct tevent_req *req) -{ - struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx); - struct be_req *be_req = hbac_ctx->be_req; - int ret; - int pam_status = PAM_SYSTEM_ERR; - bool access_allowed = false; - - ret = hbac_get_user_info_recv(req, hbac_ctx, &hbac_ctx->user_dn, - &hbac_ctx->groups_count, - &hbac_ctx->groups); - talloc_zfree(req); - if (ret != EOK) { - goto failed; - } - - ret = evaluate_ipa_hbac_rules(hbac_ctx, &access_allowed); - if (ret != EOK) { - DEBUG(1, ("evaluate_ipa_hbac_rules failed.\n")); - goto failed; - } - - if (access_allowed) { - pam_status = PAM_SUCCESS; - DEBUG(5, ("Access allowed.\n")); - } else { - pam_status = PAM_PERM_DENIED; - DEBUG(3, ("Access denied.\n")); - } - -failed: - ipa_access_reply(be_req, pam_status); -} diff --git a/server/providers/ipa/ipa_access.h b/server/providers/ipa/ipa_access.h deleted file mode 100644 index bd221c57..00000000 --- a/server/providers/ipa/ipa_access.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Access control - - Authors: - Sumit Bose <sbose@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _IPA_ACCESS_H_ -#define _IPA_ACCESS_H_ - -#include "providers/ldap/ldap_common.h" - -enum ipa_access_mode { - IPA_ACCESS_DENY = 0, - IPA_ACCESS_ALLOW -}; - -struct hbac_host_info { - const char *fqdn; - const char *serverhostname; - const char *dn; - const char **memberof; -}; - -struct ipa_access_ctx { - struct sdap_id_ctx *sdap_ctx; - struct dp_option *ipa_options; - struct time_rules_ctx *tr_ctx; -}; - -struct hbac_ctx { - struct sdap_id_ctx *sdap_ctx; - struct dp_option *ipa_options; - struct time_rules_ctx *tr_ctx; - struct be_req *be_req; - struct pam_data *pd; - struct hbac_host_info **hbac_host_info; - struct hbac_host_info *remote_hhi; - struct sysdb_attrs **hbac_rule_list; - size_t hbac_rule_count; - const char *user_dn; - size_t groups_count; - const char **groups; - bool offline; -}; - -void ipa_access_handler(struct be_req *be_req); - -#endif /* _IPA_ACCESS_H_ */ diff --git a/server/providers/ipa/ipa_auth.c b/server/providers/ipa/ipa_auth.c deleted file mode 100644 index 86b72e49..00000000 --- a/server/providers/ipa/ipa_auth.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Authentication - - Authors: - Sumit Bose <sbose@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <sys/param.h> -#include <security/pam_modules.h> - -#include "util/util.h" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/ipa/ipa_common.h" - -struct ipa_auth_ctx { - struct sdap_auth_ctx *sdap_auth_ctx; - struct krb5_ctx *krb5_ctx; - struct be_req *be_req; - be_async_callback_t callback; - void *pvt; - bool password_migration; - - int dp_err_type; - int errnum; - char *errstr; -}; - -static void ipa_auth_reply(struct ipa_auth_ctx *ipa_auth_ctx) -{ - struct pam_data *pd; - struct be_req *be_req = ipa_auth_ctx->be_req; - be_req->fn = ipa_auth_ctx->callback; - be_req->pvt = ipa_auth_ctx->pvt; - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx; - pd = talloc_get_type(be_req->req_data, struct pam_data); - int dp_err_type = ipa_auth_ctx->dp_err_type; - char *errstr = ipa_auth_ctx->errstr; - - talloc_zfree(ipa_auth_ctx); - DEBUG(9, ("sending [%d] [%d] [%s].\n", dp_err_type, pd->pam_status, - errstr)); - - be_req->fn(be_req, dp_err_type, pd->pam_status, errstr); -} - -struct ipa_auth_handler_state { - struct tevent_context *ev; - - int dp_err_type; - int errnum; - char *errstr; -}; - -static void ipa_auth_handler_callback(struct be_req *be_req, - int dp_err_type, - int errnum, - const char *errstr); - -static struct tevent_req *ipa_auth_handler_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct be_req *be_req, - be_req_fn_t auth_handler) -{ - struct ipa_auth_handler_state *state; - struct tevent_req *req; - - req = tevent_req_create(memctx, &state, struct ipa_auth_handler_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - - be_req->fn = ipa_auth_handler_callback; - be_req->pvt = req; - - auth_handler(be_req); - - return req; -} - -static void ipa_auth_handler_callback(struct be_req *be_req, - int dp_err_type, - int errnum, - const char *errstr) -{ - struct tevent_req *req = talloc_get_type(be_req->pvt, struct tevent_req); - struct ipa_auth_handler_state *state = tevent_req_data(req, - struct ipa_auth_handler_state); - - DEBUG(9, ("received from handler [%d] [%d] [%s].\n", dp_err_type, errnum, - errstr)); - state->dp_err_type = dp_err_type; - state->errnum = errnum; - state->errstr = talloc_strdup(state, errstr); - - tevent_req_post(req, state->ev); - tevent_req_done(req); - return; -} - -static int ipa_auth_handler_recv(struct tevent_req *req, TALLOC_CTX *memctx, - int *dp_err_type, int *errnum, - char **errstr) -{ - struct ipa_auth_handler_state *state = tevent_req_data(req, - struct ipa_auth_handler_state); - enum tevent_req_state tstate; - uint64_t err; - - if (tevent_req_is_error(req, &tstate, &err)) { - if (err) return err; - return EIO; - } - - *dp_err_type = state->dp_err_type; - *errnum = state->errnum; - *errstr = talloc_steal(memctx, state->errstr); - - return EOK; -} - - -static void ipa_auth_handler_done(struct tevent_req *req); -static void ipa_auth_ldap_done(struct tevent_req *req); -static void ipa_auth_handler_retry_done(struct tevent_req *req); - -void ipa_auth(struct be_req *be_req) -{ - struct tevent_req *req; - struct ipa_auth_ctx *ipa_auth_ctx; - struct sdap_id_ctx *sdap_id_ctx; - - ipa_auth_ctx = talloc_zero(be_req, struct ipa_auth_ctx); - if (ipa_auth_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL); - } - - ipa_auth_ctx->callback = be_req->fn; - ipa_auth_ctx->pvt = be_req->pvt; - - ipa_auth_ctx->be_req = be_req; - - ipa_auth_ctx->sdap_auth_ctx = talloc_zero(ipa_auth_ctx, - struct sdap_auth_ctx); - if (ipa_auth_ctx->sdap_auth_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - goto fail; - } - - sdap_id_ctx = talloc_get_type( - be_req->be_ctx->bet_info[BET_ID].pvt_bet_data, - struct sdap_id_ctx); - ipa_auth_ctx->sdap_auth_ctx->be = sdap_id_ctx->be; - ipa_auth_ctx->sdap_auth_ctx->opts = sdap_id_ctx->opts; - - ipa_auth_ctx->krb5_ctx = talloc_get_type( - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data, - struct krb5_ctx); - -/* TODO: test and activate when server side support is available */ - ipa_auth_ctx->password_migration = false; - - ipa_auth_ctx->dp_err_type = DP_ERR_FATAL; - ipa_auth_ctx->errnum = EIO; - ipa_auth_ctx->errstr = NULL; - - req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req, - krb5_pam_handler); - if (req == NULL) { - DEBUG(1, ("ipa_auth_handler_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, ipa_auth_handler_done, ipa_auth_ctx); - return; - -fail: - ipa_auth_reply(ipa_auth_ctx); -} - -static void ipa_auth_handler_done(struct tevent_req *req) -{ - struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req, - struct ipa_auth_ctx); - struct pam_data *pd; - struct be_req *be_req; - int ret; - - be_req = ipa_auth_ctx->be_req; - pd = talloc_get_type(be_req->req_data, struct pam_data); - - ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type, - &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("ipa_auth_handler request failed.\n")); - pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { - pd->pam_status = ipa_auth_ctx->errnum; - goto done; - } - - if (ipa_auth_ctx->password_migration && pd->pam_status == PAM_CRED_ERR) { - DEBUG(1, ("Assuming Kerberos password is missing, " - "starting password migration.\n")); - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = - ipa_auth_ctx->sdap_auth_ctx; - req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req, - sdap_pam_auth_handler); - if (req == NULL) { - DEBUG(1, ("ipa_auth_ldap_send failed.\n")); - goto done; - } - - tevent_req_set_callback(req, ipa_auth_ldap_done, ipa_auth_ctx); - return; - } - -done: - ipa_auth_reply(ipa_auth_ctx); -} - -static void ipa_auth_ldap_done(struct tevent_req *req) -{ - struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req, - struct ipa_auth_ctx); - struct pam_data *pd; - struct be_req *be_req; - int ret; - - be_req = ipa_auth_ctx->be_req; - pd = talloc_get_type(be_req->req_data, struct pam_data); - - ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type, - &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("ipa_auth_handler request failed.\n")); - pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { - pd->pam_status = ipa_auth_ctx->errnum; - goto done; - } - - if (pd->pam_status == PAM_SUCCESS) { - DEBUG(1, ("LDAP authentication succeded, " - "trying Kerberos authentication again.\n")); - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx; - req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req, - krb5_pam_handler); - if (req == NULL) { - DEBUG(1, ("ipa_auth_ldap_send failed.\n")); - goto done; - } - - tevent_req_set_callback(req, ipa_auth_handler_retry_done, ipa_auth_ctx); - return; - } - -done: - ipa_auth_reply(ipa_auth_ctx); -} - -static void ipa_auth_handler_retry_done(struct tevent_req *req) -{ - struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req, - struct ipa_auth_ctx); - struct pam_data *pd; - struct be_req *be_req; - int ret; - - be_req = ipa_auth_ctx->be_req; - pd = talloc_get_type(be_req->req_data, struct pam_data); - - ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type, - &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("ipa_auth_handler request failed.\n")); - pd->pam_status = PAM_SYSTEM_ERR; - } - if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { - pd->pam_status = ipa_auth_ctx->errnum; - } - - ipa_auth_reply(ipa_auth_ctx); -} diff --git a/server/providers/ipa/ipa_auth.h b/server/providers/ipa/ipa_auth.h deleted file mode 100644 index 3079bbd1..00000000 --- a/server/providers/ipa/ipa_auth.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Authentication - - Authors: - Sumit Bose <sbose@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _IPA_AUTH_H_ -#define _IPA_AUTH_H_ - -#include "providers/dp_backend.h" - -void ipa_auth(struct be_req *be_req); - -#endif /* _IPA_AUTH_H_ */ diff --git a/server/providers/ipa/ipa_common.c b/server/providers/ipa/ipa_common.c deleted file mode 100644 index 7686227a..00000000 --- a/server/providers/ipa/ipa_common.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - SSSD - - IPA Provider Common Functions - - Authors: - Simo Sorce <ssorce@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <netdb.h> -#include <ctype.h> -#include "providers/ipa/ipa_common.h" - -struct dp_option ipa_basic_opts[] = { - { "ipa_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ipa_server", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ipa_hostname", DP_OPT_STRING, NULL_STRING, NULL_STRING }, -}; - -struct dp_option ipa_def_ldap_opts[] = { - { "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING}, - { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB }, - { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, - { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, - { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, - { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING }, - { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, - { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, - { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_schema", DP_OPT_STRING, { "ipa_v1" }, NULL_STRING }, - { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, - { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, - { "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER }, - { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 3600 }, NULL_NUMBER }, - { "entry_cache_timeout", DP_OPT_NUMBER, { .number = 1800 }, NULL_NUMBER }, - { "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_id_use_start_tls", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, - { "ldap_sasl_mech", DP_OPT_STRING, { "GSSAPI" } , NULL_STRING }, - { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, - /* use the same parm name as the krb5 module so we set it only once */ - { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING }, - { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE } -}; - -struct sdap_attr_map ipa_attr_map[] = { - { "ldap_entry_usn", "entryUSN", SYSDB_USN, NULL }, - { "ldap_rootdse_last_usn", "lastUSN", SYSDB_HIGH_USN, NULL } -}; - -struct sdap_attr_map ipa_user_map[] = { - { "ldap_user_object_class", "posixAccount", SYSDB_USER_CLASS, NULL }, - { "ldap_user_name", "uid", SYSDB_NAME, NULL }, - { "ldap_user_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_user_uid_number", "uidNumber", SYSDB_UIDNUM, NULL }, - { "ldap_user_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_user_gecos", "gecos", SYSDB_GECOS, NULL }, - { "ldap_user_home_directory", "homeDirectory", SYSDB_HOMEDIR, NULL }, - { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL }, - { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL }, - { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL }, - { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL }, - { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL }, - { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, - { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL }, - { "ldap_user_shadow_min", "shadowMin", SYSDB_SHADOWPW_MIN, NULL }, - { "ldap_user_shadow_max", "shadowMax", SYSDB_SHADOWPW_MAX, NULL }, - { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SHADOWPW_WARNING, NULL }, - { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SHADOWPW_INACTIVE, NULL }, - { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SHADOWPW_EXPIRE, NULL }, - { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL }, - { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL }, - { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL }, - { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL } -}; - -struct sdap_attr_map ipa_group_map[] = { - { "ldap_group_object_class", "posixGroup", SYSDB_GROUP_CLASS, NULL }, - { "ldap_group_name", "cn", SYSDB_NAME, NULL }, - { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_group_member", "member", SYSDB_MEMBER, NULL }, - { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL }, - { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL } -}; - -struct dp_option ipa_def_krb5_opts[] = { - { "krb5_kdcip", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "krb5_ccachedir", DP_OPT_STRING, { "/tmp" }, NULL_STRING }, - { "krb5_ccname_template", DP_OPT_STRING, { "FILE:%d/krb5cc_%U_XXXXXX" }, NULL_STRING}, - { "krb5_changepw_principal", DP_OPT_STRING, { "kadmin/changepw" }, NULL_STRING }, - { "krb5_auth_timeout", DP_OPT_NUMBER, { .number = 15 }, NULL_NUMBER }, - { "krb5_keytab", DP_OPT_STRING, { "/etc/krb5.keytab" }, NULL_STRING }, - { "krb5_validate", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE } -}; - -int domain_to_basedn(TALLOC_CTX *memctx, const char *domain, char **basedn) -{ - const char *s; - char *dn; - char *p; - int l; - - s = domain; - dn = talloc_strdup(memctx, "dc="); - - while ((p = strchr(s, '.'))) { - l = p - s; - dn = talloc_asprintf_append_buffer(dn, "%.*s,dc=", l, s); - if (!dn) { - return ENOMEM; - } - s = p + 1; - } - dn = talloc_strdup_append_buffer(dn, s); - if (!dn) { - return ENOMEM; - } - - *basedn = dn; - return EOK; -} - -int ipa_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sss_domain_info *dom, - struct ipa_options **_opts) -{ - struct ipa_options *opts; - char *domain; - char *server; - char *ipa_hostname; - int ret; - char hostname[HOST_NAME_MAX + 1]; - - opts = talloc_zero(memctx, struct ipa_options); - if (!opts) return ENOMEM; - - ret = dp_get_options(opts, cdb, conf_path, - ipa_basic_opts, - IPA_OPTS_BASIC, - &opts->basic); - if (ret != EOK) { - goto done; - } - - domain = dp_opt_get_string(opts->basic, IPA_DOMAIN); - if (!domain) { - ret = dp_opt_set_string(opts->basic, IPA_DOMAIN, dom->name); - if (ret != EOK) { - goto done; - } - } - - /* FIXME: Make non-fatal once we have discovery */ - server = dp_opt_get_string(opts->basic, IPA_SERVER); - if (!server) { - DEBUG(0, ("Can't find ipa server, missing option!\n")); - ret = EINVAL; - goto done; - } - - ipa_hostname = dp_opt_get_string(opts->basic, IPA_HOSTNAME); - if (ipa_hostname == NULL) { - ret = gethostname(hostname, HOST_NAME_MAX); - if (ret != EOK) { - DEBUG(1, ("gethostname failed [%d][%s].\n", errno, - strerror(errno))); - ret = errno; - goto done; - } - hostname[HOST_NAME_MAX] = '\0'; - DEBUG(9, ("Setting ipa_hostname to [%s].\n", hostname)); - ret = dp_opt_set_string(opts->basic, IPA_HOSTNAME, hostname); - if (ret != EOK) { - goto done; - } - } - - - ret = EOK; - *_opts = opts; - -done: - if (ret != EOK) { - talloc_zfree(opts); - } - return ret; -} - -int ipa_get_id_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_options **_opts) -{ - TALLOC_CTX *tmpctx; - char *hostname; - char *basedn; - char *realm; - char *value; - int ret; - int i; - - /* self check test, this should never fail, unless someone forgot - * to properly update the code after new ldap options have been added */ - if (SDAP_OPTS_BASIC != IPA_OPTS_BASIC_TEST) { - DEBUG(0, ("Option numbers do not match (%d != %d)\n", - SDAP_OPTS_BASIC, IPA_OPTS_BASIC_TEST)); - abort(); - } - - tmpctx = talloc_new(ipa_opts); - if (!tmpctx) { - return ENOMEM; - } - - ipa_opts->id = talloc_zero(ipa_opts, struct sdap_options); - if (!ipa_opts->id) { - ret = ENOMEM; - goto done; - } - - /* get sdap options */ - ret = dp_get_options(ipa_opts->id, cdb, conf_path, - ipa_def_ldap_opts, - SDAP_OPTS_BASIC, - &ipa_opts->id->basic); - if (ret != EOK) { - goto done; - } - - if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_SEARCH_BASE)) { - ret = domain_to_basedn(tmpctx, - dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN), - &basedn); - if (ret != EOK) { - goto done; - } - - /* FIXME: get values by querying IPA */ - /* set search base */ - value = talloc_asprintf(tmpctx, "cn=accounts,%s", basedn); - if (!value) { - ret = ENOMEM; - goto done; - } - ret = dp_opt_set_string(ipa_opts->id->basic, - SDAP_SEARCH_BASE, value); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_SEARCH_BASE].opt_name, - dp_opt_get_string(ipa_opts->id->basic, SDAP_SEARCH_BASE))); - } - - /* set the ldap_sasl_authid if the ipa_hostname override was specified */ - if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_SASL_AUTHID)) { - hostname = dp_opt_get_string(ipa_opts->basic, IPA_HOSTNAME); - if (hostname) { - value = talloc_asprintf(tmpctx, "host/%s", hostname); - if (!value) { - ret = ENOMEM; - goto done; - } - ret = dp_opt_set_string(ipa_opts->id->basic, - SDAP_SASL_AUTHID, value); - if (ret != EOK) { - goto done; - } - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_SASL_AUTHID].opt_name, - dp_opt_get_string(ipa_opts->id->basic, SDAP_SASL_AUTHID))); - } - - /* set krb realm */ - if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_KRB5_REALM)) { - realm = dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN); - for (i = 0; realm[i]; i++) { - realm[i] = toupper(realm[i]); - } - ret = dp_opt_set_string(ipa_opts->id->basic, - SDAP_KRB5_REALM, realm); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_KRB5_REALM].opt_name, - dp_opt_get_string(ipa_opts->id->basic, SDAP_KRB5_REALM))); - } - - /* fix schema to IPAv1 for now */ - ipa_opts->id->schema_type = SDAP_SCHEMA_IPA_V1; - - /* set user/group search bases if they are not specified */ - if (NULL == dp_opt_get_string(ipa_opts->id->basic, - SDAP_USER_SEARCH_BASE)) { - ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_USER_SEARCH_BASE, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_SEARCH_BASE)); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_USER_SEARCH_BASE].opt_name, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_USER_SEARCH_BASE))); - } - - if (NULL == dp_opt_get_string(ipa_opts->id->basic, - SDAP_GROUP_SEARCH_BASE)) { - ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_GROUP_SEARCH_BASE, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_SEARCH_BASE)); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_GROUP_SEARCH_BASE].opt_name, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_GROUP_SEARCH_BASE))); - } - - ret = sdap_get_map(ipa_opts->id, cdb, conf_path, - ipa_attr_map, - SDAP_AT_GENERAL, - &ipa_opts->id->gen_map); - if (ret != EOK) { - goto done; - } - - ret = sdap_get_map(ipa_opts->id, - cdb, conf_path, - ipa_user_map, - SDAP_OPTS_USER, - &ipa_opts->id->user_map); - if (ret != EOK) { - goto done; - } - - ret = sdap_get_map(ipa_opts->id, - cdb, conf_path, - ipa_group_map, - SDAP_OPTS_GROUP, - &ipa_opts->id->group_map); - if (ret != EOK) { - goto done; - } - - ret = EOK; - *_opts = ipa_opts->id; - -done: - talloc_zfree(tmpctx); - if (ret != EOK) { - talloc_zfree(ipa_opts->id); - } - return ret; -} - -/* the following define is used to keep track of * the options in the krb5 - * module, so that if they change and ipa is not updated correspondingly - * this will trigger a runtime abort error */ -#define IPA_KRB5_OPTS_TEST 8 - -int ipa_get_auth_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct dp_option **_opts) -{ - char *value; - int ret; - int i; - - /* self check test, this should never fail, unless someone forgot - * to properly update the code after new ldap options have been added */ - if (KRB5_OPTS != IPA_KRB5_OPTS_TEST) { - DEBUG(0, ("Option numbers do not match (%d != %d)\n", - KRB5_OPTS, IPA_KRB5_OPTS_TEST)); - abort(); - } - - ipa_opts->auth = talloc_zero(ipa_opts, struct dp_option); - if (ipa_opts->auth == NULL) { - ret = ENOMEM; - goto done; - } - - /* get krb5 options */ - ret = dp_get_options(ipa_opts, cdb, conf_path, - ipa_def_krb5_opts, - KRB5_OPTS, &ipa_opts->auth); - if (ret != EOK) { - goto done; - } - - /* set krb realm */ - if (NULL == dp_opt_get_string(ipa_opts->auth, KRB5_REALM)) { - value = dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN); - if (!value) { - ret = ENOMEM; - goto done; - } - for (i = 0; value[i]; i++) { - value[i] = toupper(value[i]); - } - ret = dp_opt_set_string(ipa_opts->auth, KRB5_REALM, value); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->auth[KRB5_REALM].opt_name, - dp_opt_get_string(ipa_opts->auth, KRB5_REALM))); - } - - *_opts = ipa_opts->auth; - ret = EOK; - -done: - if (ret != EOK) { - talloc_zfree(ipa_opts->auth); - } - return ret; -} - -static void ipa_resolve_callback(void *private_data, struct fo_server *server) -{ - struct ipa_service *service; - struct hostent *srvaddr; - char *address; - char *new_uri; - int ret; - - service = talloc_get_type(private_data, struct ipa_service); - if (!service) { - DEBUG(1, ("FATAL: Bad private_data\n")); - return; - } - - srvaddr = fo_get_server_hostent(server); - if (!srvaddr) { - DEBUG(1, ("FATAL: No hostent available for server (%s)\n", - fo_get_server_name(server))); - return; - } - - address = talloc_asprintf(service, "%s", srvaddr->h_name); - if (!address) { - DEBUG(1, ("Failed to copy address ...\n")); - return; - } - - new_uri = talloc_asprintf(service, "ldap://%s", address); - if (!new_uri) { - DEBUG(2, ("Failed to copy URI ...\n")); - talloc_free(address); - return; - } - - /* free old one and replace with new one */ - talloc_zfree(service->sdap->uri); - service->sdap->uri = new_uri; - talloc_zfree(service->krb5_service->address); - service->krb5_service->address = address; - - ret = write_kdcinfo_file(service->krb5_service->realm, address); - if (ret != EOK) { - DEBUG(2, ("write_kdcinfo_file failed, authentication might fail.\n")); - } - -} - -int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *servers, const char *domain, - struct ipa_service **_service) -{ - TALLOC_CTX *tmp_ctx; - struct ipa_service *service; - char **list = NULL; - char *realm; - int ret; - int i; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - service = talloc_zero(tmp_ctx, struct ipa_service); - if (!service) { - ret = ENOMEM; - goto done; - } - service->sdap = talloc_zero(service, struct sdap_service); - if (!service->sdap) { - ret = ENOMEM; - goto done; - } - service->krb5_service = talloc_zero(service, struct krb5_service); - if (!service->krb5_service) { - ret = ENOMEM; - goto done; - } - - ret = be_fo_add_service(ctx, "IPA"); - if (ret != EOK) { - DEBUG(1, ("Failed to create failover service!\n")); - goto done; - } - - service->sdap->name = talloc_strdup(service, "IPA"); - if (!service->sdap->name) { - ret = ENOMEM; - goto done; - } - - service->krb5_service->name = talloc_strdup(service, "IPA"); - if (!service->krb5_service->name) { - ret = ENOMEM; - goto done; - } - - realm = talloc_strdup(service, domain); - if (!realm) { - ret = ENOMEM; - goto done; - } - for (i = 0; realm[i]; i++) { - realm[i] = toupper(realm[i]); - } - service->krb5_service->realm = realm; - - /* split server parm into a list */ - ret = split_on_separator(tmp_ctx, servers, ',', true, &list, NULL); - if (ret != EOK) { - DEBUG(1, ("Failed to parse server list!\n")); - goto done; - } - - /* now for each one add a new server to the failover service */ - for (i = 0; list[i]; i++) { - - talloc_steal(service, list[i]); - - ret = be_fo_add_server(ctx, "IPA", list[i], 0, NULL); - if (ret && ret != EEXIST) { - DEBUG(0, ("Failed to add server\n")); - goto done; - } - - DEBUG(6, ("Added Server %s\n", list[i])); - } - - ret = be_fo_service_add_callback(memctx, ctx, "IPA", - ipa_resolve_callback, service); - if (ret != EOK) { - DEBUG(1, ("Failed to add failover callback!\n")); - goto done; - } - - ret = EOK; - -done: - if (ret == EOK) { - *_service = talloc_steal(memctx, service); - } - talloc_zfree(tmp_ctx); - return ret; -} - diff --git a/server/providers/ipa/ipa_common.h b/server/providers/ipa/ipa_common.h deleted file mode 100644 index 60c7313f..00000000 --- a/server/providers/ipa/ipa_common.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - SSSD - - IPA Common utility code - - Copyright (C) Simo Sorce <ssorce@redhat.com> 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _IPA_COMMON_H_ -#define _IPA_COMMON_H_ - -#include "util/util.h" -#include "confdb/confdb.h" -#include "providers/ldap/ldap_common.h" -#include "providers/krb5/krb5_common.h" - -struct ipa_service { - struct sdap_service *sdap; - struct krb5_service *krb5_service; -}; - -/* the following define is used to keep track of the options in the ldap - * module, so that if they change and ipa is not updated correspondingly - * this will trigger a runtime abort error */ -#define IPA_OPTS_BASIC_TEST 31 - -enum ipa_basic_opt { - IPA_DOMAIN = 0, - IPA_SERVER, - IPA_HOSTNAME, - - IPA_OPTS_BASIC /* opts counter */ -}; - -struct ipa_options { - struct dp_option *basic; - - struct ipa_service *service; - - /* id provider */ - struct sdap_options *id; - struct sdap_id_ctx *id_ctx; - - /* auth and chpass provider */ - struct dp_option *auth; - struct krb5_ctx *auth_ctx; -}; - -/* options parsers */ -int ipa_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sss_domain_info *dom, - struct ipa_options **_opts); - -int ipa_get_id_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_options **_opts); - -int ipa_get_auth_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct dp_option **_opts); - -int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *servers, const char *domain, - struct ipa_service **_service); - -#endif /* _IPA_COMMON_H_ */ diff --git a/server/providers/ipa/ipa_init.c b/server/providers/ipa/ipa_init.c deleted file mode 100644 index 10b9257a..00000000 --- a/server/providers/ipa/ipa_init.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - SSSD - - IPA Provider Initialization functions - - Authors: - Simo Sorce <ssorce@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <sys/types.h> -#include <unistd.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include "providers/child_common.h" -#include "providers/ipa/ipa_common.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/ipa/ipa_auth.h" -#include "providers/ipa/ipa_access.h" -#include "providers/ipa/ipa_timerules.h" - -struct ipa_options *ipa_options = NULL; - -/* Id Handler */ -struct bet_ops ipa_id_ops = { - .handler = sdap_account_info_handler, - .finalize = NULL -}; - -struct bet_ops ipa_auth_ops = { - .handler = ipa_auth, - .finalize = NULL, -}; - -struct bet_ops ipa_chpass_ops = { - .handler = krb5_pam_handler, - .finalize = NULL, -}; - -struct bet_ops ipa_access_ops = { - .handler = ipa_access_handler, - .finalize = NULL -}; - -int common_ipa_init(struct be_ctx *bectx) -{ - const char *ipa_servers; - const char *ipa_domain; - int ret; - - ret = ipa_get_options(bectx, bectx->cdb, - bectx->conf_path, - bectx->domain, &ipa_options); - if (ret != EOK) { - return ret; - } - - ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER); - if (!ipa_servers) { - DEBUG(0, ("Missing ipa_server option!\n")); - return EINVAL; - } - - ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN); - if (!ipa_domain) { - DEBUG(0, ("Missing ipa_domain option!\n")); - return EINVAL; - } - - ret = ipa_service_init(ipa_options, bectx, ipa_servers, ipa_domain, - &ipa_options->service); - if (ret != EOK) { - DEBUG(0, ("Failed to init IPA failover service!\n")); - return ret; - } - - return EOK; -} - -int sssm_ipa_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - struct sdap_id_ctx *ctx; - int ret; - - if (!ipa_options) { - ret = common_ipa_init(bectx); - if (ret != EOK) { - return ret; - } - } - - if (ipa_options->id_ctx) { - /* already initialized */ - *ops = &ipa_id_ops; - *pvt_data = ipa_options->id_ctx; - return EOK; - } - - ctx = talloc_zero(ipa_options, struct sdap_id_ctx); - if (!ctx) { - return ENOMEM; - } - ctx->be = bectx; - ctx->service = ipa_options->service->sdap; - ipa_options->id_ctx = ctx; - - ret = ipa_get_id_options(ipa_options, bectx->cdb, - bectx->conf_path, - &ctx->opts); - if (ret != EOK) { - goto done; - } - - ret = setup_tls_config(ctx->opts->basic); - if (ret != EOK) { - DEBUG(1, ("setup_tls_config failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - ret = sdap_id_setup_tasks(ctx); - if (ret != EOK) { - goto done; - } - - ret = setup_child(ctx); - if (ret != EOK) { - DEBUG(1, ("setup_child failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - *ops = &ipa_id_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_zfree(ipa_options->id_ctx); - } - return ret; -} - -int sssm_ipa_auth_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - struct krb5_ctx *ctx; - struct tevent_signal *sige; - FILE *debug_filep; - unsigned v; - int ret; - - if (!ipa_options) { - ret = common_ipa_init(bectx); - if (ret != EOK) { - return ret; - } - } - - if (ipa_options->auth_ctx) { - /* already initialized */ - *ops = &ipa_auth_ops; - *pvt_data = ipa_options->auth_ctx; - return EOK; - } - - ctx = talloc_zero(bectx, struct krb5_ctx); - if (!ctx) { - return ENOMEM; - } - ctx->service = ipa_options->service->krb5_service; - ipa_options->auth_ctx = ctx; - - ret = ipa_get_auth_options(ipa_options, bectx->cdb, - bectx->conf_path, - &ctx->opts); - if (ret != EOK) { - goto done; - } - - ret = check_and_export_options(ctx->opts, bectx->domain); - if (ret != EOK) { - DEBUG(1, ("check_and_export_opts failed.\n")); - goto done; - } - - sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO, - child_sig_handler, NULL); - if (sige == NULL) { - DEBUG(1, ("tevent_add_signal failed.\n")); - ret = ENOMEM; - goto done; - } - - if (debug_to_file != 0) { - ret = open_debug_file_ex("krb5_child", &debug_filep); - if (ret != EOK) { - DEBUG(0, ("Error setting up logging (%d) [%s]\n", - ret, strerror(ret))); - goto done; - } - - ctx->child_debug_fd = fileno(debug_filep); - if (ctx->child_debug_fd == -1) { - DEBUG(0, ("fileno failed [%d][%s]\n", errno, strerror(errno))); - ret = errno; - goto done; - } - - v = fcntl(ctx->child_debug_fd, F_GETFD, 0); - fcntl(ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC); - } - - *ops = &ipa_auth_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_zfree(ipa_options->auth_ctx); - } - return ret; -} - -int sssm_ipa_chpass_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - int ret; - ret = sssm_ipa_auth_init(bectx, ops, pvt_data); - *ops = &ipa_chpass_ops; - return ret; -} - -int sssm_ipa_access_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - int ret; - struct ipa_access_ctx *ipa_access_ctx; - - ipa_access_ctx = talloc_zero(bectx, struct ipa_access_ctx); - if (ipa_access_ctx == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - return ENOMEM; - } - - ret = sssm_ipa_init(bectx, ops, (void **) &ipa_access_ctx->sdap_ctx); - if (ret != EOK) { - DEBUG(1, ("sssm_ipa_init failed.\n")); - goto done; - } - - ret = dp_copy_options(ipa_access_ctx, ipa_options->basic, - IPA_OPTS_BASIC, &ipa_access_ctx->ipa_options); - if (ret != EOK) { - DEBUG(1, ("dp_copy_options failed.\n")); - goto done; - } - - ret = init_time_rules_parser(ipa_access_ctx, &ipa_access_ctx->tr_ctx); - if (ret != EOK) { - DEBUG(1, ("init_time_rules_parser failed.\n")); - goto done; - } - - *ops = &ipa_access_ops; - *pvt_data = ipa_access_ctx; - -done: - if (ret != EOK) { - talloc_free(ipa_access_ctx); - } - return ret; -} diff --git a/server/providers/ipa/ipa_timerules.c b/server/providers/ipa/ipa_timerules.c deleted file mode 100644 index 1a52eef1..00000000 --- a/server/providers/ipa/ipa_timerules.c +++ /dev/null @@ -1,1186 +0,0 @@ -/* - SSSD - - IPA Provider Time Rules Parsing - - Authors: - Jakub Hrozek <jhrozek@redhat.com> - - Copyright (C) Red Hat, Inc 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#define _XOPEN_SOURCE /* strptime() needs this */ - -#include <pcre.h> -#include <talloc.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <time.h> -#include <stdbool.h> -#include <limits.h> - -#include "providers/ipa/ipa_timerules.h" -#include "util/util.h" - -#define JMP_NEOK(variable) do { \ - if (variable != EOK) goto done; \ -} while (0) - -#define JMP_NEOK_LABEL(variable, label) do { \ - if (variable != EOK) goto label; \ -} while (0) - -#define CHECK_PTR(ptr) do { \ - if (ptr == NULL) { \ - return ENOMEM; \ - } \ -} while (0) - -#define CHECK_PTR_JMP(ptr) do { \ - if (ptr == NULL) { \ - ret = ENOMEM; \ - goto done; \ - } \ -} while (0) - -#define BUFFER_OR_JUMP(ctx, ptr, count) do { \ - ptr = talloc_array(ctx, unsigned char, count); \ - if (ptr == NULL) { \ - return ENOMEM; \ - } \ - memset(ptr, 0, sizeof(unsigned char)*count); \ -} while (0) - -#define TEST_BIT_RANGE(bitfield, index, resptr) do { \ - if (bitfield) { \ - if (test_bit(&bitfield, index) == 0) { \ - *resptr = false; \ - return EOK; \ - } \ - } \ -} while (0) - -#define TEST_BIT_RANGE_PTR(bitfield, index, resptr) do { \ - if (bitfield) { \ - if (test_bit(bitfield, index) == 0) { \ - *resptr = false; \ - return EOK; \ - } \ - } \ -} while (0) - -/* number of match offsets when matching pcre regexes */ -#define OVEC_SIZE 30 - -/* regular expressions describing syntax of our HBAC grammar */ -#define RGX_WEEKLY "day (?P<day_of_week>(0|1|2|3|4|5|6|7|Mon|Tue|Wed|Thu|Fri|Sat|Sun|,|-)+)" - -#define RGX_MDAY "(?P<mperspec_day>day) (?P<interval_day>[0-9,-]+) " -#define RGX_MWEEK "(?P<mperspec_week>week) (?P<interval_week>[0-9,-]+) "RGX_WEEKLY -#define RGX_MONTHLY RGX_MDAY"|"RGX_MWEEK - -#define RGX_YDAY "(?P<yperspec_day>day) (?P<day_of_year>[0-9,-]+) " -#define RGX_YWEEK "(?P<yperspec_week>week) (?P<week_of_year>[0-9,-]+) "RGX_WEEKLY -#define RGX_YMONTH "(?P<yperspec_month>month) (?P<month_number>[0-9,-]+) (?P<m_period>.*?)$" -#define RGX_YEARLY RGX_YMONTH"|"RGX_YWEEK"|"RGX_YDAY - -#define RGX_TIMESPEC "(?P<timeFrom>[0-9]{4}) ~ (?P<timeTo>[0-9]{4})" - -#define RGX_GENERALIZED "(?P<year>[0-9]{4})(?P<month>[0-9]{2})(?P<day>[0-9]{2})(?P<hour>[0-9]{2})?(?P<minute>[0-9]{2})?(?P<second>[0-9]{2})?" - -#define RGX_PERIODIC "^periodic (?P<perspec>daily|weekly|monthly|yearly) (?P<period>.*?)"RGX_TIMESPEC"$" -#define RGX_ABSOLUTE "^absolute (?P<from>\\S+) ~ (?P<to>\\S+)$" - -/* limits on various parameters */ -#define DAY_OF_WEEK_MAX 7 -#define DAY_OF_MONTH_MAX 31 -#define WEEK_OF_MONTH_MAX 5 -#define WEEK_OF_YEAR_MAX 54 -#define DAY_OF_YEAR_MAX 366 -#define MONTH_MAX 12 -#define HOUR_MAX 23 -#define MINUTE_MAX 59 - -/* limits on sizes of buffers for bit arrays */ -#define DAY_OF_MONTH_BUFSIZE 8 -#define DAY_OF_YEAR_BUFSIZE 44 -#define WEEK_OF_YEAR_BUFSIZE 13 -#define MONTH_BUFSIZE 2 -#define HOUR_BUFSIZE 4 -#define MINUTE_BUFSIZE 8 - -/* Lookup tables for translating names of days and months */ -static const char *names_day_of_week[] = - { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", NULL }; -static const char *names_months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Nov", "Dec", NULL }; - -/* - * Timelib knows two types of ranges - periodic and absolute - */ -enum rangetypes { - TYPE_ABSOLUTE, - TYPE_PERIODIC -}; - -struct absolute_range { - time_t time_from; - time_t time_to; -}; - -struct periodic_range { - unsigned char day_of_week; - unsigned char *day_of_month; - unsigned char *day_of_year; - unsigned char week_of_month; - unsigned char *week_of_year; - unsigned char *month; - unsigned char *hour; - unsigned char *minute; -}; - -/* - * Context of one time rule being analyzed - */ -struct range_ctx { - /* main context with precompiled patterns */ - struct time_rules_ctx *trctx; - /* enum rangetypes */ - enum rangetypes type; - - struct absolute_range *abs; - struct periodic_range *per; -}; - - -/* - * The context of one regular expression - */ -struct parse_ctx { - /* the regular expression used for one parsing */ - pcre *re; - /* number of matches */ - int matches; - /* vector of matches */ - int *ovec; -}; - -/* indexes to the array of precompiled regexes */ -enum timelib_rgx { - LP_RGX_GENERALIZED, - LP_RGX_MDAY, - LP_RGX_MWEEK, - LP_RGX_YEARLY, - LP_RGX_WEEKLY, - LP_RGX_ABSOLUTE, - LP_RGX_PERIODIC, - LP_RGX_MAX, -}; - -/* matches the indexes */ -static const char *lookup_table[] = { - RGX_GENERALIZED, - RGX_MDAY, - RGX_MWEEK, - RGX_YEARLY, - RGX_WEEKLY, - RGX_ABSOLUTE, - RGX_PERIODIC, - NULL, -}; - -/* - * Main struct passed outside - * holds precompiled regular expressions - */ -struct time_rules_ctx { - pcre *re[LP_RGX_MAX]; -}; - -/******************************************************************* - * helper function - bit arrays * - *******************************************************************/ - -/* set a single bit in a bitmap */ -static void set_bit(unsigned char *bitmap, unsigned int bit) -{ - bitmap[bit/CHAR_BIT] |= 1 << (bit%CHAR_BIT); -} - -/* - * This function is based on bit_nset macro written originally by Paul Vixie, - * copyrighted by The Regents of the University of California, as found - * in tarball of fcron, file bitstring.h - */ -static void set_bit_range(unsigned char *bitmap, unsigned int start, - unsigned int stop) -{ - int startbyte = start/CHAR_BIT; - int stopbyte = stop/CHAR_BIT; - - if (startbyte == stopbyte) { - bitmap[startbyte] |= ((0xff << (start & 0x7)) & - (0xff >> (CHAR_BIT- 1 - (stop & 0x7)))); - } else { - bitmap[startbyte] |= 0xff << (start & 0x7); - while (++startbyte < stopbyte) { - bitmap[startbyte] |= 0xff; - } - bitmap[stopbyte] |= 0xff >> (CHAR_BIT- 1 - (stop & 0x7)); - } -} - -static int test_bit(unsigned char *bitmap, unsigned int bit) -{ - return (int)(bitmap[bit/CHAR_BIT] >> (bit%CHAR_BIT)) & 1; -} - -/******************************************************************* - * parsing intervals * - *******************************************************************/ - -/* - * Some ranges allow symbolic names, like Mon..Sun for names of day. - * This routine takes a list of symbolic names as NAME_ARRAY and the - * one we're looking for as KEY and returns its index or -1 when not - * found. The last member of NAME_ARRAY must be NULL. - */ -static int name_index(const char **name_array, const char *key, int min) -{ - int index = 0; - const char *one; - - if (name_array == NULL) { - return -1; - } - - while ((one = name_array[index]) != NULL) { - if (strcmp(key,one) == 0) { - return index+min; - } - index++; - } - - return -1; -} - -/* - * Sets appropriate bits given by an interval in STR (in form of 1,5-7,10) to - * a bitfield given in OUT. Does no boundary checking. STR can also contain - * symbolic names, these would be given in TRANSLATE. - */ -static int interval2bitfield(TALLOC_CTX *mem_ctx, - unsigned char *out, - const char *str, - int min, int max, - const char **translate) -{ - char *copy; - char *next, *token; - int tokval, tokmax; - char *end_ptr; - int ret; - char *dash; - - DEBUG(9, ("Converting '%s' to interval\n", str)); - - copy = talloc_strdup(mem_ctx, str); - CHECK_PTR(copy); - - next = copy; - while (next) { - token = next; - next = strchr(next, ','); - if (next) { - *next = '\0'; - next++; - } - - errno = 0; - tokval = strtol(token, &end_ptr, 10); - if (*end_ptr == '\0' && errno == 0) { - if (tokval <= max && tokval >= 0) { - set_bit(out, tokval); - continue; - } else { - ret = ERANGE; - goto done; - } - } else if ((dash = strchr(token, '-')) != NULL){ - *dash = '\0'; - ++dash; - - errno = 0; - tokval = strtol(token, &end_ptr, 10); - if (*end_ptr != '\0' || errno != 0) { - tokval = name_index(translate, token, min); - if (tokval == -1) { - ret = ERANGE; - goto done; - } - } - errno = 0; - tokmax = strtol(dash, &end_ptr, 10); - if (*end_ptr != '\0' || errno != 0) { - tokmax = name_index(translate, dash, min); - if (tokmax == -1) { - ret = ERANGE; - goto done; - } - } - - if (tokval <= max && tokmax <= max && - tokval >= min && tokmax >= min) { - if (tokmax > tokval) { - DEBUG(7, ("Setting interval %d-%d\n", tokval, tokmax)); - DEBUG(9, ("interval: %p\n", out)); - set_bit_range(out, tokval, tokmax); - } else { - /* Interval wraps around - i.e. from 18.00 to 06.00 */ - DEBUG(7, ("Setting inverted interval %d-%d\n", tokval, tokmax)); - DEBUG(9, ("interval: %p\n", out)); - set_bit_range(out, min, tokmax); - set_bit_range(out, tokval, max); - } - continue; - } else { - /* tokval or tokmax are not between <min, max> */ - ret = ERANGE; - goto done; - } - } else if ((tokval = name_index(translate, token, min)) != -1) { - /* Try to translate one token by name */ - if (tokval <= max) { - set_bit(out, tokval); - continue; - } else { - ret = ERANGE; - goto done; - } - } else { - ret = EINVAL; - goto done; - } - } - - ret = EOK; -done: - talloc_free(copy); - return ret; -} - -/******************************************************************* - * wrappers around regexp handling * - *******************************************************************/ - -/* - * Copies a named substring SUBSTR_NAME from string STR using the parsing - * information from PCTX. The context PCTX is also used as a talloc context. - * - * The resulting string is stored in OUT. - * Return value is EOK on no error or ENOENT on error capturing the substring - */ -static int copy_substring(struct parse_ctx *pctx, - const char *str, - const char *substr_name, - char **out) -{ - const char *result = NULL; - int ret; - char *o = NULL; - - result = NULL; - - ret = pcre_get_named_substring(pctx->re, str, pctx->ovec, - pctx->matches, substr_name, &result); - if (ret < 0 || result == NULL) { - DEBUG(5, ("named substring '%s' does not exist in '%s'\n", - substr_name, str)); - return ENOENT; - } - - o = talloc_strdup(pctx, result); - pcre_free_substring(result); - if (o == NULL) { - return ENOMEM; - } - - DEBUG(9, ("Copied substring named '%s' value '%s'\n", substr_name, o)); - - *out = o; - return EOK; -} - -/* - * Copies a named substring SUBSTR_NAME from string STR using the parsing - * information from PCTX and converts it to an integer. - * The context PCTX is also used as a talloc context. - * - * The resulting string is stored in OUT. - * Return value is EOK on no error or ENOENT on error capturing the substring - */ -static int substring_strtol(struct parse_ctx *pctx, - const char *str, - const char *substr_name, - int *out) -{ - char *substr = NULL; - int ret; - int val; - char *err_ptr; - - ret = copy_substring(pctx, str, substr_name, &substr); - if (ret != EOK) { - DEBUG(5, ("substring '%s' does not exist\n", substr_name)); - return ret; - } - - errno = 0; - val = strtol(substr, &err_ptr, 10); - if (substr == '\0' || *err_ptr != '\0' || errno != 0) { - DEBUG(5, ("substring '%s' does not contain an integerexist\n", - substr)); - talloc_free(substr); - return EINVAL; - } - - *out = val; - talloc_free(substr); - return EOK; -} - -/* - * Compiles a regular expression REGEXP and tries to match it against the - * string STR. Fills in structure _PCTX with info about matching. - * - * Returns EOK on no error, EFAULT on bad regexp, EINVAL when it cannot - * match the regexp. - */ -static int matches_regexp(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - const char *str, - enum timelib_rgx regex, - struct parse_ctx **_pctx) -{ - int ret; - struct parse_ctx *pctx = NULL; - - pctx = talloc_zero(ctx, struct parse_ctx); - CHECK_PTR(pctx); - pctx->ovec = talloc_array(pctx, int, OVEC_SIZE); - CHECK_PTR_JMP(pctx->ovec); - pctx->re = trctx->re[regex]; - - ret = pcre_exec(pctx->re, NULL, str, strlen(str), 0, PCRE_NOTEMPTY, pctx->ovec, OVEC_SIZE); - if (ret <= 0) { - DEBUG(8, ("string '%s' did *NOT* match regexp '%s'\n", str, lookup_table[regex])); - ret = EINVAL; - goto done; - } - DEBUG(8, ("string '%s' matched regexp '%s'\n", str, lookup_table[regex])); - - pctx->matches = ret; - *_pctx = pctx; - return EOK; - -done: - talloc_free(pctx); - return ret; -} - -/******************************************************************* - * date/time helper functions * - *******************************************************************/ - -/* - * Returns week number as an integer - * This may seem ugly, but I think it's actually less error prone - * than writing my own routine - */ -static int weeknum(const struct tm *t) -{ - char buf[3]; - - if (!strftime(buf, 3, "%U", t)) { - return -1; - } - - /* %U returns 0-53, we want 1-54 */ - return atoi(buf)+1; -} - -/* - * Return the week of the month - * Range is 1 to 5 - */ -static int get_week_of_month(const struct tm *t) -{ - int fs; /* first sunday */ - - fs = (t->tm_mday % 7) - t->tm_wday; - if (fs <= 0) { - fs += 7; - } - - return (t->tm_mday <= fs) ? 1 : (2 + (t->tm_mday - fs - 1) / 7); -} - -/* - * Normalize differencies between our HBAC definition and semantics of - * struct tm - */ -static void abs2tm(struct tm *t) -{ - /* tm defines tm_year as num of yrs since 1900, we have absolute number */ - t->tm_year %= 1900; - /* struct tm defines tm_mon as number of month since January */ - t->tm_mon--; -} - -/* - * Normalize differencies between our HBAC definition and semantics of - * struct tm - */ -static void tm2abs(struct tm *t) -{ - /* tm defines tm_year as num of yrs since 1900, we have absolute number */ - t->tm_year += 1900; - /* struct tm defines tm_mon as number of month since January */ - t->tm_mon++; -} - -/******************************************************************* - * parsing of HBAC rules themselves * - *******************************************************************/ - -/* - * Parses generalized time string given in STR and fills the - * information into OUT. - */ -static int parse_generalized_time(struct parse_ctx *pctx, - struct time_rules_ctx *trctx, - const char *str, - time_t *out) -{ - int ret; - struct parse_ctx *gctx = NULL; - struct tm tm; - - memset(&tm, 0, sizeof(tm)); - tm.tm_isdst = -1; - - ret = matches_regexp(pctx, trctx, str, LP_RGX_GENERALIZED, &gctx); - JMP_NEOK(ret); - - /* compulsory */ - ret = substring_strtol(gctx, str, "year", &tm.tm_year); - JMP_NEOK(ret); - ret = substring_strtol(gctx, str, "month", &tm.tm_mon); - JMP_NEOK(ret); - ret = substring_strtol(gctx, str, "day", &tm.tm_mday); - JMP_NEOK(ret); - /* optional */ - ret = substring_strtol(gctx, str, "hour", &tm.tm_hour); - JMP_NEOK_LABEL(ret, enoent); - ret = substring_strtol(gctx, str, "minute", &tm.tm_min); - JMP_NEOK_LABEL(ret, enoent); - ret = substring_strtol(gctx, str, "second", &tm.tm_sec); - JMP_NEOK_LABEL(ret, enoent); - -enoent: - if (ret == ENOENT) { - ret = EOK; - } - - abs2tm(&tm); - - *out = mktime(&tm); - DEBUG(3, ("converted to time: '%s'\n", ctime(out))); - if (*out == -1) { - ret = EINVAL; - } -done: - talloc_free(gctx); - return ret; -} - -/* - * Parses absolute timerange string given in STR and fills the - * information into ABS. - */ -static int parse_absolute(struct absolute_range *absr, - struct time_rules_ctx *trctx, - struct parse_ctx *pctx, - const char *str) -{ - char *from = NULL, *to = NULL; - int ret; - - ret = copy_substring(pctx, str, "from", &from); - if (ret != EOK) { - DEBUG(1, ("Missing required part 'from' in absolute timespec\n")); - ret = EINVAL; - goto done; - } - ret = copy_substring(pctx, str, "to", &to); - if (ret != EOK) { - DEBUG(1, ("Missing required part 'to' in absolute timespec\n")); - ret = EINVAL; - goto done; - } - - ret = parse_generalized_time(pctx, trctx, from, &absr->time_from); - if (ret != EOK) { - DEBUG(1, ("Cannot parse generalized time - first part\n")); - goto done; - } - - ret = parse_generalized_time(pctx, trctx, to, &absr->time_to); - if (ret != EOK) { - DEBUG(1, ("Cannot parse generalized time - second part\n")); - goto done; - } - - if (difftime(absr->time_to, absr->time_from) < 0) { - DEBUG(1, ("Not a valid interval\n")); - ret = EINVAL; - } - - ret = EOK; -done: - talloc_free(from); - talloc_free(to); - return ret; -} - -static int parse_hhmm(const char *str, int *hour, int *min) -{ - struct tm t; - char *err; - - err = strptime(str, "%H%M", &t); - if (*err != '\0') { - return EINVAL; - } - - *hour = t.tm_hour; - *min = t.tm_min; - - return EOK; -} - -/* - * Parses monthly periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic_monthly(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - struct periodic_range *per, - const char *str) -{ - int ret; - struct parse_ctx *mpctx = NULL; - char *match = NULL; - char *mperspec = NULL; - - /* This code would be much less ugly if RHEL5 PCRE knew about PCRE_DUPNAMES */ - ret = matches_regexp(ctx, trctx, str, LP_RGX_MDAY, &mpctx); - if (ret == EOK) { - ret = copy_substring(mpctx, str, "mperspec_day", &mperspec); - JMP_NEOK(ret); - ret = copy_substring(mpctx, str, "interval_day", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ctx, per->day_of_month, DAY_OF_MONTH_BUFSIZE); - ret = interval2bitfield(mpctx, per->day_of_month, match, - 1, DAY_OF_MONTH_MAX, NULL); - JMP_NEOK(ret); - } else { - ret = matches_regexp(ctx, trctx, str, LP_RGX_MWEEK, &mpctx); - JMP_NEOK(ret); - ret = copy_substring(mpctx, str, "mperspec_week", &mperspec); - JMP_NEOK(ret); - - ret = copy_substring(mpctx, str, "interval_week", &match); - JMP_NEOK(ret); - ret = interval2bitfield(mpctx, &per->week_of_month, match, - 1, WEEK_OF_MONTH_MAX, NULL); - JMP_NEOK(ret); - - ret = copy_substring(mpctx, str, "day_of_week", &match); - JMP_NEOK(ret); - ret = interval2bitfield(mpctx, &per->day_of_week, match, - 1, DAY_OF_WEEK_MAX, names_day_of_week); - JMP_NEOK(ret); - } - -done: - talloc_free(mpctx); - return ret; -} - -/* - * Parses yearly periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic_yearly(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - struct periodic_range *per, - const char *str) -{ - int ret; - struct parse_ctx *ypctx = NULL; - char *match = NULL; - char *yperspec = NULL; - - ret = matches_regexp(ctx, trctx, str, LP_RGX_YEARLY, &ypctx); - JMP_NEOK(ret); - ret = copy_substring(ypctx, str, "yperspec_day", &yperspec); - if (ret == EOK) { - ret = copy_substring(ypctx, str, "day_of_year", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ypctx, per->day_of_year, DAY_OF_YEAR_BUFSIZE); - ret = interval2bitfield(ypctx, per->day_of_year, match, - 1, DAY_OF_YEAR_MAX, NULL); - JMP_NEOK(ret); - } - - if (ret != ENOENT) goto done; - - ret = copy_substring(ypctx, str, "yperspec_week", &yperspec); - if (ret == EOK) { - ret = copy_substring(ypctx, str, "week_of_year", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ypctx, per->week_of_year, WEEK_OF_YEAR_BUFSIZE); - ret = interval2bitfield(ypctx, per->week_of_year, match, - 1, WEEK_OF_YEAR_MAX, NULL); - JMP_NEOK(ret); - - talloc_free(match); - ret = copy_substring(ypctx, str, "day_of_week", &match); - JMP_NEOK(ret); - ret = interval2bitfield(ypctx, &per->day_of_week, match, - 1, DAY_OF_WEEK_MAX, names_day_of_week); - JMP_NEOK(ret); - } - - if (ret != ENOENT) goto done; - - ret = copy_substring(ypctx, str, "yperspec_month", &yperspec); - JMP_NEOK(ret); - - talloc_free(match); - ret = copy_substring(ypctx, str, "month_number", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ypctx, per->month, MONTH_BUFSIZE); - ret = interval2bitfield(ypctx, per->month, match, - 1, MONTH_MAX, names_months); - JMP_NEOK(ret); - - talloc_free(match); - ret = copy_substring(ypctx, str, "m_period", &match); - JMP_NEOK(ret); - DEBUG(7, ("Monthly year period - calling parse_periodic_monthly()\n")); - ret = parse_periodic_monthly(ypctx, trctx, per, match); - JMP_NEOK(ret); - -done: - talloc_free(ypctx); - return ret; -} - -/* - * Parses weekly periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic_weekly(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - struct periodic_range *per, - const char *str) -{ - int ret; - struct parse_ctx *wpctx = NULL; - char *dow = NULL; - - ret = matches_regexp(ctx, trctx, str, LP_RGX_WEEKLY, &wpctx); - JMP_NEOK(ret); - - ret = copy_substring(wpctx, str, "day_of_week", &dow); - JMP_NEOK(ret); - DEBUG(8, ("day_of_week = '%s'\n", dow)); - - ret = interval2bitfield(wpctx, &per->day_of_week, dow, - 1, DAY_OF_WEEK_MAX, names_day_of_week); - -done: - talloc_free(wpctx); - return ret; -} - -static int parse_periodic_time(struct periodic_range *per, - struct parse_ctx *pctx, - const char *str) -{ - char *substr = NULL; - int ret; - - int hour_from; - int hour_to; - int min_from; - int min_to; - - /* parse out the time */ - ret = copy_substring(pctx, str, "timeFrom", &substr); - JMP_NEOK(ret); - parse_hhmm(substr, &hour_from, &min_from); - DEBUG(7, ("Parsed timeFrom: %d:%d\n", hour_from, min_from)); - JMP_NEOK(ret); - - talloc_free(substr); - ret = copy_substring(pctx, str, "timeTo", &substr); - JMP_NEOK(ret); - parse_hhmm(substr, &hour_to, &min_to); - DEBUG(7, ("Parsed timeTo: %d:%d\n", hour_to, min_to)); - JMP_NEOK(ret); - - /* set the interval */ - if (hour_from > hour_to ) { - set_bit_range(per->hour, 0, hour_to); - set_bit_range(per->hour, hour_from, HOUR_MAX); - } else { - set_bit_range(per->hour, hour_from, hour_to); - } - - if (min_from > min_to) { - set_bit_range(per->minute, 0, min_to); - set_bit_range(per->minute, min_from, MINUTE_MAX); - } else { - set_bit_range(per->minute, min_from, min_to); - } - - - ret = EOK; -done: - talloc_free(substr); - return ret; -} - -/* - * Parses periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic(struct periodic_range *per, - struct time_rules_ctx *trctx, - struct parse_ctx *pctx, - const char *str) -{ - char *substr = NULL; - char *period = NULL; - int ret; - - /* These are mandatory */ - BUFFER_OR_JUMP(per, per->hour, HOUR_BUFSIZE); - BUFFER_OR_JUMP(per, per->minute, MINUTE_BUFSIZE); - - ret = copy_substring(pctx, str, "perspec", &substr); - JMP_NEOK(ret); - ret = copy_substring(pctx, str, "period", &period); - JMP_NEOK(ret); - - if (strcmp(substr, "yearly") == 0) { - DEBUG(5, ("periodic yearly\n")); - ret = parse_periodic_yearly(pctx, trctx, per, period); - JMP_NEOK(ret); - } else if (strcmp(substr, "monthly") == 0) { - DEBUG(5, ("periodic monthly\n")); - ret = parse_periodic_monthly(pctx, trctx, per, period); - JMP_NEOK(ret); - } else if (strcmp(substr, "weekly") == 0) { - DEBUG(5, ("periodic weekly\n")); - ret = parse_periodic_weekly(pctx, trctx, per, period); - JMP_NEOK(ret); - } else if (strcmp(substr, "daily") == 0) { - DEBUG(5, ("periodic daily\n")); - } else { - DEBUG(1, ("Cannot determine periodic rule type" - "(perspec = '%s', period = '%s')\n", substr, period)); - ret = EINVAL; - goto done; - } - - talloc_free(period); - - ret = parse_periodic_time(per, pctx, str); - JMP_NEOK(ret); - - ret = EOK; -done: - talloc_free(substr); - return ret; -} - -/* - * Parses time specification given in string RULE into range_ctx - * context CTX. - */ -static int parse_timespec(struct range_ctx *ctx, const char *rule) -{ - int ret; - struct parse_ctx *pctx = NULL; - - if (matches_regexp(ctx, ctx->trctx, rule, LP_RGX_ABSOLUTE, &pctx) == EOK) { - DEBUG(5, ("Matched absolute range\n")); - ctx->type = TYPE_ABSOLUTE; - ctx->abs = talloc_zero(ctx, struct absolute_range); - CHECK_PTR_JMP(ctx->abs); - - ret = parse_absolute(ctx->abs, ctx->trctx, pctx, rule); - JMP_NEOK(ret); - } else if (matches_regexp(ctx, ctx->trctx, rule, LP_RGX_PERIODIC, &pctx) == EOK) { - DEBUG(5, ("Matched periodic range\n")); - ctx->type = TYPE_PERIODIC; - ctx->per = talloc_zero(ctx, struct periodic_range); - CHECK_PTR_JMP(ctx->per); - - ret = parse_periodic(ctx->per, ctx->trctx, pctx, rule); - JMP_NEOK(ret); - } else { - DEBUG(1, ("Cannot determine rule type\n")); - ret = EINVAL; - goto done; - } - - ret = EOK; -done: - talloc_free(pctx); - return ret; -} - -/******************************************************************* - * validation of rules against time_t * - *******************************************************************/ - -static int absolute_timerange_valid(struct absolute_range *absr, - const time_t now, - bool *result) -{ - if (difftime(absr->time_from, now) > 0) { - DEBUG(3, ("Absolute timerange invalid (before interval)\n")); - *result = false; - return EOK; - } - - if (difftime(absr->time_to, now) < 0) { - DEBUG(3, ("Absolute timerange invalid (after interval)\n")); - *result = false; - return EOK; - } - - DEBUG(3, ("Absolute timerange valid\n")); - *result = true; - return EOK; -} - -static int periodic_timerange_valid(struct periodic_range *per, - const time_t now, - bool *result) -{ - struct tm tm_now; - int wnum; - int wom; - - memset(&tm_now, 0, sizeof(struct tm)); - if (localtime_r(&now, &tm_now) == NULL) { - DEBUG(0, ("Cannot convert time_t to struct tm\n")); - return EFAULT; - } - DEBUG(9, ("Got struct tm value %s", asctime(&tm_now))); - tm2abs(&tm_now); - - wnum = weeknum(&tm_now); - if (wnum == -1) { - DEBUG(7, ("Cannot get week number")); - return EINVAL; - } - DEBUG(9, ("Week number is %d\n", wnum)); - - wom = get_week_of_month(&tm_now); - if (wnum == -1) { - DEBUG(7, ("Cannot get week of number")); - return EINVAL; - } - DEBUG(9, ("Week of month number is %d\n", wom)); - - /* The validation itself */ - TEST_BIT_RANGE(per->day_of_week, tm_now.tm_wday, result); - DEBUG(9, ("day of week OK\n")); - TEST_BIT_RANGE_PTR(per->day_of_month, tm_now.tm_mday, result); - DEBUG(9, ("day of month OK\n")); - TEST_BIT_RANGE(per->week_of_month, wom, result); - DEBUG(9, ("week of month OK\n")); - TEST_BIT_RANGE_PTR(per->week_of_year, wnum, result); - DEBUG(9, ("week of year OK\n")); - TEST_BIT_RANGE_PTR(per->month, tm_now.tm_mon, result); - DEBUG(9, ("month OK\n")); - TEST_BIT_RANGE_PTR(per->day_of_year, tm_now.tm_yday, result); - DEBUG(9, ("day of year OK\n")); - TEST_BIT_RANGE_PTR(per->hour, tm_now.tm_hour, result); - DEBUG(9, ("hour OK\n")); - TEST_BIT_RANGE_PTR(per->minute, tm_now.tm_min, result); - DEBUG(9, ("minute OK\n")); - - DEBUG(3, ("Periodic timerange valid\n")); - *result = true; - return EOK; -} - -/* - * Returns EOK if the timerange in range_ctx context is valid compared against a - * given time_t value in NOW, returns ERANGE if the time value is outside the - * specified range. - */ -static int timerange_valid(struct range_ctx *ctx, - const time_t now, - bool *result) -{ - int ret; - - switch(ctx->type) { - case TYPE_ABSOLUTE: - DEBUG(7, ("Checking absolute range\n")); - ret = absolute_timerange_valid(ctx->abs, now, result); - break; - - case TYPE_PERIODIC: - DEBUG(7, ("Checking periodic range\n")); - ret = periodic_timerange_valid(ctx->per, now, result); - break; - - default: - DEBUG(1, ("Unknown range type (%d)\n", ctx->type)); - ret = EINVAL; - break; - } - - return ret; -} - -/******************************************************************* - * public interface * - *******************************************************************/ - -/* - * This is actually the meat of the library. The function takes a string - * representation of a time rule in STR and time to check against (usually that - * would be current time) in NOW. - * - * It returns EOK if the rule is valid in the current time, ERANGE if not and - * EINVAL if the rule cannot be parsed - */ -int check_time_rule(TALLOC_CTX *mem_ctx, - struct time_rules_ctx *trctx, - const char *str, - const time_t now, - bool *result) -{ - int ret; - struct range_ctx *ctx; - - ctx = talloc_zero(mem_ctx, struct range_ctx); - CHECK_PTR_JMP(ctx); - ctx->trctx = trctx; - - DEBUG(9, ("Got time_t value %s", ctime(&now))); - - ret = parse_timespec(ctx, str); - if (ret != EOK) { - DEBUG(1, ("Cannot parse the time specification (%d)\n", ret)); - goto done; - } - - ret = timerange_valid(ctx, now, result); - if (ret != EOK) { - DEBUG(1, ("Cannot check the time range (%d)\n", ret)); - goto done; - } - - ret = EOK; -done: - talloc_free(ctx); - return EOK; -} - -/* - * Frees the resources taken by the precompiled rules - */ -static int time_rules_parser_destructor(struct time_rules_ctx *ctx) -{ - int i; - - for (i = 0; i< LP_RGX_MAX; ++i) { - pcre_free(ctx->re[i]); - ctx->re[i] = NULL; - } - - return 0; -} - -/* - * Initializes the parser by precompiling the regular expressions - * for later use - */ -int init_time_rules_parser(TALLOC_CTX *mem_ctx, - struct time_rules_ctx **_out) -{ - const char *errstr; - int errval; - int errpos; - int ret; - int i; - struct time_rules_ctx *ctx = NULL; - - ctx = talloc_zero(mem_ctx, struct time_rules_ctx); - CHECK_PTR(ctx); - talloc_set_destructor(ctx, time_rules_parser_destructor); - - /* Precompile regular expressions */ - for (i = LP_RGX_GENERALIZED; i< LP_RGX_MAX; ++i) { - ctx->re[i] = pcre_compile2(lookup_table[i], - 0, - &errval, - &errstr, - &errpos, - NULL); - - if (ctx->re[i] == NULL) { - DEBUG(0, ("Invalid Regular Expression pattern '%s' at position %d" - " (Error: %d [%s])\n", lookup_table[i], - errpos, errval, errstr)); - ret = EFAULT; - goto done; - } - - } - - *_out = ctx; - return EOK; -done: - talloc_free(ctx); - return ret; -} - diff --git a/server/providers/ipa/ipa_timerules.h b/server/providers/ipa/ipa_timerules.h deleted file mode 100644 index e1beaa22..00000000 --- a/server/providers/ipa/ipa_timerules.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - SSSD - - IPA Provider Time Rules Parsing - - Authors: - Jakub Hrozek <jhrozek@redhat.com> - - Copyright (C) Red Hat, Inc 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef __IPA_TIMERULES_H_ -#define __IPA_TIMERULES_H_ - -#include <stdbool.h> -#include <talloc.h> - -/* Opaque structure given after init */ -struct time_rules_ctx; - -/* - * Init the parser. Destroy the allocated resources by simply - * talloc_free()-ing the time_rules_ctx - */ -int init_time_rules_parser(TALLOC_CTX *mem_ctx, - struct time_rules_ctx **_out); - -/* - * This is actually the meat of the library. The function takes a string - * representation of a time rule in STR and time to check against (usually that - * would be current time) in NOW. - * - * It returns EOK if the rule can be parsed, error code if not. If the time - * given in the NOW parameter would be accepted by the rule, it stores true in - * RESULT, false otherwise. - */ -int check_time_rule(TALLOC_CTX *mem_ctx, - struct time_rules_ctx *trctx, - const char *str, - const time_t now, - bool *result); - -#endif /* __IPA_TIMERULES_H_ */ |