summaryrefslogtreecommitdiffstats
path: root/src/providers/proxy
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/proxy')
-rw-r--r--src/providers/proxy/proxy.h9
-rw-r--r--src/providers/proxy/proxy_id.c7
-rw-r--r--src/providers/proxy/proxy_init.c33
-rw-r--r--src/providers/proxy/proxy_services.c177
4 files changed, 226 insertions, 0 deletions
diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h
index d94846133..e9a550fdb 100644
--- a/src/providers/proxy/proxy.h
+++ b/src/providers/proxy/proxy.h
@@ -81,6 +81,11 @@ struct proxy_nss_ops {
struct servent *result,
char *buffer, size_t buflen,
int *errnop);
+ enum nss_status (*setservent)(void);
+ enum nss_status (*getservent_r)(struct servent *result,
+ char *buffer, size_t buflen,
+ int *errnop);
+ enum nss_status (*endservent)(void);
};
struct authtok_conv {
@@ -169,4 +174,8 @@ get_serv_byport(struct proxy_id_ctx *ctx,
const char *be_filter,
const char *protocol);
+errno_t enum_services(struct proxy_id_ctx *ctx,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom);
+
#endif /* __PROXY_H__ */
diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
index b3bd97ff5..b11750f73 100644
--- a/src/providers/proxy/proxy_id.c
+++ b/src/providers/proxy/proxy_id.c
@@ -1194,6 +1194,13 @@ void proxy_get_account_info(struct be_req *breq)
ar->extra_value);
break;
case BE_FILTER_ENUM:
+ if (!ctx->ops.setservent
+ || !ctx->ops.getservent_r
+ || !ctx->ops.endservent) {
+ return proxy_reply(breq, DP_ERR_FATAL,
+ ENODEV, "Services are not supported");
+ }
+ ret = enum_services(ctx, sysdb, domain);
break;
default:
return proxy_reply(breq, DP_ERR_FATAL,
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
index b28e65a57..d43550bfa 100644
--- a/src/providers/proxy/proxy_init.c
+++ b/src/providers/proxy/proxy_init.c
@@ -259,6 +259,39 @@ int sssm_proxy_id_init(struct be_ctx *bectx,
dlerror()));
}
+ ctx->ops.setservent = proxy_dlsym(ctx->handle,
+ "_nss_%s_setservent",
+ libname);
+ if (!ctx->ops.setservent) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Failed to load _nss_%s_setservent, error: %s. "
+ "The library does not support services.\n",
+ libname,
+ dlerror()));
+ }
+
+ ctx->ops.getservent_r = proxy_dlsym(ctx->handle,
+ "_nss_%s_getservent_r",
+ libname);
+ if (!ctx->ops.getservent_r) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Failed to load _nss_%s_getservent_r, error: %s. "
+ "The library does not support services.\n",
+ libname,
+ dlerror()));
+ }
+
+ ctx->ops.endservent = proxy_dlsym(ctx->handle,
+ "_nss_%s_endservent",
+ libname);
+ if (!ctx->ops.endservent) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Failed to load _nss_%s_endservent, 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
index 184f4daf3..ca098f011 100644
--- a/src/providers/proxy/proxy_services.c
+++ b/src/providers/proxy/proxy_services.c
@@ -197,3 +197,180 @@ done:
talloc_free(tmp_ctx);
return ret;
}
+
+static errno_t
+get_const_aliases(TALLOC_CTX *mem_ctx,
+ char **aliases,
+ const char ***const_aliases)
+{
+ errno_t ret;
+ size_t i, num_aliases;
+ const char **alias_list = NULL;
+
+ for (num_aliases = 0; aliases[num_aliases]; num_aliases++);
+
+ alias_list = talloc_zero_array(mem_ctx, const char *, num_aliases + 1);
+ if (!alias_list) return ENOMEM;
+
+ for (i = 0; aliases[i]; i++) {
+ alias_list[i] = talloc_strdup(alias_list, aliases[i]);
+ if (!alias_list[i]) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = EOK;
+ *const_aliases = alias_list;
+
+done:
+ if (ret != EOK) {
+ talloc_zfree(alias_list);
+ }
+ 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[2] = { NULL, NULL };
+
+ 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;
+ }
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret) {
+ goto done;
+ }
+ in_transaction = true;
+
+ status = ctx->ops.setservent();
+ if (status != NSS_STATUS_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+again:
+ /* 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;
+ goto again;
+
+ case NSS_STATUS_NOTFOUND:
+
+ /* we are done here */
+ DEBUG(SSSDBG_TRACE_FUNC, ("Enumeration completed.\n"));
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) 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] = svc->s_proto;
+
+ const char **const_aliases;
+ ret = get_const_aliases(tmpctx, svc->s_aliases, &const_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)));
+ goto again; /* next */
+ }
+
+ ret = sysdb_store_service(sysdb,
+ svc->s_name,
+ svc->s_port,
+ const_aliases,
+ protocols,
+ ctx->entry_cache_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)));
+ }
+ goto again; /* next */
+
+ 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;
+ }
+
+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;
+}