diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
commit | 74aa0bc6779af38018a03fd2cf4419fe85917904 (patch) | |
tree | 9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/providers/proxy/proxy_services.c | |
parent | Initial commit. (diff) | |
download | sssd-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 '')
-rw-r--r-- | src/providers/proxy/proxy_services.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/src/providers/proxy/proxy_services.c b/src/providers/proxy/proxy_services.c new file mode 100644 index 0000000..856da09 --- /dev/null +++ b/src/providers/proxy/proxy_services.c @@ -0,0 +1,372 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@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 "providers/proxy/proxy.h" +#include "util/util.h" +#include "util/strtonum.h" +#include "db/sysdb_services.h" + +#define BUFLEN 1024 + +errno_t +proxy_save_service(struct sss_domain_info *domain, + struct servent *svc, + bool lowercase, + uint64_t cache_timeout) +{ + errno_t ret; + char *cased_name; + const char **protocols; + const char **cased_aliases; + TALLOC_CTX *tmp_ctx; + char *lc_alias = NULL; + time_t now = time(NULL); + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + cased_name = sss_get_cased_name(tmp_ctx, svc->s_name, + domain->case_preserve); + if (!cased_name) { + ret = ENOMEM; + goto done; + } + + protocols = talloc_array(tmp_ctx, const char *, 2); + if (!protocols) { + ret = ENOMEM; + goto done; + } + + protocols[0] = sss_get_cased_name(protocols, svc->s_proto, + !lowercase); + if (!protocols[0]) { + ret = ENOMEM; + goto done; + } + protocols[1] = NULL; + + /* Count the aliases */ + ret = sss_get_cased_name_list(tmp_ctx, + (const char * const *) svc->s_aliases, + !lowercase, &cased_aliases); + if (ret != EOK) { + goto done; + } + + if (domain->case_preserve) { + /* Add lowercased alias to allow case-insensitive lookup */ + lc_alias = sss_tc_utf8_str_tolower(tmp_ctx, svc->s_name); + if (lc_alias == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n"); + ret = ENOMEM; + goto done; + } + + ret = add_string_to_list(tmp_ctx, lc_alias, + discard_const_p(char **, &cased_aliases)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to add lowercased name alias.\n"); + goto done; + } + } + + ret = sysdb_store_service(domain, + cased_name, + ntohs(svc->s_port), + cased_aliases, + protocols, + NULL, NULL, + cache_timeout, + now); +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t +get_serv_byname(struct proxy_id_ctx *ctx, + struct sss_domain_info *dom, + const char *name, + const char *protocol) +{ + errno_t ret; + enum nss_status status; + struct servent *result; + TALLOC_CTX *tmp_ctx; + char buffer[BUFLEN]; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + result = talloc_zero(tmp_ctx, struct servent); + if (!result) { + ret = ENOMEM; + goto done; + } + + status = ctx->ops.getservbyname_r(name, protocol, result, + buffer, BUFLEN, &ret); + if (status != NSS_STATUS_SUCCESS && status != NSS_STATUS_NOTFOUND) { + DEBUG(SSSDBG_MINOR_FAILURE, + "getservbyname_r failed for service [%s].\n", name); + goto done; + } + + if (status == NSS_STATUS_NOTFOUND) { + /* Make sure we remove it from the cache */ + ret = sysdb_svc_delete(dom, name, 0, protocol); + } else { + + /* Results found. Save them into the cache */ + ret = proxy_save_service(dom, result, + !dom->case_sensitive, + dom->service_timeout); + } + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t +get_serv_byport(struct proxy_id_ctx *ctx, + struct sss_domain_info *dom, + const char *be_filter, + const char *protocol) +{ + errno_t ret; + enum nss_status status; + struct servent *result; + TALLOC_CTX *tmp_ctx; + uint16_t port; + char buffer[BUFLEN]; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + result = talloc_zero(tmp_ctx, struct servent); + if (!result) { + ret = ENOMEM; + goto done; + } + + port = htons(strtouint16(be_filter, NULL, 0)); + if (errno) { + ret = errno; + goto done; + } + + status = ctx->ops.getservbyport_r(port, protocol, result, + buffer, BUFLEN, &ret); + if (status != NSS_STATUS_SUCCESS && status != NSS_STATUS_NOTFOUND) { + DEBUG(SSSDBG_MINOR_FAILURE, + "getservbyport_r failed for service [%s].\n", be_filter); + goto done; + } + + if (status == NSS_STATUS_NOTFOUND) { + /* Make sure we remove it from the cache */ + ret = sysdb_svc_delete(dom, NULL, port, protocol); + } else { + /* Results found. Save them into the cache */ + ret = proxy_save_service(dom, result, + !dom->case_sensitive, + dom->service_timeout); + } + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t +enum_services(struct proxy_id_ctx *ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *dom) +{ + TALLOC_CTX *tmpctx; + bool in_transaction = false; + struct servent *svc; + enum nss_status status; + size_t buflen; + char *buffer; + char *newbuf; + errno_t ret, sret; + time_t now = time(NULL); + const char **protocols; + const char **cased_aliases; + bool again; + + DEBUG(SSSDBG_TRACE_FUNC, "Enumerating services\n"); + + tmpctx = talloc_new(NULL); + if (!tmpctx) { + return ENOMEM; + } + + svc = talloc(tmpctx, struct servent); + if (!svc) { + ret = ENOMEM; + goto done; + } + + buflen = DEFAULT_BUFSIZE; + buffer = talloc_size(tmpctx, buflen); + if (!buffer) { + ret = ENOMEM; + goto done; + } + + protocols = talloc_zero_array(tmpctx, const char *, 2); + if (protocols == NULL) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_transaction_start(sysdb); + if (ret) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); + goto done; + } + in_transaction = true; + + status = ctx->ops.setservent(); + if (status != NSS_STATUS_SUCCESS) { + ret = EIO; + goto done; + } + + do { + again = false; + + /* always zero out the svc structure */ + memset(svc, 0, sizeof(struct servent)); + + /* get entry */ + status = ctx->ops.getservent_r(svc, buffer, buflen, &ret); + + switch (status) { + case NSS_STATUS_TRYAGAIN: + /* buffer too small? */ + if (buflen < MAX_BUF_SIZE) { + buflen *= 2; + } + if (buflen > MAX_BUF_SIZE) { + buflen = MAX_BUF_SIZE; + } + newbuf = talloc_realloc_size(tmpctx, buffer, buflen); + if (!newbuf) { + ret = ENOMEM; + goto done; + } + buffer = newbuf; + again = true; + break; + + case NSS_STATUS_NOTFOUND: + + /* we are done here */ + DEBUG(SSSDBG_TRACE_FUNC, "Enumeration completed.\n"); + + ret = sysdb_transaction_commit(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); + goto done; + } + + in_transaction = false; + break; + + case NSS_STATUS_SUCCESS: + + DEBUG(SSSDBG_TRACE_INTERNAL, + "Service found (%s, %d/%s)\n", + svc->s_name, svc->s_port, svc->s_proto); + + protocols[0] = sss_get_cased_name(protocols, svc->s_proto, + dom->case_sensitive); + if (!protocols[0]) { + ret = ENOMEM; + goto done; + } + protocols[1] = NULL; + + ret = sss_get_cased_name_list(tmpctx, + (const char * const *) svc->s_aliases, + dom->case_sensitive, &cased_aliases); + if (ret != EOK) { + /* Do not fail completely on errors. + * Just report the failure to save and go on */ + DEBUG(SSSDBG_OP_FAILURE, + "Failed to store service [%s]. Ignoring.\n", + strerror(ret)); + again = true; + break; + } + + ret = sysdb_store_service(dom, + svc->s_name, + svc->s_port, + cased_aliases, + protocols, + NULL, NULL, + dom->service_timeout, + now); + if (ret) { + /* Do not fail completely on errors. + * Just report the failure to save and go on */ + DEBUG(SSSDBG_OP_FAILURE, + "Failed to store service [%s]. Ignoring.\n", + strerror(ret)); + } + again = true; + break; + + case NSS_STATUS_UNAVAIL: + /* "remote" backend unavailable. Enter offline mode */ + ret = ENXIO; + break; + + default: + ret = EIO; + DEBUG(SSSDBG_CRIT_FAILURE, + "proxy -> getservent_r failed (%d)[%s]\n", + ret, strerror(ret)); + break; + } + } while (again); + +done: + talloc_zfree(tmpctx); + if (in_transaction) { + sret = sysdb_transaction_cancel(sysdb); + if (sret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not cancel transaction! [%s]\n", + strerror(sret)); + } + } + ctx->ops.endservent(); + return ret; +} |