From 627d83dff183219826489949cb55ef71945e94ab Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Mon, 23 Jan 2012 22:00:30 -0500 Subject: PROXY: add support for enumerating services --- src/providers/proxy/proxy.h | 9 ++ src/providers/proxy/proxy_id.c | 7 ++ src/providers/proxy/proxy_init.c | 33 +++++++ src/providers/proxy/proxy_services.c | 177 +++++++++++++++++++++++++++++++++++ 4 files changed, 226 insertions(+) (limited to 'src') diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index d9484613..e9a550fd 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 b3bd97ff..b11750f7 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 b28e65a5..d43550bf 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 184f4daf..ca098f01 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; +} -- cgit