From 2d6836a90bd326391782a5753f70e8ba666b5def Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Tue, 25 Sep 2012 04:27:38 -0400 Subject: SSH: Refactor sysdb and related code --- src/db/sysdb_ssh.c | 246 +++++++++++++++++++++++++------------ src/db/sysdb_ssh.h | 21 +++- src/providers/ipa/ipa_hostid.c | 18 ++- src/responder/ssh/sshsrv_cmd.c | 122 ++++++++---------- src/responder/ssh/sshsrv_private.h | 3 +- src/tests/sysdb_ssh-tests.c | 47 ++----- 6 files changed, 261 insertions(+), 196 deletions(-) diff --git a/src/db/sysdb_ssh.c b/src/db/sysdb_ssh.c index 5b956cdd..48d54a44 100644 --- a/src/db/sysdb_ssh.c +++ b/src/db/sysdb_ssh.c @@ -23,109 +23,144 @@ #include "db/sysdb_ssh.h" #include "db/sysdb_private.h" -errno_t -sysdb_store_ssh_host(struct sysdb_ctx *sysdb, - const char *name, - const char *alias, - struct sysdb_attrs *attrs) +static errno_t +sysdb_update_ssh_host(struct sysdb_ctx *sysdb, + const char *name, + struct sysdb_attrs *attrs) { TALLOC_CTX *tmp_ctx; errno_t ret; - errno_t sret; - struct ldb_message **hosts; - size_t num_hosts; - struct ldb_message_element *el; - unsigned int i; - const char *search_attrs[] = { SYSDB_NAME_ALIAS, NULL }; - bool in_transaction = false; - DEBUG(SSSDBG_TRACE_FUNC, ("Adding host %s\n", name)); + DEBUG(SSSDBG_TRACE_FUNC, ("Updating host %s\n", name)); tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } - if (!attrs) { - attrs = sysdb_new_attrs(tmp_ctx); - if (!attrs) { - ret = ENOMEM; - goto done; - } - } - - ret = sysdb_transaction_start(sysdb); + ret = sysdb_store_custom(sysdb, name, SSH_HOSTS_SUBDIR, attrs); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); + DEBUG(SSSDBG_OP_FAILURE, + ("Error storing host %s [%d]: %s\n", name, ret, strerror(ret))); goto done; } - in_transaction = true; + ret = EOK; - ret = sysdb_search_ssh_hosts(tmp_ctx, sysdb, name, search_attrs, - &hosts, &num_hosts); - if (ret != EOK && ret != ENOENT) { - goto done; +done: + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +sysdb_store_ssh_host(struct sysdb_ctx *sysdb, + const char *name, + const char *alias, + time_t now, + struct sysdb_attrs *attrs) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret, sret; + bool in_transaction = false; + const char *search_attrs[] = { SYSDB_NAME_ALIAS, NULL }; + bool new_alias; + struct ldb_message *host = NULL; + struct ldb_message_element *el; + unsigned int i; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; } - if (num_hosts > 1) { - ret = EINVAL; - DEBUG(SSSDBG_CRIT_FAILURE, - ("Found more than one host with name [%s].\n", name)); + ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, SYSDB_SSH_HOST_OC); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Could not set object class [%d]: %s\n", ret, strerror(ret))); goto done; } - ret = sysdb_delete_ssh_host(sysdb, name); - if (ret != EOK && ret != ENOENT) { + ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, name); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, - ("Failed to delete host [%s].\n", name)); + ("Could not set name attribute [%d]: %s\n", ret, strerror(ret))); goto done; } - if (num_hosts == 1) { - el = ldb_msg_find_element(hosts[0], SYSDB_NAME_ALIAS); + if (alias) { + new_alias = true; - if (el) { - for (i = 0; i < el->num_values; i++) { - if (alias && strcmp((char *)el->values[i].data, alias) == 0) { - alias = NULL; - } + ret = sysdb_transaction_start(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); + goto done; + } + + in_transaction = true; - ret = sysdb_attrs_add_val(attrs, - SYSDB_NAME_ALIAS, &el->values[i]); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - ("Could not add name alias [%s]\n", - el->values[i].data)); - goto done; + /* copy aliases from the existing entry */ + ret = sysdb_get_ssh_host(tmp_ctx, sysdb, name, search_attrs, &host); + if (ret != EOK && ret != ENOENT) { + goto done; + } + + if (host) { + el = ldb_msg_find_element(host, SYSDB_NAME_ALIAS); + + if (el) { + for (i = 0; i < el->num_values; i++) { + if (strcmp((char *)el->values[i].data, alias) == 0) { + new_alias = false; + } + + ret = sysdb_attrs_add_val(attrs, + SYSDB_NAME_ALIAS, &el->values[i]); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Could not add name alias %s [%d]: %s\n", + el->values[i].data, ret, strerror(ret))); + goto done; + } } } } - } - if (alias) { - ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, alias); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - ("Could not add name alias [%s]\n", alias)); - goto done; + /* add alias only if it is not already present */ + if (new_alias) { + ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, alias); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Could not add name alias %s [%d]: %s\n", + alias, ret, strerror(ret))); + goto done; + } } } - ret = sysdb_store_custom(sysdb, name, SSH_HOSTS_SUBDIR, attrs); + ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("sysdb_store_custom failed [%d]: %s\n", - ret, strerror(ret))); + DEBUG(SSSDBG_OP_FAILURE, + ("Could not set sysdb lastUpdate [%d]: %s\n", + ret, strerror(ret))); goto done; } - ret = sysdb_transaction_commit(sysdb); + ret = sysdb_update_ssh_host(sysdb, name, attrs); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); goto done; } - in_transaction = false; + if (in_transaction) { + ret = sysdb_transaction_commit(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); + goto done; + } + + in_transaction = false; + } + ret = EOK; done: @@ -149,44 +184,40 @@ sysdb_delete_ssh_host(struct sysdb_ctx *sysdb, return sysdb_delete_custom(sysdb, name, SSH_HOSTS_SUBDIR); } -errno_t +static errno_t sysdb_search_ssh_hosts(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - const char *name, + const char *filter, const char **attrs, struct ldb_message ***hosts, - size_t *host_count) + size_t *num_hosts) { errno_t ret; TALLOC_CTX *tmp_ctx; - const char *filter; - size_t count; - struct ldb_message **msgs; + struct ldb_message **results; + size_t num_results; tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) return ENOMEM; - - filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME, name); - if (!filter) { - ret = ENOMEM; - goto done; + if (!tmp_ctx) { + return ENOMEM; } ret = sysdb_search_custom(tmp_ctx, sysdb, filter, SSH_HOSTS_SUBDIR, attrs, - &count, &msgs); + &num_results, &results); if (ret != EOK && ret != ENOENT) { DEBUG(SSSDBG_CRIT_FAILURE, - ("Error looking up host [%s]", name)); + ("Error looking up host [%d]: %s\n", + ret, strerror(ret))); goto done; } if (ret == ENOENT) { DEBUG(SSSDBG_TRACE_FUNC, ("No such host\n")); *hosts = NULL; - *host_count = 0; + *num_hosts = 0; goto done; } - *hosts = talloc_steal(mem_ctx, msgs); - *host_count = count; + *hosts = talloc_steal(mem_ctx, results); + *num_hosts = num_results; ret = EOK; done: @@ -194,3 +225,60 @@ done: return ret; } + +errno_t +sysdb_get_ssh_host(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + const char *name, + const char **attrs, + struct ldb_message **host) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + const char *filter; + struct ldb_message **hosts; + size_t num_hosts; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME, name); + if (!filter) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_search_ssh_hosts(tmp_ctx, sysdb, filter, attrs, + &hosts, &num_hosts); + if (ret != EOK) { + goto done; + } + + if (num_hosts > 1) { + ret = EINVAL; + DEBUG(SSSDBG_CRIT_FAILURE, + ("Found more than one host with name %s\n", name)); + goto done; + } + + *host = talloc_steal(mem_ctx, hosts[0]); + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +sysdb_get_ssh_known_hosts(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + const char **attrs, + struct ldb_message ***hosts, + size_t *num_hosts) +{ + return sysdb_search_ssh_hosts(mem_ctx, sysdb, NULL, attrs, + hosts, num_hosts); +} diff --git a/src/db/sysdb_ssh.h b/src/db/sysdb_ssh.h index 3136dcc0..49de66ec 100644 --- a/src/db/sysdb_ssh.h +++ b/src/db/sysdb_ssh.h @@ -25,10 +25,13 @@ #define SSH_HOSTS_SUBDIR "ssh_hosts" +#define SYSDB_SSH_HOST_OC "sshHost" + errno_t sysdb_store_ssh_host(struct sysdb_ctx *sysdb, const char *name, const char *alias, + time_t now, struct sysdb_attrs *attrs); errno_t @@ -36,11 +39,17 @@ sysdb_delete_ssh_host(struct sysdb_ctx *sysdb, const char *name); errno_t -sysdb_search_ssh_hosts(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - const char *name, - const char **attrs, - struct ldb_message ***hosts, - size_t *host_count); +sysdb_get_ssh_host(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + const char *name, + const char **attrs, + struct ldb_message **host); + +errno_t +sysdb_get_ssh_known_hosts(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + const char **attrs, + struct ldb_message ***hosts, + size_t *num_hosts); #endif /* _SYSDB_SSH_H_ */ diff --git a/src/providers/ipa/ipa_hostid.c b/src/providers/ipa/ipa_hostid.c index c322c61f..f85454ff 100644 --- a/src/providers/ipa/ipa_hostid.c +++ b/src/providers/ipa/ipa_hostid.c @@ -246,6 +246,8 @@ hosts_get_done(struct tevent_req *subreq) struct hosts_get_state); int dp_error = DP_ERR_FATAL; errno_t ret; + struct sysdb_attrs *attrs; + time_t now = time(NULL); ret = ipa_host_info_recv(subreq, state, &state->count, &state->hosts, @@ -280,8 +282,20 @@ hosts_get_done(struct tevent_req *subreq) goto done; } - ret = sysdb_store_ssh_host(state->sysdb, state->name, state->alias, - state->hosts[0]); + attrs = sysdb_new_attrs(state); + if (!attrs) { + ret = ENOMEM; + goto done; + } + + /* we are interested only in the host keys */ + ret = sysdb_attrs_copy_values(state->hosts[0], attrs, SYSDB_SSH_PUBKEY); + if (ret != EOK) { + goto done; + } + + ret = sysdb_store_ssh_host(state->sysdb, state->name, state->alias, now, + attrs); if (ret != EOK) { goto done; } diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c index 6c10967e..a47894bf 100644 --- a/src/responder/ssh/sshsrv_cmd.c +++ b/src/responder/ssh/sshsrv_cmd.c @@ -235,17 +235,14 @@ ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx) return EIO; } - cmd_ctx->results = res->msgs; - cmd_ctx->results_len = res->count; - - if (cmd_ctx->results_len > 1) { + if (res->count > 1) { DEBUG(SSSDBG_FATAL_FAILURE, ("User search by name (%s) returned > 1 results!\n", cmd_ctx->name)); - return ENOENT; + return EINVAL; } - if (cmd_ctx->results_len == 0) { + if (!res->count) { /* if a multidomain search, try with next */ if (cmd_ctx->check_next) { cmd_ctx->domain = cmd_ctx->domain->next; @@ -258,6 +255,8 @@ ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx) return ENOENT; } + cmd_ctx->result = res->msgs[0]; + /* one result found */ return EOK; } @@ -360,23 +359,15 @@ ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx) return EFAULT; } - ret = sysdb_search_ssh_hosts(cmd_ctx, sysdb, - cmd_ctx->name, attrs, - &cmd_ctx->results, &cmd_ctx->results_len); + ret = sysdb_get_ssh_host(cmd_ctx, sysdb, cmd_ctx->name, attrs, + &cmd_ctx->result); if (ret != EOK && ret != ENOENT) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to make request to our cache!\n")); return EIO; } - if (cmd_ctx->results_len > 1) { - DEBUG(SSSDBG_FATAL_FAILURE, - ("Host search by name (%s) returned > 1 results!\n", - cmd_ctx->name)); - return ENOENT; - } - - if (cmd_ctx->results_len == 0) { + if (ret == ENOENT) { /* if a multidomain search, try with next */ if (cmd_ctx->check_next) { cmd_ctx->domain = cmd_ctx->domain->next; @@ -601,8 +592,8 @@ ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx) goto done; } - ret = sysdb_search_ssh_hosts(tmp_ctx, sysdb, "*", attrs, - &hosts, &num_hosts); + ret = sysdb_get_ssh_known_hosts(tmp_ctx, sysdb, attrs, + &hosts, &num_hosts); if (ret != EOK) { if (ret != ENOENT) { DEBUG(SSSDBG_OP_FAILURE, @@ -741,8 +732,7 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx) uint8_t *body; size_t body_len; size_t c = 0; - size_t i; - unsigned int j; + unsigned int i; struct ldb_message_element *el; uint32_t count = 0; const char *name; @@ -758,14 +748,9 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx) return ret; } - /* count number of results */ - for (i = 0; i < cmd_ctx->results_len; i++) { - el = ldb_msg_find_element(cmd_ctx->results[i], SYSDB_SSH_PUBKEY); - if (!el) { - continue; - } - - count += el->num_values; + el = ldb_msg_find_element(cmd_ctx->result, SYSDB_SSH_PUBKEY); + if (el) { + count = el->num_values; } ret = sss_packet_grow(cctx->creq->out, 2*sizeof(uint32_t)); @@ -777,55 +762,50 @@ ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx) SAFEALIGN_SET_UINT32(body+c, count, &c); SAFEALIGN_SET_UINT32(body+c, 0, &c); - for (i = 0; i < cmd_ctx->results_len; i++) { - name = ldb_msg_find_attr_as_string(cmd_ctx->results[i], - SYSDB_NAME, NULL); - if (!name) { - DEBUG(SSSDBG_OP_FAILURE, - ("Got unnamed result for [%s@%s]\n", - cmd_ctx->name, cmd_ctx->domain->name)); - return ENOENT; - } - - fqname = talloc_asprintf(cmd_ctx, "%s@%s", - name, cmd_ctx->domain->name); - if (!fqname) { - return ENOMEM; - } - - fqname_len = strlen(fqname)+1; + if (!el) { + return EOK; + } - el = ldb_msg_find_element(cmd_ctx->results[i], SYSDB_SSH_PUBKEY); - if (!el) { - /* this object has no SSH public keys */ - continue; - } + name = ldb_msg_find_attr_as_string(cmd_ctx->result, SYSDB_NAME, NULL); + if (!name) { + DEBUG(SSSDBG_OP_FAILURE, + ("Got unnamed result for [%s@%s]\n", + cmd_ctx->name, cmd_ctx->domain->name)); + return ENOENT; + } - for (j = 0; j < el->num_values; j++) { - key = sss_base64_decode(cmd_ctx, - (const char *)el->values[j].data, - &key_len); - if (!key) { - return ENOMEM; - } + fqname = talloc_asprintf(cmd_ctx, "%s@%s", + name, cmd_ctx->domain->name); + if (!fqname) { + return ENOMEM; + } - ret = sss_packet_grow(cctx->creq->out, - 3*sizeof(uint32_t) + key_len + fqname_len); - if (ret != EOK) { - talloc_free(key); - return ret; - } - sss_packet_get_body(cctx->creq->out, &body, &body_len); + fqname_len = strlen(fqname)+1; - SAFEALIGN_SET_UINT32(body+c, 0, &c); - SAFEALIGN_SET_UINT32(body+c, fqname_len, &c); - safealign_memcpy(body+c, fqname, fqname_len, &c); - SAFEALIGN_SET_UINT32(body+c, key_len, &c); - safealign_memcpy(body+c, key, key_len, &c); + for (i = 0; i < el->num_values; i++) { + key = sss_base64_decode(cmd_ctx, + (const char *)el->values[i].data, + &key_len); + if (!key) { + return ENOMEM; + } + ret = sss_packet_grow(cctx->creq->out, + 3*sizeof(uint32_t) + key_len + fqname_len); + if (ret != EOK) { talloc_free(key); - count++; + return ret; } + sss_packet_get_body(cctx->creq->out, &body, &body_len); + + SAFEALIGN_SET_UINT32(body+c, 0, &c); + SAFEALIGN_SET_UINT32(body+c, fqname_len, &c); + safealign_memcpy(body+c, fqname, fqname_len, &c); + SAFEALIGN_SET_UINT32(body+c, key_len, &c); + safealign_memcpy(body+c, key, key_len, &c); + + talloc_free(key); + count++; } return EOK; diff --git a/src/responder/ssh/sshsrv_private.h b/src/responder/ssh/sshsrv_private.h index e63a3105..e228af4a 100644 --- a/src/responder/ssh/sshsrv_private.h +++ b/src/responder/ssh/sshsrv_private.h @@ -44,8 +44,7 @@ struct ssh_cmd_ctx { struct sss_domain_info *domain; bool check_next; - struct ldb_message **results; - size_t results_len; + struct ldb_message *result; }; struct sss_cmd_table *get_ssh_cmds(void); diff --git a/src/tests/sysdb_ssh-tests.c b/src/tests/sysdb_ssh-tests.c index 2d5bd8e2..f914993c 100644 --- a/src/tests/sysdb_ssh-tests.c +++ b/src/tests/sysdb_ssh-tests.c @@ -164,19 +164,19 @@ struct test_data { const char *hostname; const char *alias; - struct ldb_message **hosts; + struct ldb_message *host; struct sysdb_attrs *attrs; - - size_t count; }; static int test_sysdb_store_ssh_host(struct test_data *data) { int ret; + time_t now = time(NULL); ret = sysdb_store_ssh_host(data->ctx->sysdb, data->hostname, data->alias, + now, data->attrs); return ret; } @@ -189,14 +189,15 @@ static int test_sysdb_delete_ssh_host(struct test_data *data) return ret; } -static int test_sysdb_search_ssh_hosts(struct test_data *data) +static int test_sysdb_get_ssh_host(struct test_data *data) { int ret; const char *attrs[] = { SYSDB_NAME, NULL }; - ret = sysdb_search_ssh_hosts(data->ctx, data->ctx->sysdb, - data->hostname, attrs, - &data->hosts, &data->count); + ret = sysdb_get_ssh_host(data->ctx, data->ctx->sysdb, + data->hostname, attrs, + &data->host); + return ret; } @@ -235,18 +236,6 @@ START_TEST (store_one_host_test) return; } - ret = sysdb_attrs_add_string(data->attrs, SYSDB_OBJECTCLASS, "testClass"); - if (ret != EOK) { - fail("Could not add attribute."); - return; - } - - ret = sysdb_attrs_add_string(data->attrs, SYSDB_NAME, TEST_HOSTNAME); - if (ret != EOK) { - fail("Could not add attribute."); - return; - } - ret = test_sysdb_store_ssh_host(data); fail_if(ret != EOK, "Could not store host into database"); @@ -324,7 +313,7 @@ START_TEST (delete_nonexistent_host_test) } END_TEST -START_TEST (sysdb_search_ssh_host_test) +START_TEST (sysdb_get_ssh_host_test) { struct sysdb_test_ctx *test_ctx; struct test_data *data; @@ -359,20 +348,6 @@ START_TEST (sysdb_search_ssh_host_test) return; } - ret = sysdb_attrs_add_string(data->attrs, SYSDB_OBJECTCLASS, "testClass"); - if (ret != EOK) { - fail("Could not add attribute."); - talloc_free(test_ctx); - return; - } - - ret = sysdb_attrs_add_string(data->attrs, SYSDB_NAME, TEST_HOSTNAME); - if (ret != EOK) { - fail("Could not add attribute."); - talloc_free(test_ctx); - return; - } - ret = test_sysdb_store_ssh_host(data); if (ret != EOK) { fail("Could not store host '%s' to database", TEST_HOSTNAME); @@ -380,7 +355,7 @@ START_TEST (sysdb_search_ssh_host_test) return; } - ret = test_sysdb_search_ssh_hosts(data); + ret = test_sysdb_get_ssh_host(data); fail_if(ret != EOK, "Could not find host '%s'",TEST_HOSTNAME); talloc_free(test_ctx); @@ -396,7 +371,7 @@ Suite *create_sysdb_ssh_suite(void) tcase_add_test(tc_sysdb_ssh, store_one_host_test); tcase_add_test(tc_sysdb_ssh, delete_existing_host_test); tcase_add_test(tc_sysdb_ssh, delete_nonexistent_host_test); - tcase_add_test(tc_sysdb_ssh, sysdb_search_ssh_host_test); + tcase_add_test(tc_sysdb_ssh, sysdb_get_ssh_host_test); suite_add_tcase(s, tc_sysdb_ssh); return s; } -- cgit