diff options
-rw-r--r-- | src/responder/ifp/ifp_iface.c | 1 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface.xml | 5 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface_generated.c | 49 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface_generated.h | 5 | ||||
-rw-r--r-- | src/responder/ifp/ifp_users.c | 295 | ||||
-rw-r--r-- | src/responder/ifp/ifp_users.h | 5 |
6 files changed, 360 insertions, 0 deletions
diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c index 4fea60565..e413e74f9 100644 --- a/src/responder/ifp/ifp_iface.c +++ b/src/responder/ifp/ifp_iface.c @@ -88,6 +88,7 @@ struct iface_ifp_users iface_ifp_users = { .FindByID = ifp_users_find_by_id, .FindByCertificate = ifp_users_find_by_cert, .ListByCertificate = ifp_users_list_by_cert, + .FindByNameAndCertificate = ifp_users_find_by_name_and_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 93ccf90cb..0a23f5690 100644 --- a/src/responder/ifp/ifp_iface.xml +++ b/src/responder/ifp/ifp_iface.xml @@ -157,6 +157,11 @@ <arg name="limit" type="u" direction="in" /> <arg name="result" type="ao" direction="out" /> </method> + <method name="FindByNameAndCertificate"> + <arg name="name" type="s" direction="in" /> + <arg name="pem_cert" type="s" direction="in" /> + <arg name="result" type="o" direction="out" /> + </method> <method name="ListByName"> <arg name="name_filter" type="s" direction="in" /> <arg name="limit" type="u" direction="in" /> diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c index 7ad9c34b9..211646b67 100644 --- a/src/responder/ifp/ifp_iface_generated.c +++ b/src/responder/ifp/ifp_iface_generated.c @@ -15,6 +15,9 @@ static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr); /* invokes a handler with a 'su' DBus signature */ static int invoke_su_method(struct sbus_request *dbus_req, void *function_ptr); +/* invokes a handler with a 'ss' DBus signature */ +static int invoke_ss_method(struct sbus_request *dbus_req, void *function_ptr); + /* invokes a handler with a 'ssu' DBus signature */ static int invoke_ssu_method(struct sbus_request *dbus_req, void *function_ptr); @@ -762,6 +765,26 @@ int iface_ifp_users_ListByCertificate_finish(struct sbus_request *req, const cha DBUS_TYPE_INVALID); } +/* arguments for org.freedesktop.sssd.infopipe.Users.FindByNameAndCertificate */ +const struct sbus_arg_meta iface_ifp_users_FindByNameAndCertificate__in[] = { + { "name", "s" }, + { "pem_cert", "s" }, + { NULL, } +}; + +/* arguments for org.freedesktop.sssd.infopipe.Users.FindByNameAndCertificate */ +const struct sbus_arg_meta iface_ifp_users_FindByNameAndCertificate__out[] = { + { "result", "o" }, + { NULL, } +}; + +int iface_ifp_users_FindByNameAndCertificate_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" }, @@ -834,6 +857,13 @@ const struct sbus_method_meta iface_ifp_users__methods[] = { invoke_su_method, }, { + "FindByNameAndCertificate", /* name */ + iface_ifp_users_FindByNameAndCertificate__in, + iface_ifp_users_FindByNameAndCertificate__out, + offsetof(struct iface_ifp_users, FindByNameAndCertificate), + invoke_ss_method, + }, + { "ListByName", /* name */ iface_ifp_users_ListByName__in, iface_ifp_users_ListByName__out, @@ -1170,6 +1200,25 @@ const struct sbus_interface_meta iface_ifp_groups_group_meta = { sbus_invoke_get_all, /* GetAll invoker */ }; +/* invokes a handler with a 'ss' DBus signature */ +static int invoke_ss_method(struct sbus_request *dbus_req, void *function_ptr) +{ + const char * arg_0; + const char * arg_1; + int (*handler)(struct sbus_request *, void *, const char *, const char *) = function_ptr; + + if (!sbus_request_parse_or_finish(dbus_req, + DBUS_TYPE_STRING, &arg_0, + DBUS_TYPE_STRING, &arg_1, + DBUS_TYPE_INVALID)) { + return EOK; /* request handled */ + } + + return (handler)(dbus_req, dbus_req->intf->handler_data, + arg_0, + arg_1); +} + /* invokes a handler with a 'ssu' DBus signature */ static int invoke_ssu_method(struct sbus_request *dbus_req, void *function_ptr) { diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h index 80b9aa290..e69fc3a3e 100644 --- a/src/responder/ifp/ifp_iface_generated.h +++ b/src/responder/ifp/ifp_iface_generated.h @@ -73,6 +73,7 @@ #define IFACE_IFP_USERS_FINDBYID "FindByID" #define IFACE_IFP_USERS_FINDBYCERTIFICATE "FindByCertificate" #define IFACE_IFP_USERS_LISTBYCERTIFICATE "ListByCertificate" +#define IFACE_IFP_USERS_FINDBYNAMEANDCERTIFICATE "FindByNameAndCertificate" #define IFACE_IFP_USERS_LISTBYNAME "ListByName" #define IFACE_IFP_USERS_LISTBYDOMAINANDNAME "ListByDomainAndName" @@ -249,6 +250,7 @@ struct iface_ifp_users { 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 (*ListByCertificate)(struct sbus_request *req, void *data, const char *arg_pem_cert, uint32_t arg_limit); + int (*FindByNameAndCertificate)(struct sbus_request *req, void *data, const char *arg_name, 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); }; @@ -265,6 +267,9 @@ int iface_ifp_users_FindByCertificate_finish(struct sbus_request *req, const cha /* finish function for ListByCertificate */ int iface_ifp_users_ListByCertificate_finish(struct sbus_request *req, const char *arg_result[], int len_result); +/* finish function for FindByNameAndCertificate */ +int iface_ifp_users_FindByNameAndCertificate_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 26e07aadb..cc78300f3 100644 --- a/src/responder/ifp/ifp_users.c +++ b/src/responder/ifp/ifp_users.c @@ -446,6 +446,301 @@ static int ifp_users_list_copy(struct ifp_list_ctx *list_ctx, return EOK; } +struct name_and_cert_ctx { + const char *name; + char *derb64; + struct sbus_request *sbus_req; + char *user_opath; + struct ifp_list_ctx *list_ctx; +}; + +static void ifp_users_find_by_name_and_cert_name_done(struct tevent_req *req); +static int ifp_users_find_by_name_and_cert_step( + struct name_and_cert_ctx *name_and_cert_ctx); +static void ifp_users_find_by_name_and_cert_done(struct tevent_req *req); +static void ifp_users_find_by_name_and_cert_reply( + struct name_and_cert_ctx *name_and_cert_ctx); + +int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, void *data, + const char *name, const char *pem_cert) +{ + struct ifp_ctx *ctx; + struct tevent_req *req; + int ret; + struct name_and_cert_ctx *name_and_cert_ctx = NULL; + DBusError *error; + + ctx = talloc_get_type(data, struct ifp_ctx); + if (ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return ERR_INTERNAL; + } + + if ((name == NULL || *name == '\0') + && (pem_cert == NULL || *pem_cert == '\0')) { + error = sbus_error_new(sbus_req, DBUS_ERROR_INVALID_ARGS, + "Missing input"); + 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; + } + + name_and_cert_ctx = talloc_zero(sbus_req, struct name_and_cert_ctx); + if (name_and_cert_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc failed.\n"); + return ENOMEM; + } + + name_and_cert_ctx->sbus_req = sbus_req; + + if (name != NULL && *name != '\0') { + name_and_cert_ctx->name = talloc_strdup(name_and_cert_ctx, name); + if (name_and_cert_ctx->name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + return ENOMEM; + } + } + + if (pem_cert != NULL && *pem_cert != '\0') { + ret = sss_cert_pem_to_derb64(name_and_cert_ctx, pem_cert, + &(name_and_cert_ctx->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; + } + + /* FIXME: if unlimted searches with limit=0 will work please replace + * 100 with 0. */ + name_and_cert_ctx->list_ctx = ifp_list_ctx_new(sbus_req, ctx, + name_and_cert_ctx->derb64, + 100); + if (name_and_cert_ctx->list_ctx == NULL) { + return ENOMEM; + } + } + + if (name_and_cert_ctx->name != NULL) { + req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->rctx->ncache, 0, NULL, + name_and_cert_ctx->name); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_set_callback(req, ifp_users_find_by_name_and_cert_name_done, + name_and_cert_ctx); + } else { + ret = ifp_users_find_by_name_and_cert_step(name_and_cert_ctx); + if (ret != EOK) { + return ret; + } + } + + return EOK; +} + +static void ifp_users_find_by_name_and_cert_name_done(struct tevent_req *req) +{ + DBusError *error; + struct name_and_cert_ctx *name_and_cert_ctx = NULL; + struct sbus_request *sbus_req; + struct cache_req_result *result; + errno_t ret; + + name_and_cert_ctx = tevent_req_callback_data(req, struct name_and_cert_ctx); + sbus_req = name_and_cert_ctx->sbus_req; + + ret = cache_req_user_by_name_recv(name_and_cert_ctx, req, &result); + talloc_zfree(req); + if (ret == ENOENT) { + error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND, + "User not found"); + goto fail; + } 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 fail; + } + + name_and_cert_ctx->user_opath = ifp_users_build_path_from_msg( + name_and_cert_ctx, + result->domain, + result->msgs[0]); + if (name_and_cert_ctx->user_opath == NULL) { + error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, + "Failed to compose object path"); + goto fail; + } + + if (name_and_cert_ctx->list_ctx != NULL) { + ret = ifp_users_find_by_name_and_cert_step(name_and_cert_ctx); + if (ret != EOK) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, + "Failed to fetch certificate [%d]: %s\n", + ret, sss_strerror(ret)); + goto fail; + } + } else { + ifp_users_find_by_name_and_cert_reply(name_and_cert_ctx); + } + + return; + +fail: + sbus_request_fail_and_finish(sbus_req, error); + return; +} + +static int ifp_users_find_by_name_and_cert_step( + struct name_and_cert_ctx *name_and_cert_ctx) +{ + struct tevent_req *req; + struct ifp_list_ctx *list_ctx = name_and_cert_ctx->list_ctx; + + req = cache_req_user_by_cert_send(list_ctx, + list_ctx->ctx->rctx->ev, + list_ctx->ctx->rctx, + list_ctx->ctx->rctx->ncache, + 0, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_set_callback(req, ifp_users_find_by_name_and_cert_done, + name_and_cert_ctx); + + return EOK; +} + +static void ifp_users_find_by_name_and_cert_done(struct tevent_req *req) +{ + DBusError *error; + struct name_and_cert_ctx *name_and_cert_ctx; + struct ifp_list_ctx *list_ctx; + struct sbus_request *sbus_req; + struct cache_req_result *result; + errno_t ret; + + name_and_cert_ctx = tevent_req_callback_data(req, struct name_and_cert_ctx); + list_ctx = name_and_cert_ctx->list_ctx; + sbus_req = list_ctx->sbus_req; + + ret = cache_req_user_by_cert_recv(name_and_cert_ctx, req, &result); + talloc_zfree(req); + if (ret != EOK && ret != ENOENT) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, + "Failed to fetch user [%d]: %s\n", + ret, sss_strerror(ret)); + sbus_request_fail_and_finish(sbus_req, error); + return; + } + + if (ret == EOK) { + ret = ifp_users_list_copy(list_ctx, result->ldb_result); + if (ret != EOK) { + error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, + "Failed to copy domain result"); + sbus_request_fail_and_finish(sbus_req, error); + return; + } + } + + list_ctx->dom = get_next_domain(list_ctx->dom, SSS_GND_DESCEND); + if (list_ctx->dom == NULL) { + return ifp_users_find_by_name_and_cert_reply(name_and_cert_ctx); + } + + ret = ifp_users_find_by_name_and_cert_step(name_and_cert_ctx); + if (ret != EOK) { + error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, + "Failed to start next-domain search"); + sbus_request_fail_and_finish(sbus_req, error); + return; + } + return; +} + +static void ifp_users_find_by_name_and_cert_reply( + struct name_and_cert_ctx *name_and_cert_ctx) +{ + struct sbus_request *sbus_req = name_and_cert_ctx->sbus_req; + struct ifp_list_ctx *list_ctx = name_and_cert_ctx->list_ctx; + DBusError *error; + size_t c; + + /* If no name was given check if there is only one user mapped to the + * certificate and return its object path. Either no or more than one + * mapped users are errors in this case. + * The case where a given name could not be found is already handled in + * ifp_users_find_by_name_and_cert_name_done(). */ + if (name_and_cert_ctx->user_opath == NULL) { + if (list_ctx == NULL || list_ctx->path_count == 0) { + error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND, + "User not found"); + sbus_request_fail_and_finish(sbus_req, error); + } else if (list_ctx->path_count == 1) { + iface_ifp_users_FindByNameAndCertificate_finish(sbus_req, + list_ctx->paths[0]); + } else { + error = sbus_error_new(sbus_req, SBUS_ERROR_MORE_THAN_ONE, + "More than one user found. " + "Use ListByCertificate to get all."); + sbus_request_fail_and_finish(sbus_req, error); + } + return; + } + + /* If there was no certficate given just return the object path of the + * user found by name. If a certificate was given an no mapped user was + * found return an error. */ + if (list_ctx == NULL || list_ctx->path_count == 0) { + if (name_and_cert_ctx->derb64 == NULL) { + iface_ifp_users_FindByNameAndCertificate_finish(sbus_req, + name_and_cert_ctx->user_opath); + } else { + error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND, + "No user matching name and certificate " + "found"); + sbus_request_fail_and_finish(sbus_req, error); + } + return; + } + + /* Check if the user found by name is one of the users mapped to the + * certificate. */ + for (c = 0; c < list_ctx->path_count; c++) { + if (strcmp(name_and_cert_ctx->user_opath, list_ctx->paths[c]) == 0) { + iface_ifp_users_FindByNameAndCertificate_finish(sbus_req, + name_and_cert_ctx->user_opath); + return; + } + } + + /* A user was found by name but the certificate is mapped to one or more + * different users. */ + error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND, + "No user matching name and certificate found"); + sbus_request_fail_and_finish(sbus_req, error); + + /* name_and_cert_ctx is already freed because sbus_req (the parent) is + * already freed by the DBus finish calls */ + return; +} + static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx); static void ifp_users_list_by_name_done(struct tevent_req *req); static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx); diff --git a/src/responder/ifp/ifp_users.h b/src/responder/ifp/ifp_users.h index 467ebc644..f8fefeb7f 100644 --- a/src/responder/ifp/ifp_users.h +++ b/src/responder/ifp/ifp_users.h @@ -49,6 +49,11 @@ int ifp_users_list_by_cert(struct sbus_request *sbus_req, const char *pem_cert, uint32_t limit); +int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, + void *data, + const char *name, + const char *pem_cert); + int ifp_users_list_by_name(struct sbus_request *sbus_req, void *data, const char *filter, |