summaryrefslogtreecommitdiffstats
path: root/src/providers/proxy/proxy_services.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/providers/proxy/proxy_services.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 '')
-rw-r--r--src/providers/proxy/proxy_services.c372
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;
+}