From aec5785126354bd8b192f63fe04ea08dae9c0705 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Sat, 21 Jan 2012 12:37:36 -0500 Subject: PROXY: add support for service lookups (non-enumeration) --- Makefile.am | 1 + src/providers/proxy/proxy.h | 24 +++++ src/providers/proxy/proxy_id.c | 28 +++++ src/providers/proxy/proxy_init.c | 22 ++++ src/providers/proxy/proxy_services.c | 199 +++++++++++++++++++++++++++++++++++ 5 files changed, 274 insertions(+) create mode 100644 src/providers/proxy/proxy_services.c diff --git a/Makefile.am b/Makefile.am index 2e47e96f..a8ae01d7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -949,6 +949,7 @@ libsss_proxy_la_SOURCES = \ src/providers/proxy/proxy_init.c \ src/providers/proxy/proxy_id.c \ src/providers/proxy/proxy_netgroup.c \ + src/providers/proxy/proxy_services.c \ src/providers/proxy/proxy_auth.c libsss_proxy_la_CFLAGS = \ $(AM_CFLAGS) diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index 41981fd8..d9484613 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -70,6 +70,17 @@ struct proxy_nss_ops { enum nss_status (*getnetgrent_r)(struct __netgrent *result, char *buffer, size_t buflen, int *errnop); enum nss_status (*endnetgrent)(struct __netgrent *result); + + /* Services */ + enum nss_status (*getservbyname_r)(const char *name, + const char *protocol, + struct servent *result, + char *buffer, size_t buflen, + int *errnop); + enum nss_status (*getservbyport_r)(int port, const char *protocol, + struct servent *result, + char *buffer, size_t buflen, + int *errnop); }; struct authtok_conv { @@ -145,4 +156,17 @@ errno_t get_netgroup(struct proxy_id_ctx *ctx, struct sss_domain_info *dom, const char *name); +errno_t get_serv_byname(struct proxy_id_ctx *ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *dom, + const char *name, + const char *protocol); + +errno_t +get_serv_byport(struct proxy_id_ctx *ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *dom, + const char *be_filter, + const char *protocol); + #endif /* __PROXY_H__ */ diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c index cfb058a8..b3bd97ff 100644 --- a/src/providers/proxy/proxy_id.c +++ b/src/providers/proxy/proxy_id.c @@ -1173,6 +1173,34 @@ void proxy_get_account_info(struct be_req *breq) ret = get_netgroup(ctx, sysdb, domain, ar->filter_value); break; + case BE_REQ_SERVICES: + switch (ar->filter_type) { + case BE_FILTER_NAME: + if (ctx->ops.getservbyname_r == NULL) { + return proxy_reply(breq, DP_ERR_FATAL, + ENODEV, "Services are not supported"); + } + ret = get_serv_byname(ctx, sysdb, domain, + ar->filter_value, + ar->extra_value); + break; + case BE_FILTER_IDNUM: + if (ctx->ops.getservbyport_r == NULL) { + return proxy_reply(breq, DP_ERR_FATAL, + ENODEV, "Services are not supported"); + } + ret = get_serv_byport(ctx, sysdb, domain, + ar->filter_value, + ar->extra_value); + break; + case BE_FILTER_ENUM: + break; + default: + return proxy_reply(breq, DP_ERR_FATAL, + EINVAL, "Invalid filter type"); + } + break; + default: /*fail*/ return proxy_reply(breq, DP_ERR_FATAL, EINVAL, "Invalid request type"); diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c index f53d6de1..b28e65a5 100644 --- a/src/providers/proxy/proxy_init.c +++ b/src/providers/proxy/proxy_init.c @@ -237,6 +237,28 @@ int sssm_proxy_id_init(struct be_ctx *bectx, dlerror())); } + ctx->ops.getservbyname_r = proxy_dlsym(ctx->handle, + "_nss_%s_getservbyname_r", + libname); + if (!ctx->ops.getservbyname_r) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Failed to load _nss_%s_getservbyname_r, error: %s. " + "The library does not support services.\n", + libname, + dlerror())); + } + + ctx->ops.getservbyport_r = proxy_dlsym(ctx->handle, + "_nss_%s_getservbyport_r", + libname); + if (!ctx->ops.getservbyport_r) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Failed to load _nss_%s_getservbyport_r, error: %s. " + "The library does not support services.\n", + libname, + dlerror())); + } + *ops = &proxy_id_ops; *pvt_data = ctx; ret = EOK; diff --git a/src/providers/proxy/proxy_services.c b/src/providers/proxy/proxy_services.c new file mode 100644 index 00000000..184f4daf --- /dev/null +++ b/src/providers/proxy/proxy_services.c @@ -0,0 +1,199 @@ +/* + SSSD + + Authors: + Stephen Gallagher + + 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 . +*/ + +#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 sysdb_ctx *sysdb, + 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; + size_t num_aliases, i; + 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, !lowercase); + 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 */ + for(num_aliases = 0; svc->s_aliases[num_aliases]; num_aliases++); + + if (num_aliases >= 1) { + cased_aliases = talloc_array(tmp_ctx, const char *, num_aliases + 1); + if (!cased_aliases) { + ret = ENOMEM; + goto done; + } + + for (i = 0; i < num_aliases; i++) { + cased_aliases[i] = sss_get_cased_name(tmp_ctx, svc->s_aliases[i], + !lowercase); + if (!cased_aliases[i]) { + ret = ENOMEM; + goto done; + } + } + cased_aliases[num_aliases] = NULL; + } else { + cased_aliases = NULL; + } + + ret = sysdb_store_service(sysdb, + cased_name, + ntohs(svc->s_port), + cased_aliases, + protocols, + cache_timeout, + now); +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t +get_serv_byname(struct proxy_id_ctx *ctx, + struct sysdb_ctx *sysdb, + 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)); + return ret; + } + + if (status == NSS_STATUS_NOTFOUND) { + /* Make sure we remove it from the cache */ + ret = sysdb_svc_delete(sysdb, name, 0, protocol); + } else { + + /* Results found. Save them into the cache */ + ret = proxy_save_service(sysdb, result, + !dom->case_sensitive, + ctx->entry_cache_timeout); + } + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t +get_serv_byport(struct proxy_id_ctx *ctx, + struct sysdb_ctx *sysdb, + 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; + } + + errno = 0; + 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)); + return ret; + } + + if (status == NSS_STATUS_NOTFOUND) { + /* Make sure we remove it from the cache */ + ret = sysdb_svc_delete(sysdb, NULL, port, protocol); + } else { + /* Results found. Save them into the cache */ + ret = proxy_save_service(sysdb, result, + !dom->case_sensitive, + ctx->entry_cache_timeout); + } + +done: + talloc_free(tmp_ctx); + return ret; +} -- cgit