From 827a016a07d5f911cc4195be89896a376fd71f59 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 26 May 2015 14:29:17 +0200 Subject: IFP: add FindByCertificate method for User objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related to https://fedorahosted.org/sssd/ticket/2596 Reviewed-by: Pavel Březina --- Makefile.am | 4 +- src/responder/common/responder.h | 3 +- src/responder/common/responder_cache_req.c | 88 +++++++++++++++++++++++++++--- src/responder/common/responder_cache_req.h | 19 ++++++- src/responder/common/responder_dp.c | 11 ++++ src/responder/ifp/ifp_iface.c | 1 + src/responder/ifp/ifp_iface.xml | 4 ++ src/responder/ifp/ifp_iface_generated.c | 26 +++++++++ src/responder/ifp/ifp_iface_generated.h | 5 ++ src/responder/ifp/ifp_users.c | 87 +++++++++++++++++++++++++++++ src/responder/ifp/ifp_users.h | 4 ++ src/responder/ifp/ifpsrv_cmd.c | 4 +- 12 files changed, 242 insertions(+), 14 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1d80c3671..93a32dbdb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1139,7 +1139,9 @@ sssd_ifp_CFLAGS = \ $(AM_CFLAGS) sssd_ifp_LDADD = \ $(SSSD_LIBS) \ - $(SSSD_INTERNAL_LTLIBS) + $(SSSD_INTERNAL_LTLIBS) \ + libsss_cert.la \ + $(NULL) dist_dbuspolicy_DATA = \ src/responder/ifp/org.freedesktop.sssd.infopipe.conf dist_dbusservice_DATA = \ diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h index 9c7a73809..bd0250d52 100644 --- a/src/responder/common/responder.h +++ b/src/responder/common/responder.h @@ -281,7 +281,8 @@ enum sss_dp_acct_type { SSS_DP_NETGR, SSS_DP_SERVICES, SSS_DP_SECID, - SSS_DP_USER_AND_GROUP + SSS_DP_USER_AND_GROUP, + SSS_DP_CERT }; struct tevent_req * diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c index 7ba257276..dd81abadf 100644 --- a/src/responder/common/responder_cache_req.c +++ b/src/responder/common/responder_cache_req.c @@ -34,6 +34,7 @@ struct cache_req_input { /* Provided input. */ const char *orig_name; uint32_t id; + const char *cert; /* Data Provider request type resolved from @type. * FIXME: This is currently needed for data provider calls. We should @@ -56,7 +57,8 @@ struct cache_req_input * cache_req_input_create(TALLOC_CTX *mem_ctx, enum cache_req_type type, const char *name, - uint32_t id) + uint32_t id, + const char *cert) { struct cache_req_input *input; @@ -82,6 +84,17 @@ cache_req_input_create(TALLOC_CTX *mem_ctx, goto fail; } break; + case CACHE_REQ_USER_BY_CERT: + if (cert == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Bug: certificate cannot be NULL!\n"); + goto fail; + } + + input->cert = talloc_strdup(input, cert); + if (input->cert == NULL) { + goto fail; + } + break; case CACHE_REQ_USER_BY_ID: case CACHE_REQ_GROUP_BY_ID: if (id == 0) { @@ -108,6 +121,9 @@ cache_req_input_create(TALLOC_CTX *mem_ctx, case CACHE_REQ_INITGROUPS: input->dp_type = SSS_DP_INITGROUPS; break; + case CACHE_REQ_USER_BY_CERT: + input->dp_type = SSS_DP_CERT; + break; } return input; @@ -192,6 +208,17 @@ cache_req_input_set_domain(struct cache_req_input *input, goto done; } break; + case CACHE_REQ_USER_BY_CERT: + /* certificates might be quite long, only use the last 10 charcters + * for logging */ + fqn = talloc_asprintf(tmp_ctx, "CERT:%s@%s", + get_last_x_chars(input->cert, 10), + domain->name); + if (fqn == NULL) { + ret = ENOMEM; + goto done; + } + break; } input->domain = domain; @@ -227,6 +254,9 @@ static errno_t cache_req_check_ncache(struct cache_req_input *input, case CACHE_REQ_GROUP_BY_ID: ret = sss_ncache_check_gid(ncache, neg_timeout, input->id); break; + case CACHE_REQ_USER_BY_CERT: + ret = sss_ncache_check_cert(ncache, neg_timeout, input->cert); + break; } if (ret == EEXIST) { @@ -254,6 +284,7 @@ static void cache_req_add_to_ncache(struct cache_req_input *input, break; case CACHE_REQ_USER_BY_ID: case CACHE_REQ_GROUP_BY_ID: + case CACHE_REQ_USER_BY_CERT: /* Nothing to do. Those types must be unique among all domains so * the don't contain domain part. Therefore they must be set only * if all domains are search and the entry is not found. */ @@ -290,6 +321,9 @@ static void cache_req_add_to_ncache_global(struct cache_req_input *input, case CACHE_REQ_GROUP_BY_ID: ret = sss_ncache_set_gid(ncache, false, input->id); break; + case CACHE_REQ_USER_BY_CERT: + ret = sss_ncache_set_cert(ncache, false, input->cert); + break; } if (ret != EOK) { @@ -338,6 +372,11 @@ static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx, ret = sysdb_initgroups_with_views(mem_ctx, input->domain, input->dom_objname, &result); break; + case CACHE_REQ_USER_BY_CERT: + one_item_only = true; + ret = sysdb_search_user_by_cert(mem_ctx, input->domain, + input->cert, &result); + break; } if (ret != EOK) { @@ -461,6 +500,7 @@ static errno_t cache_req_cache_check(struct tevent_req *req) const char *extra_flag = NULL; uint64_t cache_expire = 0; errno_t ret; + const char *search_str; state = tevent_req_data(req, struct cache_req_cache_state); @@ -479,6 +519,10 @@ static errno_t cache_req_cache_check(struct tevent_req *req) state->cache_refresh_percent, cache_expire); } + search_str = state->input->dom_objname; + if (state->input->type == CACHE_REQ_USER_BY_CERT) { + search_str = state->input->cert; + } switch (ret) { case EOK: DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning...\n"); @@ -492,7 +536,7 @@ static errno_t cache_req_cache_check(struct tevent_req *req) subreq = sss_dp_get_account_send(state, state->rctx, state->input->domain, true, state->input->dp_type, - state->input->dom_objname, + search_str, state->input->id, NULL); if (subreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory sending out-of-band " @@ -514,7 +558,7 @@ static errno_t cache_req_cache_check(struct tevent_req *req) subreq = sss_dp_get_account_send(state, state->rctx, state->input->domain, true, state->input->dp_type, - state->input->dom_objname, + search_str, state->input->id, extra_flag); if (subreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, @@ -890,7 +934,8 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx, { struct cache_req_input *input; - input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_NAME, name, 0); + input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_NAME, name, 0, + NULL); if (input == NULL) { return NULL; } @@ -912,7 +957,31 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx, { struct cache_req_input *input; - input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_ID, NULL, uid); + input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_ID, NULL, uid, + NULL); + if (input == NULL) { + return NULL; + } + + return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache, + neg_timeout, cache_refresh_percent, + domain, input); +} + +struct tevent_req * +cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int neg_timeout, + int cache_refresh_percent, + const char *domain, + const char *pem_cert) +{ + struct cache_req_input *input; + + input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_CERT, + NULL, 0, pem_cert); if (input == NULL) { return NULL; } @@ -934,7 +1003,8 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, { struct cache_req_input *input; - input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_NAME, name, 0); + input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_NAME, name, 0, + NULL); if (input == NULL) { return NULL; } @@ -956,7 +1026,8 @@ cache_req_group_by_id_send(TALLOC_CTX *mem_ctx, { struct cache_req_input *input; - input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_ID, NULL, gid); + input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_ID, NULL, gid, + NULL); if (input == NULL) { return NULL; } @@ -978,7 +1049,8 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx, { struct cache_req_input *input; - input = cache_req_input_create(mem_ctx, CACHE_REQ_INITGROUPS, name, 0); + input = cache_req_input_create(mem_ctx, CACHE_REQ_INITGROUPS, name, 0, + NULL); if (input == NULL) { return NULL; } diff --git a/src/responder/common/responder_cache_req.h b/src/responder/common/responder_cache_req.h index 088e8efe0..84a9dde7d 100644 --- a/src/responder/common/responder_cache_req.h +++ b/src/responder/common/responder_cache_req.h @@ -32,7 +32,8 @@ enum cache_req_type { CACHE_REQ_USER_BY_ID, CACHE_REQ_GROUP_BY_NAME, CACHE_REQ_GROUP_BY_ID, - CACHE_REQ_INITGROUPS + CACHE_REQ_INITGROUPS, + CACHE_REQ_USER_BY_CERT }; struct cache_req_input; @@ -41,7 +42,8 @@ struct cache_req_input * cache_req_input_create(TALLOC_CTX *mem_ctx, enum cache_req_type type, const char *name, - uint32_t id); + uint32_t id, + const char *cert); /** * Currently only SSS_DP_USER and SSS_DP_INITGROUPS are supported. @@ -89,6 +91,19 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx, #define cache_req_user_by_id_recv(mem_ctx, req, _result, _domain) \ cache_req_recv(mem_ctx, req, _result, _domain, NULL) +struct tevent_req * +cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int neg_timeout, + int cache_refresh_percent, + const char *domain, + const char *pem_cert); + +#define cache_req_user_by_cert_recv(mem_ctx, req, _result, _domain, _name) \ + cache_req_recv(mem_ctx, req, _result, _domain, _name) + struct tevent_req * cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c index 853b3eae3..f752c94c3 100644 --- a/src/responder/common/responder_dp.c +++ b/src/responder/common/responder_dp.c @@ -548,6 +548,9 @@ sss_dp_get_account_msg(void *pvt) case SSS_DP_USER_AND_GROUP: be_type = BE_REQ_USER_AND_GROUP; break; + case SSS_DP_CERT: + be_type = BE_REQ_BY_CERT; + break; } if (info->fast_reply) { @@ -563,6 +566,14 @@ sss_dp_get_account_msg(void *pvt) filter = talloc_asprintf(info, "%s=%s", DP_SEC_ID, info->opt_name); } + } else if (info->type == SSS_DP_CERT) { + if (info->extra) { + filter = talloc_asprintf(info, "%s=%s:%s", DP_CERT, + info->opt_name, info->extra); + } else { + filter = talloc_asprintf(info, "%s=%s", DP_CERT, + info->opt_name); + } } else { if (info->extra) { filter = talloc_asprintf(info, "name=%s:%s", diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c index 015c66dc5..86d8d338c 100644 --- a/src/responder/ifp/ifp_iface.c +++ b/src/responder/ifp/ifp_iface.c @@ -82,6 +82,7 @@ struct iface_ifp_users iface_ifp_users = { { &iface_ifp_users_meta, 0 }, .FindByName = ifp_users_find_by_name, .FindByID = ifp_users_find_by_id, + .FindByCertificate = ifp_users_find_by_cert, .ListByName = ifp_users_list_by_name, .ListByDomainAndName = ifp_users_list_by_domain_and_name }; diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml index 628692af6..5a56b624a 100644 --- a/src/responder/ifp/ifp_iface.xml +++ b/src/responder/ifp/ifp_iface.xml @@ -136,6 +136,10 @@ + + + + diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c index 8255cbea7..a4fdd5d12 100644 --- a/src/responder/ifp/ifp_iface_generated.c +++ b/src/responder/ifp/ifp_iface_generated.c @@ -685,6 +685,25 @@ int iface_ifp_users_FindByID_finish(struct sbus_request *req, const char *arg_re DBUS_TYPE_INVALID); } +/* arguments for org.freedesktop.sssd.infopipe.Users.FindByCertificate */ +const struct sbus_arg_meta iface_ifp_users_FindByCertificate__in[] = { + { "pem_cert", "s" }, + { NULL, } +}; + +/* arguments for org.freedesktop.sssd.infopipe.Users.FindByCertificate */ +const struct sbus_arg_meta iface_ifp_users_FindByCertificate__out[] = { + { "result", "o" }, + { NULL, } +}; + +int iface_ifp_users_FindByCertificate_finish(struct sbus_request *req, const char *arg_result) +{ + return sbus_request_return_and_finish(req, + DBUS_TYPE_OBJECT_PATH, &arg_result, + DBUS_TYPE_INVALID); +} + /* arguments for org.freedesktop.sssd.infopipe.Users.ListByName */ const struct sbus_arg_meta iface_ifp_users_ListByName__in[] = { { "name_filter", "s" }, @@ -742,6 +761,13 @@ const struct sbus_method_meta iface_ifp_users__methods[] = { offsetof(struct iface_ifp_users, FindByID), invoke_u_method, }, + { + "FindByCertificate", /* name */ + iface_ifp_users_FindByCertificate__in, + iface_ifp_users_FindByCertificate__out, + offsetof(struct iface_ifp_users, FindByCertificate), + invoke_s_method, + }, { "ListByName", /* name */ iface_ifp_users_ListByName__in, diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h index d2e5cdd3a..4dfe61ddf 100644 --- a/src/responder/ifp/ifp_iface_generated.h +++ b/src/responder/ifp/ifp_iface_generated.h @@ -68,6 +68,7 @@ #define IFACE_IFP_USERS "org.freedesktop.sssd.infopipe.Users" #define IFACE_IFP_USERS_FINDBYNAME "FindByName" #define IFACE_IFP_USERS_FINDBYID "FindByID" +#define IFACE_IFP_USERS_FINDBYCERTIFICATE "FindByCertificate" #define IFACE_IFP_USERS_LISTBYNAME "ListByName" #define IFACE_IFP_USERS_LISTBYDOMAINANDNAME "ListByDomainAndName" @@ -235,6 +236,7 @@ struct iface_ifp_users { struct sbus_vtable vtable; /* derive from sbus_vtable */ int (*FindByName)(struct sbus_request *req, void *data, const char *arg_name); int (*FindByID)(struct sbus_request *req, void *data, uint32_t arg_id); + int (*FindByCertificate)(struct sbus_request *req, void *data, const char *arg_pem_cert); int (*ListByName)(struct sbus_request *req, void *data, const char *arg_name_filter, uint32_t arg_limit); int (*ListByDomainAndName)(struct sbus_request *req, void *data, const char *arg_domain_name, const char *arg_name_filter, uint32_t arg_limit); }; @@ -245,6 +247,9 @@ int iface_ifp_users_FindByName_finish(struct sbus_request *req, const char *arg_ /* finish function for FindByID */ int iface_ifp_users_FindByID_finish(struct sbus_request *req, const char *arg_result); +/* finish function for FindByCertificate */ +int iface_ifp_users_FindByCertificate_finish(struct sbus_request *req, const char *arg_result); + /* finish function for ListByName */ int iface_ifp_users_ListByName_finish(struct sbus_request *req, const char *arg_result[], int len_result); diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c index fa6f47f0d..2ec74c30b 100644 --- a/src/responder/ifp/ifp_users.c +++ b/src/responder/ifp/ifp_users.c @@ -25,6 +25,7 @@ #include "db/sysdb.h" #include "util/util.h" #include "util/strtonum.h" +#include "util/cert.h" #include "sbus/sssd_dbus_errors.h" #include "responder/common/responder.h" #include "responder/common/responder_cache_req.h" @@ -222,6 +223,92 @@ done: return; } +static void ifp_users_find_by_cert_done(struct tevent_req *req); + +int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data, + const char *pem_cert) +{ + struct ifp_ctx *ctx; + struct tevent_req *req; + int ret; + char *derb64; + DBusError *error; + + ctx = talloc_get_type(data, struct ifp_ctx); + if (ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return ERR_INTERNAL; + } + + ret = sss_cert_pem_to_derb64(sbus_req, pem_cert, &derb64); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_cert_pem_to_derb64 failed.\n"); + + if (ret == ENOMEM) { + return ret; + } + + error = sbus_error_new(sbus_req, DBUS_ERROR_INVALID_ARGS, + "Invalid certificate format"); + sbus_request_fail_and_finish(sbus_req, error); + /* the connection is already terminated with an error message, hence + * we have to return EOK to not terminate the connection twice. */ + return EOK; + } + + req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->ncache, ctx->neg_timeout, 0, + NULL, derb64); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_set_callback(req, ifp_users_find_by_cert_done, sbus_req); + + return EOK; +} + +static void ifp_users_find_by_cert_done(struct tevent_req *req) +{ + DBusError *error; + struct sbus_request *sbus_req; + struct sss_domain_info *domain; + struct ldb_result *result; + char *object_path; + errno_t ret; + + sbus_req = tevent_req_callback_data(req, struct sbus_request); + + ret = cache_req_user_by_cert_recv(sbus_req, req, &result, &domain, NULL); + talloc_zfree(req); + if (ret == ENOENT) { + error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND, + "User not found"); + goto done; + } else if (ret != EOK) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " + "user [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + object_path = ifp_users_build_path_from_msg(sbus_req, domain, + result->msgs[0]); + if (object_path == NULL) { + error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, + "Failed to compose object path"); + goto done; + } + +done: + if (ret != EOK) { + sbus_request_fail_and_finish(sbus_req, error); + return; + } + + iface_ifp_users_FindByCertificate_finish(sbus_req, object_path); + return; +} + int ifp_users_list_by_name(struct sbus_request *sbus_req, void *data, const char *filter, diff --git a/src/responder/ifp/ifp_users.h b/src/responder/ifp/ifp_users.h index 4da0a7347..471c3fb01 100644 --- a/src/responder/ifp/ifp_users.h +++ b/src/responder/ifp/ifp_users.h @@ -43,6 +43,10 @@ int ifp_users_find_by_id(struct sbus_request *sbus_req, void *data, uint32_t id); +int ifp_users_find_by_cert(struct sbus_request *sbus_req, + void *data, + const char *pem_cert); + int ifp_users_list_by_name(struct sbus_request *sbus_req, void *data, const char *filter, diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c index d4d5dc640..ab6156fd6 100644 --- a/src/responder/ifp/ifpsrv_cmd.c +++ b/src/responder/ifp/ifpsrv_cmd.c @@ -497,11 +497,11 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq) switch (state->search_type) { case SSS_DP_USER: input = cache_req_input_create(state, CACHE_REQ_USER_BY_NAME, - state->name, 0); + state->name, 0, NULL); break; case SSS_DP_INITGROUPS: input = cache_req_input_create(state, CACHE_REQ_INITGROUPS, - state->name, 0); + state->name, 0, NULL); break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported search type [%d]!\n", -- cgit