summaryrefslogtreecommitdiffstats
path: root/src/db/sysdb_ssh.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/db/sysdb_ssh.c
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/db/sysdb_ssh.c')
-rw-r--r--src/db/sysdb_ssh.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/src/db/sysdb_ssh.c b/src/db/sysdb_ssh.c
new file mode 100644
index 0000000..4983dcc
--- /dev/null
+++ b/src/db/sysdb_ssh.c
@@ -0,0 +1,401 @@
+/*
+ Authors:
+ Jan Cholasta <jcholast@redhat.com>
+
+ Copyright (C) 2012 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 <talloc.h>
+
+#include "db/sysdb_ssh.h"
+#include "db/sysdb_private.h"
+
+static struct ldb_dn *
+sysdb_ssh_host_dn(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ return sysdb_custom_dn(mem_ctx, domain, name, SSH_HOSTS_SUBDIR);
+}
+
+static errno_t
+sysdb_update_ssh_host(struct sss_domain_info *domain,
+ const char *name,
+ struct sysdb_attrs *attrs)
+{
+ errno_t ret;
+
+ ret = sysdb_store_custom(domain, name, SSH_HOSTS_SUBDIR,
+ attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Error storing host %s [%d]: %s\n", name, ret, strerror(ret));
+ return ret;
+ }
+
+ return EOK;
+}
+
+errno_t
+sysdb_store_ssh_host(struct sss_domain_info *domain,
+ const char *name,
+ const char *alias,
+ int cache_timeout,
+ 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;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Storing host %s\n", name);
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_transaction_start(domain->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+ goto done;
+ }
+
+ in_transaction = true;
+
+ ret = sysdb_get_ssh_host(tmp_ctx, domain, name, search_attrs, &host);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
+ 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_attrs_add_string(attrs, SYSDB_NAME, name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Could not set name attribute [%d]: %s\n", ret, strerror(ret));
+ goto done;
+ }
+
+ if (alias) {
+ new_alias = true;
+
+ /* copy aliases from the existing entry */
+ 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;
+ }
+ }
+ }
+ }
+
+ /* 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;
+ }
+ }
+ }
+
+ /* make sure sshPublicKey is present when modifying an existing host */
+ if (host) {
+ ret = sysdb_attrs_get_el(attrs, SYSDB_SSH_PUBKEY, &el);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Could not get sysdb sshPublicKey [%d]: %s\n",
+ ret, strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Could not set sysdb lastUpdate [%d]: %s\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
+ cache_timeout ? (now + cache_timeout) : 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Could not set sysdb cache expire [%d]: %s\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ ret = sysdb_update_ssh_host(domain, name, attrs);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sysdb_transaction_commit(domain->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
+ goto done;
+ }
+
+ in_transaction = false;
+
+ ret = EOK;
+
+done:
+ if (in_transaction) {
+ sret = sysdb_transaction_cancel(domain->sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
+ }
+ }
+
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+errno_t
+sysdb_set_ssh_host_attr(struct sss_domain_info *domain,
+ const char *name,
+ struct sysdb_attrs *attrs,
+ int mod_op)
+{
+ errno_t ret;
+ struct ldb_dn *dn;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ dn = sysdb_ssh_host_dn(tmp_ctx, domain, name);
+ if (!dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+errno_t
+sysdb_update_ssh_known_host_expire(struct sss_domain_info *domain,
+ const char *name,
+ time_t now,
+ int known_hosts_timeout)
+{
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret;
+ struct sysdb_attrs *attrs;
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Updating known_hosts expire time of host %s\n", name);
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ attrs = sysdb_new_attrs(tmp_ctx);
+ if (!attrs) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_add_time_t(attrs, SYSDB_SSH_KNOWN_HOSTS_EXPIRE,
+ now + known_hosts_timeout);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Could not set known_hosts expire time [%d]: %s\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ ret = sysdb_update_ssh_host(domain, name, attrs);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+errno_t
+sysdb_delete_ssh_host(struct sss_domain_info *domain,
+ const char *name)
+{
+ DEBUG(SSSDBG_TRACE_FUNC, "Deleting host %s\n", name);
+ return sysdb_delete_custom(domain, name, SSH_HOSTS_SUBDIR);
+}
+
+errno_t
+sysdb_search_ssh_hosts(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *filter,
+ const char **attrs,
+ size_t *num_hosts,
+ struct ldb_message ***hosts)
+{
+ errno_t ret;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message **results;
+ size_t num_results;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_search_custom(tmp_ctx, domain, filter,
+ SSH_HOSTS_SUBDIR, attrs,
+ &num_results, &results);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "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;
+ *num_hosts = 0;
+ goto done;
+ }
+
+ *hosts = talloc_steal(mem_ctx, results);
+ *num_hosts = num_results;
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+errno_t
+sysdb_get_ssh_host(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ 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, domain, filter, attrs,
+ &num_hosts, &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 sss_domain_info *domain,
+ time_t now,
+ const char **attrs,
+ struct ldb_message ***hosts,
+ size_t *num_hosts)
+{
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret;
+ const char *filter;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ filter = talloc_asprintf(tmp_ctx,
+ "(&(|(!(%s=*))(%s=0)(%s>=%lld))(%s>=%lld))",
+ SYSDB_CACHE_EXPIRE,
+ SYSDB_CACHE_EXPIRE,
+ SYSDB_CACHE_EXPIRE, (long long)now + 1,
+ SYSDB_SSH_KNOWN_HOSTS_EXPIRE, (long long)now + 1);
+ if (!filter) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_search_ssh_hosts(mem_ctx, domain, filter, attrs,
+ num_hosts, hosts);
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}