From 98531e56318b65eb1bb6883fdfe12e771d8a1efe Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 24 Feb 2009 19:28:40 -0500 Subject: Add PAM responder Also move responders under server/responder with shared code in server/responder/common Signed-off-by: Simo Sorce --- server/nss/nsssrv.c | 589 ------------ server/nss/nsssrv.h | 122 --- server/nss/nsssrv_cmd.c | 2237 -------------------------------------------- server/nss/nsssrv_dp.c | 432 --------- server/nss/nsssrv_packet.c | 220 ----- 5 files changed, 3600 deletions(-) delete mode 100644 server/nss/nsssrv.c delete mode 100644 server/nss/nsssrv.h delete mode 100644 server/nss/nsssrv_cmd.c delete mode 100644 server/nss/nsssrv_dp.c delete mode 100644 server/nss/nsssrv_packet.c (limited to 'server/nss') diff --git a/server/nss/nsssrv.c b/server/nss/nsssrv.c deleted file mode 100644 index c48aed4a..00000000 --- a/server/nss/nsssrv.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - SSSD - - NSS Responder - - Copyright (C) Simo Sorce 2008 - - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "popt.h" -#include "util/util.h" -#include "nss/nsssrv.h" -#include "db/sysdb.h" -#include "confdb/confdb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "util/btreemap.h" -#include "providers/data_provider.h" -#include "monitor/monitor_sbus.h" -#include "monitor/monitor_interfaces.h" -#include "sbus/sbus_client.h" - -#define SSS_NSS_PIPE_NAME "nss" - -static int service_identity(DBusMessage *message, struct sbus_conn_ctx *sconn); -static int service_pong(DBusMessage *message, struct sbus_conn_ctx *sconn); -static int service_reload(DBusMessage *message, struct sbus_conn_ctx *sconn); -static int nss_init_domains(struct nss_ctx *nctx); -static int _domain_comparator(const void *key1, const void *key2); - -struct sbus_method nss_sbus_methods[] = { - {SERVICE_METHOD_IDENTITY, service_identity}, - {SERVICE_METHOD_PING, service_pong}, - {SERVICE_METHOD_RELOAD, service_reload}, - {NULL, NULL} -}; - -static void set_nonblocking(int fd) -{ - unsigned v; - v = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, v | O_NONBLOCK); -} - -static void set_close_on_exec(int fd) -{ - unsigned v; - v = fcntl(fd, F_GETFD, 0); - fcntl(fd, F_SETFD, v | FD_CLOEXEC); -} - -static int client_destructor(struct cli_ctx *ctx) -{ - if (ctx->cfd > 0) close(ctx->cfd); - return 0; -} - -static void client_send(struct event_context *ev, struct cli_ctx *cctx) -{ - int ret; - - ret = nss_packet_send(cctx->creq->out, cctx->cfd); - if (ret == EAGAIN) { - /* not all data was sent, loop again */ - return; - } - if (ret != EOK) { - DEBUG(0, ("Failed to read request, aborting client!\n")); - talloc_free(cctx); - return; - } - - /* ok all sent */ - EVENT_FD_NOT_WRITEABLE(cctx->cfde); - EVENT_FD_READABLE(cctx->cfde); - talloc_free(cctx->creq); - cctx->creq = NULL; - return; -} - -static void client_recv(struct event_context *ev, struct cli_ctx *cctx) -{ - int ret; - - if (!cctx->creq) { - cctx->creq = talloc_zero(cctx, struct cli_request); - if (!cctx->creq) { - DEBUG(0, ("Failed to alloc request, aborting client!\n")); - talloc_free(cctx); - return; - } - } - - if (!cctx->creq->in) { - ret = nss_packet_new(cctx->creq, NSS_PACKET_MAX_RECV_SIZE, - 0, &cctx->creq->in); - if (ret != EOK) { - DEBUG(0, ("Failed to alloc request, aborting client!\n")); - talloc_free(cctx); - return; - } - } - - ret = nss_packet_recv(cctx->creq->in, cctx->cfd); - switch (ret) { - case EOK: - /* do not read anymore */ - EVENT_FD_NOT_READABLE(cctx->cfde); - /* execute command */ - ret = nss_cmd_execute(cctx); - if (ret != EOK) { - DEBUG(0, ("Failed to execute request, aborting client!\n")); - talloc_free(cctx); - } - /* past this point cctx can be freed at any time by callbacks - * in case of error, do not use it */ - return; - - case EAGAIN: - /* need to read still some data, loop again */ - break; - - case EINVAL: - DEBUG(6, ("Invalid data from client, closing connection!\n")); - talloc_free(cctx); - break; - - case ENODATA: - DEBUG(5, ("Client disconnected!\n")); - talloc_free(cctx); - break; - - default: - DEBUG(6, ("Failed to read request, aborting client!\n")); - talloc_free(cctx); - } - - return; -} - -static void client_fd_handler(struct event_context *ev, - struct fd_event *fde, - uint16_t flags, void *ptr) -{ - struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx); - - if (flags & EVENT_FD_READ) { - client_recv(ev, cctx); - return; - } - if (flags & EVENT_FD_WRITE) { - client_send(ev, cctx); - return; - } -} - -static void accept_fd_handler(struct event_context *ev, - struct fd_event *fde, - uint16_t flags, void *ptr) -{ - /* accept and attach new event handler */ - struct nss_ctx *nctx = talloc_get_type(ptr, struct nss_ctx); - struct cli_ctx *cctx; - socklen_t len; - - cctx = talloc_zero(nctx, struct cli_ctx); - if (!cctx) { - struct sockaddr_un addr; - int fd; - DEBUG(0, ("Out of memory trying to setup client context!\n")); - /* accept and close to signal the client we have a problem */ - memset(&addr, 0, sizeof(addr)); - len = sizeof(addr); - fd = accept(nctx->lfd, (struct sockaddr *)&addr, &len); - if (fd == -1) { - return; - } - close(fd); - return; - } - - len = sizeof(cctx->addr); - cctx->cfd = accept(nctx->lfd, (struct sockaddr *)&cctx->addr, &len); - if (cctx->cfd == -1) { - DEBUG(1, ("Accept failed [%s]", strerror(errno))); - talloc_free(cctx); - return; - } - - cctx->cfde = event_add_fd(ev, cctx, cctx->cfd, - EVENT_FD_READ, client_fd_handler, cctx); - if (!cctx->cfde) { - close(cctx->cfd); - talloc_free(cctx); - DEBUG(2, ("Failed to queue client handler\n")); - } - - cctx->ev = ev; - cctx->nctx = nctx; - - talloc_set_destructor(cctx, client_destructor); - - DEBUG(4, ("Client connected!\n")); - - return; -} - -static int service_identity(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - dbus_uint16_t version = NSS_SBUS_SERVICE_VERSION; - const char *name = NSS_SBUS_SERVICE_NAME; - DBusMessage *reply; - dbus_bool_t ret; - - DEBUG(4,("Sending ID reply: (%s,%d)\n", - name, version)); - - reply = dbus_message_new_method_return(message); - if (!reply) return ENOMEM; - - ret = dbus_message_append_args(reply, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT16, &version, - DBUS_TYPE_INVALID); - if (!ret) { - dbus_message_unref(reply); - return EIO; - } - - /* send reply back */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - return EOK; -} - -static int service_pong(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply; - dbus_bool_t ret; - - reply = dbus_message_new_method_return(message); - if (!reply) return ENOMEM; - - ret = dbus_message_append_args(reply, DBUS_TYPE_INVALID); - if (!ret) { - dbus_message_unref(reply); - return EIO; - } - - /* send reply back */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - return EOK; -} - -static int service_reload(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - /* Monitor calls this function when we need to reload - * our configuration information. Perform whatever steps - * are needed to update the configuration objects. - */ - - /* Send an empty reply to acknowledge receipt */ - return service_pong(message, sconn); -} - -static int nss_sbus_init(struct nss_ctx *nctx) -{ - int ret; - char *sbus_address; - struct service_sbus_ctx *ss_ctx; - struct sbus_method_ctx *sm_ctx; - - /* Set up SBUS connection to the monitor */ - ret = monitor_get_sbus_address(nctx, nctx->cdb, &sbus_address); - if (ret != EOK) { - DEBUG(0, ("Could not locate monitor address.\n")); - return ret; - } - - ret = monitor_init_sbus_methods(nctx, nss_sbus_methods, &sm_ctx); - if (ret != EOK) { - DEBUG(0, ("Could not initialize SBUS methods.\n")); - return ret; - } - - ret = sbus_client_init(nctx, nctx->ev, - sbus_address, sm_ctx, - NULL /* Private Data */, - NULL /* Destructor */, - &ss_ctx); - if (ret != EOK) { - DEBUG(0, ("Failed to connect to monitor services.\n")); - return ret; - } - - /* Set up NSS-specific listeners */ - /* None currently used */ - - nctx->ss_ctx = ss_ctx; - - return EOK; -} - -/* create a unix socket and listen to it */ -static int set_unix_socket(struct nss_ctx *nctx) -{ - struct sockaddr_un addr; - char *default_pipe; - int ret; - - default_pipe = talloc_asprintf(nctx, "%s/%s", PIPE_PATH, SSS_NSS_PIPE_NAME); - if (!default_pipe) { - return ENOMEM; - } - - ret = confdb_get_string(nctx->cdb, nctx, - "config/services/nss", "unixSocket", - default_pipe, &nctx->sock_name); - if (ret != EOK) { - talloc_free(default_pipe); - return ret; - } - talloc_free(default_pipe); - - nctx->lfd = socket(AF_UNIX, SOCK_STREAM, 0); - if (nctx->lfd == -1) { - return EIO; - } - - /* Set the umask so that permissions are set right on the socket. - * It must be readable and writable by anybody on the system. */ - umask(0111); - - set_nonblocking(nctx->lfd); - set_close_on_exec(nctx->lfd); - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, nctx->sock_name, sizeof(addr.sun_path)); - - /* make sure we have no old sockets around */ - unlink(nctx->sock_name); - - if (bind(nctx->lfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - DEBUG(0,("Unable to bind on socket '%s'\n", nctx->sock_name)); - goto failed; - } - if (listen(nctx->lfd, 10) != 0) { - DEBUG(0,("Unable to listen on socket '%s'\n", nctx->sock_name)); - goto failed; - } - - nctx->lfde = event_add_fd(nctx->ev, nctx, nctx->lfd, - EVENT_FD_READ, accept_fd_handler, nctx); - - /* we want default permissions on created files to be very strict, - so set our umask to 0177 */ - umask(0177); - return EOK; - -failed: - /* we want default permissions on created files to be very strict, - so set our umask to 0177 */ - umask(0177); - close(nctx->lfd); - return EIO; -} - -/* domain names are case insensitive for now - * NOTE: this function is not utf-8 safe, - * only ASCII names for now */ -static int _domain_comparator(const void *key1, const void *key2) -{ - return strcasecmp((const char *)key1, (const char *)key2); -} - -static int nss_init_domains(struct nss_ctx *nctx) -{ - char *path; - char **domains; - char *provider; - TALLOC_CTX *tmp_ctx; - struct nss_domain_info *info; - int ret, i, c; - int retval; - - tmp_ctx = talloc_new(nctx); - ret = confdb_get_domains(nctx->cdb, tmp_ctx, &domains); - if (ret != EOK) { - retval = ret; - goto done; - } - - i = 0; - c = 0; - while (domains[i] != NULL) { - DEBUG(3, ("Adding domain %s to the map\n", domains[i])); - - path = talloc_asprintf(tmp_ctx, "config/domains/%s", domains[i]); - if (!path) { - retval = ENOMEM; - goto done; - } - - /* alloc on tmp_ctx, it will be stolen by btreemap_set_value */ - info = talloc_zero(tmp_ctx, struct nss_domain_info); - if (!info) { - retval = ENOMEM; - goto done; - } - - /* Build the basedn for this domain */ - info->basedn = talloc_asprintf(info, SYSDB_DOM_BASE, domains[i]); - DEBUG(3, ("BaseDN: %s\n", info->basedn)); - - ret = confdb_get_int(nctx->cdb, tmp_ctx, path, - "enumerate", false, &(info->enumerate)); - if (ret != EOK) { - DEBUG(0, ("Failed to fetch enumerate for [%s]!\n", domains[i])); - } - - ret = confdb_get_bool(nctx->cdb, tmp_ctx, path, - "legacy", false, &(info->legacy)); - if (ret != EOK) { - DEBUG(0, ("Failed to fetch legacy for [%s]!\n", domains[i])); - } - - ret = confdb_get_string(nctx->cdb, tmp_ctx, path, "provider", - NULL, &provider); - if (ret != EOK) { - DEBUG(0, ("Failed to fetch provider for [%s]!\n", domains[i])); - } - if (provider) info->has_provider = true; - - ret = btreemap_set_value(nctx, &nctx->domain_map, - domains[i], info, - _domain_comparator); - if (ret != EOK) { - DEBUG(1, ("Failed to store domain info, aborting!\n")); - retval = ret; - goto done; - } - - i++; - c++; - } - if (c == 0) { - /* No domains configured! - * Note: this should never happen, since LOCAL should - * always be configured */ - DEBUG(0, ("No domains configured on this client!\n")); - retval = EINVAL; - goto done; - } - - ret = confdb_get_string(nctx->cdb, nctx, - "config/domains", "default", - NULL, &nctx->default_domain); - if (ret != EOK) { - retval = ret; - goto done; - } - - retval = EOK; - -done: - talloc_free(tmp_ctx); - return retval; -} - -int nss_process_init(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct confdb_ctx *cdb) -{ - struct nss_ctx *nctx; - int ret; - - nctx = talloc_zero(mem_ctx, struct nss_ctx); - if (!nctx) { - DEBUG(0, ("fatal error initializing nss_ctx\n")); - return ENOMEM; - } - nctx->ev = ev; - nctx->cdb = cdb; - - ret = nss_init_domains(nctx); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up domain map\n")); - return ret; - } - - ret = nss_sbus_init(nctx); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up message bus\n")); - return ret; - } - - ret = nss_dp_init(nctx); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up backend connector\n")); - return ret; - } - - ret = sysdb_init(nctx, ev, cdb, NULL, &nctx->sysdb); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing nss_ctx\n")); - return ret; - } - - /* after all initializations we are ready to listen on our socket */ - ret = set_unix_socket(nctx); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing socket\n")); - return ret; - } - - nctx->cache_timeout = 600; /* FIXME: read from conf */ - - DEBUG(1, ("NSS Initialization complete\n")); - - return EOK; -} - -int main(int argc, const char *argv[]) -{ - int opt; - poptContext pc; - struct main_context *main_ctx; - int ret; - - struct poptOption long_options[] = { - POPT_AUTOHELP - SSSD_MAIN_OPTS - { NULL } - }; - - pc = poptGetContext(argv[0], argc, argv, long_options, 0); - while((opt = poptGetNextOpt(pc)) != -1) { - switch(opt) { - default: - fprintf(stderr, "\nInvalid option %s: %s\n\n", - poptBadOption(pc, 0), poptStrerror(opt)); - poptPrintUsage(pc, stderr, 0); - return 1; - } - } - - poptFreeContext(pc); - - /* set up things like debug , signals, daemonization, etc... */ - ret = server_setup("sssd[nss]", 0, &main_ctx); - if (ret != EOK) return 2; - - ret = nss_process_init(main_ctx, - main_ctx->event_ctx, - main_ctx->confdb_ctx); - if (ret != EOK) return 3; - - /* loop on main */ - server_loop(main_ctx); - - return 0; -} - diff --git a/server/nss/nsssrv.h b/server/nss/nsssrv.h deleted file mode 100644 index 2352a505..00000000 --- a/server/nss/nsssrv.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - SSSD - - NSS Responder, header file - - Copyright (C) Simo Sorce 2008 - - 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 . -*/ - -#ifndef __NSSSRV_H__ -#define __NSSSRV_H__ - -#include -#include -#include "talloc.h" -#include "tevent.h" -#include "ldb.h" -#include "../nss_client/sss_nss.h" -#include "dbus/dbus.h" - -#define NSS_SBUS_SERVICE_VERSION 0x0001 -#define NSS_SBUS_SERVICE_NAME "nss" - -#define NSS_PACKET_MAX_RECV_SIZE 1024 - -/* NSS_DOMAIN_DELIM can be specified in config.h */ -#include "config.h" -#ifndef NSS_DOMAIN_DELIM -#define NSS_DOMAIN_DELIM '@' -#endif - -#define NSS_ENUM_USERS 0x01 -#define NSS_ENUM_GROUPS 0x02 -#define NSS_ENUM_ALL 0x03 - -struct sysdb_ctx; -struct getent_ctx; - -struct nss_ctx { - struct event_context *ev; - struct fd_event *lfde; - int lfd; - struct sysdb_ctx *sysdb; - struct confdb_ctx *cdb; - char *sock_name; - struct service_sbus_ctx *ss_ctx; - struct service_sbus_ctx *dp_ctx; - struct btreemap *domain_map; - char *default_domain; - - int cache_timeout; -}; - -struct cli_ctx { - struct event_context *ev; - struct nss_ctx *nctx; - int cfd; - struct fd_event *cfde; - struct sockaddr_un addr; - struct cli_request *creq; - struct getent_ctx *gctx; -}; - -struct nss_domain_info { - char *basedn; - int enumerate; - bool has_provider; - bool legacy; -}; - -struct nss_packet; - -struct cli_request { - - /* original request from the wire */ - struct nss_packet *in; - - /* reply data */ - struct nss_packet *out; -}; - -/* from nsssrv_packet.c */ -int nss_packet_new(TALLOC_CTX *mem_ctx, size_t size, - enum sss_nss_command cmd, - struct nss_packet **rpacket); -int nss_packet_grow(struct nss_packet *packet, size_t size); -int nss_packet_recv(struct nss_packet *packet, int fd); -int nss_packet_send(struct nss_packet *packet, int fd); -enum sss_nss_command nss_packet_get_cmd(struct nss_packet *packet); -void nss_packet_get_body(struct nss_packet *packet, uint8_t **body, size_t *blen); -void nss_packet_set_error(struct nss_packet *packet, int error); - -/* from nsssrv_cmd.c */ -int nss_cmd_execute(struct cli_ctx *cctx); - -/* from nsssrv_dp.c */ -#define NSS_DP_USER 1 -#define NSS_DP_GROUP 2 -#define NSS_DP_INITGROUPS 3 - -typedef void (*nss_dp_callback_t)(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -int nss_dp_send_acct_req(struct nss_ctx *nctx, TALLOC_CTX *memctx, - nss_dp_callback_t callback, void *callback_ctx, - int timeout, const char *domain, int type, - const char *opt_name, uint32_t opt_id); -int nss_dp_init(struct nss_ctx *nctx); - -#endif /* __NSSSRV_H__ */ diff --git a/server/nss/nsssrv_cmd.c b/server/nss/nsssrv_cmd.c deleted file mode 100644 index b16d27c2..00000000 --- a/server/nss/nsssrv_cmd.c +++ /dev/null @@ -1,2237 +0,0 @@ -/* - SSSD - - NSS Responder - - Copyright (C) Simo Sorce 2008 - - 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 "util/util.h" -#include "util/btreemap.h" -#include "nss/nsssrv.h" -#include "db/sysdb.h" -#include - -struct nss_cmd_ctx { - struct cli_ctx *cctx; - const char *name; - uid_t id; - - bool immediate; - bool done; - int nr; -}; - -struct getent_ctx { - struct ldb_result *pwds; - struct ldb_result *grps; - int pwd_cur; - int grp_cur; -}; - -struct nss_dom_ctx { - struct nss_cmd_ctx *cmdctx; - const char *domain; - bool check_provider; - bool legacy; -}; - -struct nss_cmd_table { - enum sss_nss_command cmd; - int (*fn)(struct cli_ctx *cctx); -}; - -static void nss_cmd_done(struct nss_cmd_ctx *cmdctx) -{ - /* now that the packet is in place, unlock queue - * making the event writable */ - EVENT_FD_WRITEABLE(cmdctx->cctx->cfde); - - /* free all request related data through the talloc hierarchy */ - talloc_free(cmdctx); -} - -static int nss_cmd_send_error(struct nss_cmd_ctx *cmdctx, int err) -{ - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - nss_packet_set_error(cctx->creq->out, err); - return EOK; -} - -#define NSS_CMD_FATAL_ERROR(cctx) do { \ - DEBUG(1,("Fatal error, killing connection!")); \ - talloc_free(cctx); \ - return; \ -} while(0) - -static int nss_parse_name(struct nss_dom_ctx *dctx, const char *fullname) -{ - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct nss_ctx *nctx = cmdctx->cctx->nctx; - struct nss_domain_info *info; - struct btreemap *domain_map; - char *delim; - char *domain; - - domain_map = nctx->domain_map; - - if ((delim = strchr(fullname, NSS_DOMAIN_DELIM)) != NULL) { - domain = delim+1; - } else { - domain = nctx->default_domain; - } - - /* Check for registered domain */ - info = btreemap_get_value(domain_map, (void *)domain); - if (!info) { - /* No such domain was registered. Return EINVAL. - * TODO: alternative approach? - * Alternatively, we could simply fail down to - * below, treating the entire construct as the - * full name if the domain is unspecified. - */ - return EINVAL; - } - - dctx->check_provider = info->has_provider; - dctx->legacy = info->legacy; - - dctx->domain = talloc_strdup(dctx, domain); - if (!dctx->domain) return ENOMEM; - - if (delim) { - cmdctx->name = talloc_strndup(cmdctx, fullname, delim-fullname); - } else { - cmdctx->name = talloc_strdup(cmdctx, fullname); - } - if (!cmdctx->name) return ENOMEM; - - return EOK; -} - -static int nss_cmd_get_version(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - uint8_t *body; - size_t blen; - int ret; - - cmdctx = talloc(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - /* create response packet */ - ret = nss_packet_new(cctx->creq, sizeof(uint32_t), - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - nss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = SSS_NSS_VERSION; - - nss_cmd_done(cmdctx); - return EOK; -} - -/**************************************************************************** - * PASSWD db related functions - ***************************************************************************/ - -static int fill_pwent(struct nss_packet *packet, - struct ldb_message **msgs, - int count) -{ - struct ldb_message *msg; - uint8_t *body; - const char *name; - const char *fullname; - const char *homedir; - const char *shell; - uint64_t uid; - uint64_t gid; - size_t rsize, rp, blen; - size_t s1, s2, s3, s4; - int i, ret, num; - - /* first 2 fields (len and reserved), filled up later */ - ret = nss_packet_grow(packet, 2*sizeof(uint32_t)); - rp = 2*sizeof(uint32_t); - - num = 0; - for (i = 0; i < count; i++) { - msg = msgs[i]; - - name = ldb_msg_find_attr_as_string(msg, SYSDB_PW_NAME, NULL); - fullname = ldb_msg_find_attr_as_string(msg, SYSDB_PW_FULLNAME, NULL); - homedir = ldb_msg_find_attr_as_string(msg, SYSDB_PW_HOMEDIR, NULL); - shell = ldb_msg_find_attr_as_string(msg, SYSDB_PW_SHELL, NULL); - uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_PW_UIDNUM, 0); - gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_PW_GIDNUM, 0); - - if (!name || !fullname || !homedir || !shell || !uid || !gid) { - DEBUG(1, ("Incomplete user object for %s[%llu]! Skipping\n", - name?name:"", (unsigned long long int)uid)); - continue; - } - - s1 = strlen(name) + 1; - s2 = strlen(fullname) + 1; - s3 = strlen(homedir) + 1; - s4 = strlen(shell) + 1; - rsize = 2*sizeof(uint64_t) +s1 + 2 + s2 + s3 +s4; - - ret = nss_packet_grow(packet, rsize); - if (ret != EOK) { - num = 0; - goto done; - } - nss_packet_get_body(packet, &body, &blen); - - ((uint64_t *)(&body[rp]))[0] = uid; - ((uint64_t *)(&body[rp]))[1] = gid; - rp += 2*sizeof(uint64_t); - memcpy(&body[rp], name, s1); - rp += s1; - memcpy(&body[rp], "x", 2); - rp += 2; - memcpy(&body[rp], fullname, s2); - rp += s2; - memcpy(&body[rp], homedir, s3); - rp += s3; - memcpy(&body[rp], shell, s4); - rp += s4; - - num++; - } - -done: - nss_packet_get_body(packet, &body, &blen); - ((uint32_t *)body)[0] = num; /* num results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - - return EOK; -} - -static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static void nss_cmd_getpwnam_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int timeout; - uint64_t lastUpdate; - uint8_t *body; - size_t blen; - bool call_provider = false; - int ret; - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - - if (dctx->check_provider) { - switch (res->count) { - case 0: - call_provider = true; - break; - - case 1: - timeout = cmdctx->cctx->nctx->cache_timeout; - - lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_LAST_UPDATE, 0); - if (lastUpdate + timeout < time(NULL)) { - call_provider = true; - } - break; - - default: - DEBUG(1, ("getpwnam call returned more than one result !?!\n")); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - } - - if (call_provider) { - - /* dont loop forever :-) */ - dctx->check_provider = false; - timeout = SSS_NSS_SOCKET_TIMEOUT/2; - - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_getpwnam_dp_callback, dctx, - timeout, dctx->domain, NSS_DP_USER, - cmdctx->name, 0); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - return; - } - - switch (res->count) { - case 0: - - DEBUG(2, ("No results for getpwnam call\n")); - - ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t), - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - case 1: - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - ret = fill_pwent(cctx->creq->out, res->msgs, res->count); - nss_packet_set_error(cctx->creq->out, ret); - - break; - - default: - DEBUG(1, ("getpwnam call returned more than one result !?!\n")); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - -done: - nss_cmd_done(cmdctx); -} - -static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->name, - dctx->legacy, - nss_cmd_getpwnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } -} - -static int nss_cmd_getpwnam(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - uint8_t *body; - size_t blen; - int ret; - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) return ENOMEM; - dctx->cmdctx = cmdctx; - - /* get user name to query */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - /* if not terminated fail */ - if (body[blen -1] != '\0') { - talloc_free(cmdctx); - return EINVAL; - } - - ret = nss_parse_name(dctx, (const char *)body); - if (ret != EOK) { - DEBUG(1, ("Invalid name received\n")); - talloc_free(cmdctx); - return ret; - } - DEBUG(4, ("Requesting info for [%s] from [%s]\n", - cmdctx->name, dctx->domain)); - - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->name, - dctx->legacy, - nss_cmd_getpwnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret == EOK) { - nss_cmd_done(cmdctx); - } - return ret; - } - - return EOK; -} - -static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static void nss_cmd_getpwuid_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int timeout; - uint64_t lastUpdate; - uint8_t *body; - size_t blen; - bool call_provider = false; - int ret; - - /* one less to go */ - cmdctx->nr--; - - /* check if another callback already replied */ - if (cmdctx->done) { - /* now check if this is the last callback */ - if (cmdctx->nr == 0) { - /* ok we are really done with this request */ - goto done; - } - } - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - - if (dctx->check_provider) { - switch (res->count) { - case 0: - call_provider = true; - break; - - case 1: - timeout = cmdctx->cctx->nctx->cache_timeout; - - lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_LAST_UPDATE, 0); - if (lastUpdate + timeout < time(NULL)) { - call_provider = true; - } - break; - - default: - DEBUG(1, ("getpwuid call returned more than one result !?!\n")); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - } - - if (call_provider) { - - /* yet one more call to go */ - cmdctx->nr++; - - /* dont loop forever :-) */ - dctx->check_provider = false; - timeout = SSS_NSS_SOCKET_TIMEOUT/2; - - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_getpwuid_dp_callback, dctx, - timeout, dctx->domain, NSS_DP_USER, - NULL, cmdctx->id); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - return; - } - - switch (res->count) { - case 0: - if (cmdctx->nr != 0) { - /* nothing to do */ - return; - } - - DEBUG(2, ("No results for getpwuid call\n")); - - ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t), - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - case 1: - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - ret = fill_pwent(cctx->creq->out, res->msgs, res->count); - nss_packet_set_error(cctx->creq->out, ret); - - break; - - default: - DEBUG(1, ("getpwnam call returned more than one result !?!\n")); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - -done: - if (cmdctx->nr != 0) { - cmdctx->done = true; /* signal that we are done */ - return; - } - nss_cmd_done(cmdctx); -} - -static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_getpwuid(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->id, - dctx->legacy, - nss_cmd_getpwuid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - if (cmdctx->nr != 0) { - cmdctx->done = true; /* signal that we are done */ - return; - } - nss_cmd_done(cmdctx); - } -} - -static int nss_cmd_getpwuid(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct nss_domain_info *info; - const char **domains; - uint8_t *body; - size_t blen; - int i, num, ret; - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - /* get uid to query */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - - if (blen != sizeof(uint64_t)) { - return EINVAL; - } - - cmdctx->id = (uid_t)*((uint64_t *)body); - - /* FIXME: Just ask all backends for now, until we check for ranges */ - dctx = NULL; - domains = NULL; - num = 0; - /* get domains list */ - btreemap_get_keys(cmdctx, cctx->nctx->domain_map, - (const void ***)&domains, &num); - - cmdctx->nr = num; - - for (i = 0; i < num; i++) { - info = btreemap_get_value(cctx->nctx->domain_map, domains[i]); - - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) return ENOMEM; - - dctx->cmdctx = cmdctx; - dctx->domain = talloc_strdup(dctx, domains[i]); - if (!dctx->domain) return ENOMEM; - dctx->check_provider = info->has_provider; - dctx->legacy = info->legacy; - - - DEBUG(4, ("Requesting info for [%lu@%s]\n", - cmdctx->id, dctx->domain)); - - ret = sysdb_getpwuid(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->id, - dctx->legacy, - nss_cmd_getpwuid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - /* shutdown ? */ - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret == EOK) { - nss_cmd_done(cmdctx); - } - return ret; - } - } - - return EOK; -} - -/* to keep it simple at this stage we are retrieving the - * full enumeration again for each request for each process - * and we also block on setpwent() for the full time needed - * to retrieve the data. And endpwent() frees all the data. - * Next steps are: - * - use an nsssrv wide cache with data already structured - * so that it can be immediately returned (see nscd way) - * - use mutexes so that setpwent() can return immediately - * even if the data is still being fetched - * - make getpwent() wait on the mutex - */ -static void nss_cmd_getpwent_callback(void *ptr, int status, - struct ldb_result *res); - -static void nss_cmd_setpwent_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_cmd_ctx *cmdctx = talloc_get_type(ptr, struct nss_cmd_ctx); - struct cli_ctx *cctx = cmdctx->cctx; - struct getent_ctx *gctx = cctx->gctx; - struct ldb_result *store = gctx->pwds; - int i, j, c, ret; - - cmdctx->nr--; - - if (cmdctx->done) { - /* do not reply until all domain searches are done */ - if (cmdctx->nr != 0) return; - else goto done; - } - - if (status != LDB_SUCCESS) { - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_packet_set_error(cctx->creq->out, status); - cmdctx->done = true; - return; - } - - if (store) { - c = store->count + res->count; - store->msgs = talloc_realloc(store, store->msgs, - struct ldb_message *, c); - if (!store->msgs) NSS_CMD_FATAL_ERROR(cctx); - - for (i = store->count, j = 0; i < c; i++, j++) { - store->msgs[i] = talloc_steal(store->msgs, res->msgs[j]); - if (!store->msgs[i]) NSS_CMD_FATAL_ERROR(cctx); - } - store->count = c; - talloc_free(res); - } else { - gctx->pwds = talloc_steal(gctx, res); - } - - /* do not reply until all domain searches are done */ - if (cmdctx->nr) return; - - if (cmdctx->immediate) { - /* this was a getpwent call w/o setpwent, - * return immediately one result */ - nss_cmd_getpwent_callback(ptr, status, res); - - return; - } - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - -done: - nss_cmd_done(cmdctx); -} - -static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_enumpwent(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, dctx->legacy, - nss_cmd_setpwent_callback, cmdctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } -} - -static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate) -{ - struct nss_domain_info *info; - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct getent_ctx *gctx; - const char **domains; - int timeout; - int i, ret, num; - - DEBUG(4, ("Requesting info for all users\n")); - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - if (cctx->gctx == NULL) { - gctx = talloc_zero(cctx, struct getent_ctx); - if (!gctx) { - talloc_free(cmdctx); - return ENOMEM; - } - cctx->gctx = gctx; - } - if (cctx->gctx->pwds) { - talloc_free(cctx->gctx->pwds); - cctx->gctx->pwds = NULL; - cctx->gctx->pwd_cur = 0; - } - - cmdctx->immediate = immediate; - - domains = NULL; - num = 0; - /* get domains list */ - btreemap_get_keys(cmdctx, cctx->nctx->domain_map, - (const void ***)&domains, &num); - - /* check if enumeration is enabled in any domain */ - for (i = 0; i < num; i++) { - info = btreemap_get_value(cctx->nctx->domain_map, domains[i]); - - if ((info->enumerate & NSS_ENUM_USERS) == 0) { - continue; - } - - /* TODO: enabled, check if we have a recent cached enumeration */ - - /* ok no cache, go and ask the backend to enumerate */ - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) return ENOMEM; - - dctx->cmdctx = cmdctx; - dctx->domain = talloc_strdup(dctx, domains[i]); - if (!dctx->domain) return ENOMEM; - dctx->check_provider = info->has_provider; - dctx->legacy = info->legacy; - - if (dctx->check_provider) { - timeout = SSS_NSS_SOCKET_TIMEOUT/(i+2); - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_setpw_dp_callback, dctx, - timeout, domains[i], NSS_DP_USER, - NULL, 0); - } else { - ret = sysdb_enumpwent(dctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, dctx->legacy, - nss_cmd_setpwent_callback, cmdctx); - } - if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", - domains[i])); - continue; - } - - /* number of replies to wait for before setpwent is done */ - cmdctx->nr++; - } - - if (cmdctx->nr == 0) { - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - nss_packet_set_error(cctx->creq->out, ret); - nss_cmd_done(cmdctx); - return EOK; - } - - return ret; -} - -static int nss_cmd_setpwent(struct cli_ctx *cctx) -{ - return nss_cmd_setpwent_ext(cctx, false); -} - - -static int nss_cmd_retpwent(struct cli_ctx *cctx, int num) -{ - struct getent_ctx *gctx = cctx->gctx; - int n, ret; - - n = gctx->pwds->count - gctx->pwd_cur; - if (n > num) n = num; - - ret = fill_pwent(cctx->creq->out, - &(gctx->pwds->msgs[gctx->pwd_cur]), n); - gctx->pwd_cur += n; - - return ret; -} - -/* used only if a process calls getpwent() without first calling setpwent() - */ -static void nss_cmd_getpwent_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_cmd_ctx *cmdctx = talloc_get_type(ptr, struct nss_cmd_ctx); - struct cli_ctx *cctx = cmdctx->cctx; - struct getent_ctx *gctx = cctx->gctx; - uint8_t *body; - size_t blen; - uint32_t num; - int ret; - - /* get max num of entries to return in one call */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen != sizeof(uint32_t)) { - NSS_CMD_FATAL_ERROR(cctx); - } - num = *((uint32_t *)body); - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - if (status != LDB_SUCCESS) { - nss_packet_set_error(cctx->creq->out, status); - goto done; - } - - gctx->pwds = talloc_steal(gctx, res); - - ret = nss_cmd_retpwent(cctx, num); - nss_packet_set_error(cctx->creq->out, ret); - -done: - nss_cmd_done(cmdctx); -} - -static int nss_cmd_getpwent(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct getent_ctx *gctx; - uint8_t *body; - size_t blen; - uint32_t num; - int ret; - - DEBUG(4, ("Requesting info for all accounts\n")); - - /* get max num of entries to return in one call */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen != sizeof(uint32_t)) { - return EINVAL; - } - num = *((uint32_t *)body); - - /* see if we need to trigger an implicit setpwent() */ - if (cctx->gctx == NULL || cctx->gctx->pwds == NULL) { - if (cctx->gctx == NULL) { - gctx = talloc_zero(cctx, struct getent_ctx); - if (!gctx) { - return ENOMEM; - } - cctx->gctx = gctx; - } - if (cctx->gctx->pwds == NULL) { - ret = nss_cmd_setpwent_ext(cctx, true); - return ret; - } - } - - cmdctx = talloc(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - ret = nss_cmd_retpwent(cctx, num); - nss_packet_set_error(cctx->creq->out, ret); - nss_cmd_done(cmdctx); - return EOK; -} - -static int nss_cmd_endpwent(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - int ret; - - DEBUG(4, ("Terminating request info for all accounts\n")); - - cmdctx = talloc(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - - if (cctx->gctx == NULL) goto done; - if (cctx->gctx->pwds == NULL) goto done; - - /* free results and reset */ - talloc_free(cctx->gctx->pwds); - cctx->gctx->pwds = NULL; - cctx->gctx->pwd_cur = 0; - -done: - nss_cmd_done(cmdctx); - return EOK; -} - -/**************************************************************************** - * GROUP db related functions - ***************************************************************************/ - -static int fill_grent(struct nss_packet *packet, - struct ldb_message **msgs, - int count) -{ - struct ldb_message_element *el; - struct ldb_message *msg; - uint8_t *body; - const char *name; - uint64_t gid; - size_t rsize, rp, blen, mnump; - int i, j, ret, num, memnum; - bool get_group = true; - bool memnum_set = false; - - /* first 2 fields (len and reserved), filled up later */ - ret = nss_packet_grow(packet, 2*sizeof(uint32_t)); - rp = 2*sizeof(uint32_t); - - num = 0; - mnump = 0; - for (i = 0; i < count; i++) { - msg = msgs[i]; - - if (get_group) { - /* find group name/gid */ - name = ldb_msg_find_attr_as_string(msg, SYSDB_GR_NAME, NULL); - gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GR_GIDNUM, 0); - if (!name || !gid) { - DEBUG(1, ("Incomplete group object for %s[%llu]! Aborting\n", - name?name:"", (unsigned long long int)gid)); - num = 0; - goto done; - } - - /* fill in gid and name and set pointer for number of members */ - rsize = sizeof(uint64_t) + sizeof(uint32_t) + strlen(name)+1 +2; - ret = nss_packet_grow(packet, rsize); - nss_packet_get_body(packet, &body, &blen); - rp = blen - rsize; - ((uint64_t *)(&body[rp]))[0] = gid; - rp += sizeof(uint64_t); - ((uint32_t *)(&body[rp]))[0] = 0; /* init members num to 0 */ - mnump = rp; /* keep around members num pointer to set later */ - rp += sizeof(uint32_t); - memcpy(&body[rp], name, strlen(name)+1); - body[blen-2] = 'x'; /* group passwd field */ - body[blen-1] = '\0'; - - memnum_set = false; - memnum = 0; - num++; - - /* legacy style group, members are in SYSDB_LEGACY_MEMBER */ - el = ldb_msg_find_element(msg, SYSDB_LEGACY_MEMBER); - if (el) { - /* legacy */ - memnum = el->num_values; - - for (j = 0; j < memnum; j++) { - rsize = el->values[j].length + 1; - ret = nss_packet_grow(packet, rsize); - if (ret != EOK) { - num = 0; - goto done; - } - - nss_packet_get_body(packet, &body, &blen); - rp = blen - rsize; - memcpy(&body[rp], el->values[j].data, el->values[j].length); - body[blen-1] = '\0'; - } - - nss_packet_get_body(packet, &body, &blen); - ((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */ - memnum_set = true; - - } else { - get_group = false; - } - - continue; - } - - name = ldb_msg_find_attr_as_string(msg, SYSDB_PW_NAME, NULL); - - if (!name) { - /* last member of previous group found, or error. - * set next element to be a group, and eventually - * fail there if here start bogus entries */ - get_group = true; - i--; - nss_packet_get_body(packet, &body, &blen); - ((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */ - memnum_set = true; - continue; - } - - rsize = strlen(name) + 1; - - ret = nss_packet_grow(packet, rsize); - if (ret != EOK) { - num = 0; - goto done; - } - nss_packet_get_body(packet, &body, &blen); - rp = blen - rsize; - memcpy(&body[rp], name, rsize); - - memnum++; - } - - if (!memnum_set) { - /* fill in the last group member count */ - if (mnump != 0) { - nss_packet_get_body(packet, &body, &blen); - ((uint32_t *)(&body[mnump]))[0] = memnum; /* num members */ - } - } - -done: - nss_packet_get_body(packet, &body, &blen); - ((uint32_t *)body)[0] = num; /* num results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - - return EOK; -} - -static void nss_cmd_getgrnam_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static void nss_cmd_getgrnam_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int timeout; - uint64_t lastUpdate; - uint8_t *body; - size_t blen; - bool call_provider = false; - int ret; - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - return; - } - - if (dctx->check_provider) { - switch (res->count) { - case 0: - call_provider = true; - break; - - default: - timeout = cmdctx->cctx->nctx->cache_timeout; - - lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_LAST_UPDATE, 0); - if (lastUpdate + timeout < time(NULL)) { - call_provider = true; - } - } - } - - if (call_provider) { - - /* dont loop forever :-) */ - dctx->check_provider = false; - timeout = SSS_NSS_SOCKET_TIMEOUT/2; - - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_getgrnam_dp_callback, dctx, - timeout, dctx->domain, NSS_DP_GROUP, - cmdctx->name, 0); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - - return; - } - - switch (res->count) { - case 0: - - DEBUG(2, ("No results for getgrnam call\n")); - - ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t), - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - default: - - DEBUG(6, ("Returning info for group [%s]\n", cmdctx->name)); - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - ret = fill_grent(cctx->creq->out, res->msgs, res->count); - nss_packet_set_error(cctx->creq->out, ret); - } - -done: - nss_cmd_done(cmdctx); -} - -static void nss_cmd_getgrnam_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_getgrnam(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->name, - dctx->legacy, - nss_cmd_getgrnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } -} - -static int nss_cmd_getgrnam(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - uint8_t *body; - size_t blen; - int ret; - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) return ENOMEM; - dctx->cmdctx = cmdctx; - - /* get user name to query */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - /* if not terminated fail */ - if (body[blen -1] != '\0') { - talloc_free(cmdctx); - return EINVAL; - } - - ret = nss_parse_name(dctx, (const char *)body); - if (ret != EOK) { - DEBUG(1, ("Invalid name received\n")); - talloc_free(cmdctx); - return ret; - } - DEBUG(4, ("Requesting info for [%s] from [%s]\n", - cmdctx->name, dctx->domain)); - - ret = sysdb_getgrnam(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->name, - dctx->legacy, - nss_cmd_getgrnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret == EOK) { - nss_cmd_done(cmdctx); - } - return ret; - } - - return EOK; -} - -static void nss_cmd_getgrgid_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static void nss_cmd_getgrgid_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int timeout; - uint64_t lastUpdate; - uint8_t *body; - size_t blen; - bool call_provider = false; - int ret; - - /* one less to go */ - cmdctx->nr--; - - /* check if another callback already replied */ - if (cmdctx->done) { - /* now check if this is the last callback */ - if (cmdctx->nr == 0) { - /* ok we are really done with this request */ - goto done; - } - } - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - - if (dctx->check_provider) { - switch (res->count) { - case 0: - call_provider = true; - break; - - default: - timeout = cmdctx->cctx->nctx->cache_timeout; - - lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_LAST_UPDATE, 0); - if (lastUpdate + timeout < time(NULL)) { - call_provider = true; - } - } - } - - if (call_provider) { - - /* yet one more call to go */ - cmdctx->nr++; - - /* dont loop forever :-) */ - dctx->check_provider = false; - timeout = SSS_NSS_SOCKET_TIMEOUT/2; - - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_getgrgid_dp_callback, dctx, - timeout, dctx->domain, NSS_DP_GROUP, - NULL, cmdctx->id); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - return; - } - - switch (res->count) { - case 0: - if (cmdctx->nr != 0) { - /* nothing to do */ - return; - } - - DEBUG(2, ("No results for getgrgid call\n")); - - ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t), - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - default: - - DEBUG(6, ("Returning info for group [%u]\n", (unsigned)cmdctx->id)); - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - ret = fill_grent(cctx->creq->out, res->msgs, res->count); - nss_packet_set_error(cctx->creq->out, ret); - } - -done: - if (cmdctx->nr != 0) { - cmdctx->done = true; /* signal that we are done */ - return; - } - nss_cmd_done(cmdctx); -} - -static void nss_cmd_getgrgid_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_getgrgid(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->id, - dctx->legacy, - nss_cmd_getgrgid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } -} - -static int nss_cmd_getgrgid(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct nss_domain_info *info; - const char **domains; - uint8_t *body; - size_t blen; - int i, num, ret; - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - /* get uid to query */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - - if (blen != sizeof(uint64_t)) { - return EINVAL; - } - - cmdctx->id = (gid_t)*((uint64_t *)body); - - /* FIXME: Just ask all backends for now, until we check for ranges */ - dctx = NULL; - domains = NULL; - num = 0; - /* get domains list */ - btreemap_get_keys(cmdctx, cctx->nctx->domain_map, - (const void ***)&domains, &num); - - cmdctx->nr = num; - - for (i = 0; i < num; i++) { - info = btreemap_get_value(cctx->nctx->domain_map, domains[i]); - - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) return ENOMEM; - - dctx->cmdctx = cmdctx; - dctx->domain = talloc_strdup(dctx, domains[i]); - if (!dctx->domain) return ENOMEM; - dctx->check_provider = info->has_provider; - dctx->legacy = info->legacy; - - DEBUG(4, ("Requesting info for [%lu@%s]\n", - cmdctx->id, dctx->domain)); - - ret = sysdb_getgrgid(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->id, - dctx->legacy, - nss_cmd_getgrgid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - /* shutdown ? */ - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret == EOK) { - nss_cmd_done(cmdctx); - } - return ret; - } - } - - return EOK; -} - -/* to keep it simple at this stage we are retrieving the - * full enumeration again for each request for each process - * and we also block on setgrent() for the full time needed - * to retrieve the data. And endgrent() frees all the data. - * Next steps are: - * - use and nsssrv wide cache with data already structured - * so that it can be immediately returned (see nscd way) - * - use mutexes so that setgrent() can return immediately - * even if the data is still being fetched - * - make getgrent() wait on the mutex - */ -static void nss_cmd_getgrent_callback(void *ptr, int status, - struct ldb_result *res); - -static void nss_cmd_setgrent_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_cmd_ctx *cmdctx = talloc_get_type(ptr, struct nss_cmd_ctx); - struct cli_ctx *cctx = cmdctx->cctx; - struct getent_ctx *gctx = cctx->gctx; - struct ldb_result *store = gctx->grps; - int i, j, c, ret; - - cmdctx->nr--; - - if (cmdctx->done) { - /* do not reply until all domain searches are done */ - if (cmdctx->nr != 0) return; - else goto done; - } - - if (status != LDB_SUCCESS) { - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_packet_set_error(cctx->creq->out, status); - cmdctx->done = true; - return; - } - - if (store) { - c = store->count + res->count; - store->msgs = talloc_realloc(store, store->msgs, - struct ldb_message *, c); - if (!store->msgs) NSS_CMD_FATAL_ERROR(cctx); - - for (i = store->count, j = 0; i < c; i++, j++) { - store->msgs[i] = talloc_steal(store->msgs, res->msgs[j]); - if (!store->msgs[i]) NSS_CMD_FATAL_ERROR(cctx); - } - store->count = c; - talloc_free(res); - } else { - gctx->grps = talloc_steal(gctx, res); - } - - /* do not reply until all domain searches are done */ - if (cmdctx->nr) return; - - if (cmdctx->immediate) { - /* this was a getgrent call w/o setgrent, - * return immediately one result */ - nss_cmd_getgrent_callback(ptr, status, res); - return; - } - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - -done: - nss_cmd_done(cmdctx); -} - -static void nss_cmd_setgr_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_enumgrent(dctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, dctx->legacy, - nss_cmd_setgrent_callback, cmdctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } -} - -static int nss_cmd_setgrent_ext(struct cli_ctx *cctx, bool immediate) -{ - struct nss_domain_info *info; - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct getent_ctx *gctx; - const char **domains; - int timeout; - int i, ret, num; - - DEBUG(4, ("Requesting info for all groups\n")); - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - if (cctx->gctx == NULL) { - gctx = talloc_zero(cctx, struct getent_ctx); - if (!gctx) { - talloc_free(cmdctx); - return ENOMEM; - } - cctx->gctx = gctx; - } - if (cctx->gctx->grps) { - talloc_free(cctx->gctx->grps); - cctx->gctx->grps = NULL; - cctx->gctx->grp_cur = 0; - } - - cmdctx->immediate = immediate; - - domains = NULL; - num = 0; - /* get domains list */ - btreemap_get_keys(cmdctx, cctx->nctx->domain_map, - (const void ***)&domains, &num); - - /* check if enumeration is enabled in any domain */ - for (i = 0; i < num; i++) { - info = btreemap_get_value(cctx->nctx->domain_map, domains[i]); - - if ((info->enumerate & NSS_ENUM_GROUPS) == 0) { - continue; - } - - /* TODO: enabled, check if we have a recent cached enumeration */ - - /* ok no cache, go and ask the backend to enumerate */ - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) return ENOMEM; - - dctx->cmdctx = cmdctx; - dctx->domain = talloc_strdup(dctx, domains[i]); - if (!dctx->domain) return ENOMEM; - dctx->check_provider = info->has_provider; - dctx->legacy = info->legacy; - - if (dctx->check_provider) { - timeout = SSS_NSS_SOCKET_TIMEOUT/(i+2); - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_setgr_dp_callback, dctx, - timeout, domains[i], NSS_DP_GROUP, - NULL, 0); - } else { - ret = sysdb_enumgrent(dctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, dctx->legacy, - nss_cmd_setgrent_callback, cmdctx); - } - if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", - domains[i])); - continue; - } - - cmdctx->nr++; - } - - if (cmdctx->nr == 0) { - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - nss_packet_set_error(cctx->creq->out, ret); - nss_cmd_done(cmdctx); - return EOK; - } - - return ret; -} - -static int nss_cmd_setgrent(struct cli_ctx *cctx) -{ - return nss_cmd_setgrent_ext(cctx, false); -} - -static int nss_cmd_retgrent(struct cli_ctx *cctx, int num) -{ - struct getent_ctx *gctx = cctx->gctx; - int n, ret; - - n = gctx->grps->count - gctx->grp_cur; - if (n > num) n = num; - - ret = fill_grent(cctx->creq->out, - &(gctx->grps->msgs[gctx->grp_cur]), n); - gctx->grp_cur += n; - - return ret; -} - -/* used only if a process calls getpwent() without first calling setpwent() - * in this case we basically trigger an implicit setpwent() */ -static void nss_cmd_getgrent_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_cmd_ctx *cmdctx = talloc_get_type(ptr, struct nss_cmd_ctx); - struct cli_ctx *cctx = cmdctx->cctx; - struct getent_ctx *gctx = cctx->gctx; - uint8_t *body; - size_t blen; - uint32_t num; - int ret; - - /* get max num of entries to return in one call */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen != sizeof(uint32_t)) { - ret = nss_cmd_send_error(cmdctx, EIO); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } - num = *((uint32_t *)body); - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - if (status != LDB_SUCCESS) { - nss_packet_set_error(cctx->creq->out, status); - goto done; - } - - gctx->grps = talloc_steal(gctx, res); - - ret = nss_cmd_retgrent(cctx, num); - nss_packet_set_error(cctx->creq->out, ret); - -done: - nss_cmd_done(cmdctx); -} - -static int nss_cmd_getgrent(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct getent_ctx *gctx; - uint8_t *body; - size_t blen; - uint32_t num; - int ret; - - DEBUG(4, ("Requesting info for all groups\n")); - - /* get max num of entries to return in one call */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen != sizeof(uint32_t)) { - return EINVAL; - } - num = *((uint32_t *)body); - - /* see if we need to trigger an implicit setpwent() */ - if (cctx->gctx == NULL || cctx->gctx->grps == NULL) { - if (cctx->gctx == NULL) { - gctx = talloc_zero(cctx, struct getent_ctx); - if (!gctx) { - return ENOMEM; - } - cctx->gctx = gctx; - } - if (cctx->gctx->grps == NULL) { - ret = nss_cmd_setgrent_ext(cctx, true); - return ret; - } - } - - cmdctx = talloc(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - ret = nss_cmd_retgrent(cctx, num); - nss_packet_set_error(cctx->creq->out, ret); - nss_cmd_done(cmdctx); - return EOK; -} - -static int nss_cmd_endgrent(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - int ret; - - DEBUG(4, ("Terminating request info for all groups\n")); - - cmdctx = talloc(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - - if (cctx->gctx == NULL) goto done; - if (cctx->gctx->grps == NULL) goto done; - - /* free results and reset */ - talloc_free(cctx->gctx->grps); - cctx->gctx->grps = NULL; - cctx->gctx->grp_cur = 0; - -done: - nss_cmd_done(cmdctx); - return EOK; -} - -static void nss_cmd_initgr_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_cmd_ctx *cmdctx = talloc_get_type(ptr, struct nss_cmd_ctx); - struct cli_ctx *cctx = cmdctx->cctx; - uint8_t *body; - size_t blen; - uint64_t gid; - uint32_t num; - int ret, i; - - /* create response packet */ - ret = nss_packet_new(cctx->creq, 0, - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - if (status != LDB_SUCCESS) { - nss_packet_set_error(cctx->creq->out, status); - goto done; - } - - num = res->count; - /* the first 64 bit uint is really 2 32 units used to hold the number of - * results */ - ret = nss_packet_grow(cctx->creq->out, (1 + num) * sizeof(uint64_t)); - if (ret != EOK) { - nss_packet_set_error(cctx->creq->out, ret); - goto done; - } - nss_packet_get_body(cctx->creq->out, &body, &blen); - - for (i = 0; i < num; i++) { - gid = ldb_msg_find_attr_as_uint64(res->msgs[i], SYSDB_GR_GIDNUM, 0); - if (!gid) { - DEBUG(1, ("Incomplete group object for initgroups! Aborting\n")); - nss_packet_set_error(cctx->creq->out, EIO); - num = 0; - goto done; - } - ((uint64_t *)body)[i+1] = gid; - } - - ((uint32_t *)body)[0] = num; /* num results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - -done: - nss_cmd_done(cmdctx); -} - -static void nss_cmd_getinitgr_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_initgroups(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->name, - dctx->legacy, - nss_cmd_initgr_callback, cmdctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } -} - -static void nss_cmd_getinit_callback(void *ptr, int status, - struct ldb_result *res); - -static void nss_cmd_getinitnam_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->name, - dctx->legacy, - nss_cmd_getinit_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_cmd_done(cmdctx); - } -} - -static void nss_cmd_getinit_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - int timeout; - uint64_t lastUpdate; - uint8_t *body; - size_t blen; - bool call_provider = false; - int ret; - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - - if (dctx->check_provider) { - switch (res->count) { - case 0: - call_provider = true; - break; - - default: - timeout = cmdctx->cctx->nctx->cache_timeout; - - lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_LAST_UPDATE, 0); - if (lastUpdate + timeout < time(NULL)) { - call_provider = true; - } - } - } - - if (call_provider) { - - /* dont loop forever :-) */ - dctx->check_provider = false; - timeout = SSS_NSS_SOCKET_TIMEOUT/2; - - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_getinitnam_callback, dctx, - timeout, dctx->domain, NSS_DP_USER, - cmdctx->name, 0); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - - return; - } - - switch (res->count) { - case 0: - - DEBUG(2, ("No results for initgroups call\n")); - - ret = nss_packet_new(cctx->creq, 2*sizeof(uint32_t), - nss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - nss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - case 1: - - timeout = SSS_NSS_SOCKET_TIMEOUT/2; - ret = nss_dp_send_acct_req(cctx->nctx, cmdctx, - nss_cmd_getinitgr_callback, dctx, - timeout, dctx->domain, NSS_DP_INITGROUPS, - cmdctx->name, 0); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - goto done; - } - - return; - - default: - DEBUG(1, ("getpwnam call returned more than one result !?!\n")); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - -done: - nss_cmd_done(cmdctx); -} - -/* for now, if we are online, try to always query the backend */ -static int nss_cmd_initgroups(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - uint8_t *body; - size_t blen; - int ret; - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) return ENOMEM; - dctx->cmdctx = cmdctx; - - /* get user name to query */ - nss_packet_get_body(cctx->creq->in, &body, &blen); - cmdctx->name = (const char *)body; - /* if not terminated fail */ - if (cmdctx->name[blen -1] != '\0') { - return EINVAL; - } - - ret = nss_parse_name(dctx, (const char *)body); - if (ret != EOK) { - DEBUG(1, ("Invalid name received\n")); - talloc_free(cmdctx); - return ret; - } - DEBUG(4, ("Requesting info for [%s] from [%s]\n", - cmdctx->name, dctx->domain)); - - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, - dctx->domain, cmdctx->name, - dctx->legacy, - nss_cmd_getinit_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret == EOK) { - nss_cmd_done(cmdctx); - } - return ret; - } - - return EOK; -} - -struct nss_cmd_table nss_cmds[] = { - {SSS_NSS_GET_VERSION, nss_cmd_get_version}, - {SSS_NSS_GETPWNAM, nss_cmd_getpwnam}, - {SSS_NSS_GETPWUID, nss_cmd_getpwuid}, - {SSS_NSS_SETPWENT, nss_cmd_setpwent}, - {SSS_NSS_GETPWENT, nss_cmd_getpwent}, - {SSS_NSS_ENDPWENT, nss_cmd_endpwent}, - {SSS_NSS_GETGRNAM, nss_cmd_getgrnam}, - {SSS_NSS_GETGRGID, nss_cmd_getgrgid}, - {SSS_NSS_SETGRENT, nss_cmd_setgrent}, - {SSS_NSS_GETGRENT, nss_cmd_getgrent}, - {SSS_NSS_ENDGRENT, nss_cmd_endgrent}, - {SSS_NSS_INITGR, nss_cmd_initgroups}, - {SSS_NSS_NULL, NULL} -}; - -int nss_cmd_execute(struct cli_ctx *cctx) -{ - enum sss_nss_command cmd; - int i; - - cmd = nss_packet_get_cmd(cctx->creq->in); - - for (i = 0; nss_cmds[i].cmd != SSS_NSS_NULL; i++) { - if (cmd == nss_cmds[i].cmd) { - return nss_cmds[i].fn(cctx); - } - } - - return EINVAL; -} - diff --git a/server/nss/nsssrv_dp.c b/server/nss/nsssrv_dp.c deleted file mode 100644 index ec8aea8b..00000000 --- a/server/nss/nsssrv_dp.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - SSSD - - NSS Responder - Data Provider Interfaces - - Copyright (C) Simo Sorce 2008 - - 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 -#include -#include "util/util.h" -#include "nss/nsssrv.h" -#include "providers/data_provider.h" -#include "sbus/sbus_client.h" -#include "providers/dp_sbus.h" - -struct nss_dp_req { - nss_dp_callback_t callback; - void *callback_ctx; - struct timed_event *te; - DBusPendingCall *pending_reply; -}; - -static int nss_dp_req_destructor(void *ptr) -{ - struct nss_dp_req *req = talloc_get_type(ptr, struct nss_dp_req); - - if (req->pending_reply) { - dbus_pending_call_cancel(req->pending_reply); - } - - return 0; -} - -static void nss_dp_send_acct_timeout(struct event_context *ev, - struct timed_event *te, - struct timeval t, void *data) -{ - struct nss_dp_req *ndp_req; - dbus_uint16_t err_maj = DP_ERR_TIMEOUT; - dbus_uint32_t err_min = EIO; - const char *err_msg = "Request timed out"; - - ndp_req = talloc_get_type(data, struct nss_dp_req); - - ndp_req->callback(err_maj, err_min, err_msg, ndp_req->callback_ctx); - - talloc_free(ndp_req); -} - -static int nss_dp_get_reply(DBusPendingCall *pending, - dbus_uint16_t *err_maj, - dbus_uint32_t *err_min, - const char **err_msg); - -static void nss_dp_send_acct_callback(DBusPendingCall *pending, void *ptr) -{ - struct nss_dp_req *ndp_req; - dbus_uint16_t err_maj; - dbus_uint32_t err_min; - const char *err_msg; - int ret; - - ndp_req = talloc_get_type(ptr, struct nss_dp_req); - - /* free timeout event and remove request destructor */ - talloc_free(ndp_req->te); - talloc_set_destructor(ndp_req, NULL); - - ret = nss_dp_get_reply(pending, &err_maj, &err_min, &err_msg); - if (ret != EOK) { - err_maj = DP_ERR_FATAL; - err_min = ret; - err_msg = "Failed to get reply from Data Provider"; - } - - ndp_req->callback(err_maj, err_min, err_msg, ndp_req->callback_ctx); - - talloc_free(ndp_req); -} - -int nss_dp_send_acct_req(struct nss_ctx *nctx, TALLOC_CTX *memctx, - nss_dp_callback_t callback, void *callback_ctx, - int timeout, const char *domain, int type, - const char *opt_name, uint32_t opt_id) -{ - struct nss_dp_req *ndp_req; - DBusMessage *msg; - DBusPendingCall *pending_reply; - DBusConnection *conn; - dbus_bool_t ret; - uint32_t be_type; - const char *attrs = "core"; - char *filter; - struct timeval tv; - - /* either, or, not both */ - if (opt_name && opt_id) { - return EINVAL; - } - - if (!domain) { - return EINVAL; - } - - switch (type) { - case NSS_DP_USER: - be_type = BE_REQ_USER; - break; - case NSS_DP_GROUP: - be_type = BE_REQ_GROUP; - break; - case NSS_DP_INITGROUPS: - be_type = BE_REQ_INITGROUPS; - break; - default: - return EINVAL; - } - - if (opt_name) { - filter = talloc_asprintf(memctx, "name=%s", opt_name); - } else if (opt_id) { - filter = talloc_asprintf(memctx, "idnumber=%u", opt_id); - } else { - filter = talloc_strdup(memctx, "name=*"); - } - if (!filter) { - talloc_free(nctx); - return ENOMEM; - } - - conn = sbus_get_connection(nctx->dp_ctx->scon_ctx); - - /* create the message */ - msg = dbus_message_new_method_call(NULL, - DP_CLI_PATH, - DP_CLI_INTERFACE, - DP_SRV_METHOD_GETACCTINFO); - if (msg == NULL) { - DEBUG(0,("Out of memory?!\n")); - return ENOMEM; - } - - DEBUG(4, ("Sending request for [%s][%u][%s][%s]\n", - domain, be_type, attrs, filter)); - - ret = dbus_message_append_args(msg, - DBUS_TYPE_STRING, &domain, - DBUS_TYPE_UINT32, &be_type, - DBUS_TYPE_STRING, &attrs, - DBUS_TYPE_STRING, &filter, - DBUS_TYPE_INVALID); - if (!ret) { - DEBUG(1,("Failed to build message\n")); - return EIO; - } - - ret = dbus_connection_send_with_reply(conn, msg, &pending_reply, - 600000 /* TODO: set timeout */); - if (!ret) { - /* - * Critical Failure - * We can't communicate on this connection - * We'll drop it using the default destructor. - */ - DEBUG(0, ("D-BUS send failed.\n")); - dbus_message_unref(msg); - return EIO; - } - - ndp_req = talloc_zero(memctx, struct nss_dp_req); - if (!ndp_req) { - dbus_message_unref(msg); - return ENOMEM; - } - ndp_req->callback = callback; - ndp_req->callback_ctx = callback_ctx; - - /* set up destructor */ - ndp_req->pending_reply = pending_reply; - talloc_set_destructor((TALLOC_CTX *)ndp_req, nss_dp_req_destructor); - - /* setup the timeout handler */ - gettimeofday(&tv, NULL); - tv.tv_sec += timeout/1000; - tv.tv_usec += (timeout%1000) * 1000; - ndp_req->te = event_add_timed(nctx->ev, memctx, tv, - nss_dp_send_acct_timeout, ndp_req); - - /* Set up the reply handler */ - dbus_pending_call_set_notify(pending_reply, - nss_dp_send_acct_callback, - ndp_req, NULL); - dbus_message_unref(msg); - - return EOK; -} - -static int nss_dp_get_reply(DBusPendingCall *pending, - dbus_uint16_t *err_maj, - dbus_uint32_t *err_min, - const char **err_msg) -{ - DBusMessage *reply; - DBusError dbus_error; - dbus_bool_t ret; - int type; - int err = EOK; - - dbus_error_init(&dbus_error); - - reply = dbus_pending_call_steal_reply(pending); - if (!reply) { - /* reply should never be null. This function shouldn't be called - * until reply is valid or timeout has occurred. If reply is NULL - * here, something is seriously wrong and we should bail out. - */ - DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n")); - - /* FIXME: Destroy this connection ? */ - err = EIO; - goto done; - } - - type = dbus_message_get_type(reply); - switch (type) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - ret = dbus_message_get_args(reply, &dbus_error, - DBUS_TYPE_UINT16, err_maj, - DBUS_TYPE_UINT32, err_min, - DBUS_TYPE_STRING, err_msg, - DBUS_TYPE_INVALID); - if (!ret) { - DEBUG(1,("Filed to parse message\n")); - /* FIXME: Destroy this connection ? */ - if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error); - err = EIO; - goto done; - } - - DEBUG(4, ("Got reply (%u, %u, %s) from Data Provider\n", - (unsigned int)*err_maj, (unsigned int)*err_min, *err_msg)); - - break; - - case DBUS_MESSAGE_TYPE_ERROR: - DEBUG(0,("The Data Provider returned an error [%s]\n", - dbus_message_get_error_name(reply))); - /* Falling through to default intentionally*/ - default: - /* - * Timeout or other error occurred or something - * unexpected happened. - * It doesn't matter which, because either way we - * know that this connection isn't trustworthy. - * We'll destroy it now. - */ - - /* FIXME: Destroy this connection ? */ - err = EIO; - } - -done: - dbus_pending_call_unref(pending); - dbus_message_unref(reply); - - return err; -} - -static int nss_dp_identity(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - dbus_uint16_t version = DATA_PROVIDER_VERSION; - dbus_uint16_t clitype = DP_CLI_FRONTEND; - const char *cliname = "NSS"; - const char *nullname = ""; - DBusMessage *reply; - dbus_bool_t ret; - - DEBUG(4,("Sending ID reply: (%d,%d,%s)\n", - clitype, version, cliname)); - - reply = dbus_message_new_method_return(message); - if (!reply) return ENOMEM; - - ret = dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &clitype, - DBUS_TYPE_UINT16, &version, - DBUS_TYPE_STRING, &cliname, - DBUS_TYPE_STRING, &nullname, - DBUS_TYPE_INVALID); - if (!ret) { - dbus_message_unref(reply); - return EIO; - } - - /* send reply back */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - return EOK; -} - -struct sbus_method nss_dp_methods[] = { - { DP_CLI_METHOD_IDENTITY, nss_dp_identity }, - { NULL, NULL } -}; - -struct nss_dp_pvt_ctx { - struct nss_ctx *nctx; - struct sbus_method *methods; - time_t last_retry; - int retries; -}; - -static int nss_dp_conn_destructor(void *data); -static void nss_dp_reconnect(struct event_context *ev, - struct timed_event *te, - struct timeval tv, void *data); - -static void nss_dp_conn_reconnect(struct nss_dp_pvt_ctx *pvt) -{ - struct nss_ctx *nctx; - struct timed_event *te; - struct timeval tv; - struct sbus_method_ctx *sm_ctx; - char *sbus_address; - time_t now; - int ret; - - now = time(NULL); - - /* reset retry if last reconnect was > 60 sec. ago */ - if (pvt->last_retry + 60 < now) pvt->retries = 0; - if (pvt->retries >= 3) { - DEBUG(4, ("Too many reconnect retries! Giving up\n")); - return; - } - - pvt->last_retry = now; - pvt->retries++; - - nctx = pvt->nctx; - - ret = dp_get_sbus_address(nctx, nctx->cdb, &sbus_address); - if (ret != EOK) { - DEBUG(0, ("Could not locate data provider address.\n")); - return; - } - - ret = dp_init_sbus_methods(nctx, pvt->methods, &sm_ctx); - if (ret != EOK) { - DEBUG(0, ("Could not initialize SBUS methods.\n")); - return; - } - - ret = sbus_client_init(nctx, nctx->ev, - sbus_address, sm_ctx, - pvt, nss_dp_conn_destructor, - &nctx->dp_ctx); - if (ret != EOK) { - DEBUG(4, ("Failed to reconnect [%d(%s)]!\n", ret, strerror(ret))); - - tv.tv_sec = now +5; - tv.tv_usec = 0; - te = event_add_timed(nctx->ev, nctx, tv, nss_dp_reconnect, pvt); - if (te == NULL) { - DEBUG(4, ("Failed to add timed event! Giving up\n")); - } else { - DEBUG(4, ("Retrying in 5 seconds\n")); - } - } -} - -static void nss_dp_reconnect(struct event_context *ev, - struct timed_event *te, - struct timeval tv, void *data) -{ - struct nss_dp_pvt_ctx *pvt; - - pvt = talloc_get_type(data, struct nss_dp_pvt_ctx); - - nss_dp_conn_reconnect(pvt); -} - -int nss_dp_conn_destructor(void *data) -{ - struct nss_dp_pvt_ctx *pvt; - struct sbus_conn_ctx *scon; - - scon = talloc_get_type(data, struct sbus_conn_ctx); - if (!scon) return 0; - - /* if this is a regular disconnect just quit */ - if (sbus_conn_disconnecting(scon)) return 0; - - pvt = talloc_get_type(sbus_conn_get_private_data(scon), - struct nss_dp_pvt_ctx); - if (pvt) return 0; - - nss_dp_conn_reconnect(pvt); - - return 0; -} - -int nss_dp_init(struct nss_ctx *nctx) -{ - struct nss_dp_pvt_ctx *pvt; - - pvt = talloc_zero(nctx, struct nss_dp_pvt_ctx); - if (!pvt) return ENOMEM; - - pvt->nctx = nctx; - pvt->methods = nss_dp_methods; - - nss_dp_conn_reconnect(pvt); - - return EOK; -} - diff --git a/server/nss/nsssrv_packet.c b/server/nss/nsssrv_packet.c deleted file mode 100644 index f79087d4..00000000 --- a/server/nss/nsssrv_packet.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - SSSD - - NSS Responder, command parser - - Copyright (C) Simo Sorce 2008 - - 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 -#include -#include -#include -#include "talloc.h" -#include "util/util.h" -#include "nss/nsssrv.h" - -#define NSSSRV_PACKET_MEM_SIZE 512 - -struct nss_packet { - size_t memsize; - uint8_t *buffer; - - /* header */ - uint32_t *len; - uint32_t *cmd; - uint32_t *status; - uint32_t *reserved; - - uint8_t *body; - - /* io pointer */ - size_t iop; -}; - -/* - * Allocate a new packet structure - * - * - if size is defined use it otherwise the default packet will be - * NSSSRV_PACKET_MEM_SIZE bytes. - */ -int nss_packet_new(TALLOC_CTX *mem_ctx, size_t size, - enum sss_nss_command cmd, - struct nss_packet **rpacket) -{ - struct nss_packet *packet; - - packet = talloc(mem_ctx, struct nss_packet); - if (!packet) return ENOMEM; - - if (size) { - int n = (size + SSS_NSS_HEADER_SIZE) % NSSSRV_PACKET_MEM_SIZE; - packet->memsize = (n + 1) * NSSSRV_PACKET_MEM_SIZE; - } else { - packet->memsize = NSSSRV_PACKET_MEM_SIZE; - } - - packet->buffer = talloc_size(packet, packet->memsize); - if (!packet->buffer) { - talloc_free(packet); - return ENOMEM; - } - memset(packet->buffer, 0, SSS_NSS_HEADER_SIZE); - - packet->len = &((uint32_t *)packet->buffer)[0]; - packet->cmd = &((uint32_t *)packet->buffer)[1]; - packet->status = &((uint32_t *)packet->buffer)[2]; - packet->reserved = &((uint32_t *)packet->buffer)[3]; - packet->body = (uint8_t *)&((uint32_t *)packet->buffer)[4]; - - *(packet->len) = size + SSS_NSS_HEADER_SIZE; - *(packet->cmd) = cmd; - - packet->iop = 0; - - *rpacket = packet; - - return EOK; -} - -/* grows a packet size only in NSSSRV_PACKET_MEM_SIZE chunks */ -int nss_packet_grow(struct nss_packet *packet, size_t size) -{ - size_t totlen, len; - uint8_t *newmem; - - if (size == 0) { - return EOK; - } - - totlen = packet->memsize; - len = *packet->len + size; - - /* make sure we do not overflow */ - if (totlen < len) { - int n = len % NSSSRV_PACKET_MEM_SIZE + 1; - totlen += n * NSSSRV_PACKET_MEM_SIZE; - if (totlen < len) { - return EINVAL; - } - } - - if (totlen > packet->memsize) { - newmem = talloc_realloc_size(packet, packet->buffer, totlen); - if (!newmem) { - return ENOMEM; - } - - packet->memsize = totlen; - packet->buffer = newmem; - packet->len = &((uint32_t *)packet->buffer)[0]; - packet->cmd = &((uint32_t *)packet->buffer)[1]; - packet->status = &((uint32_t *)packet->buffer)[2]; - packet->reserved = &((uint32_t *)packet->buffer)[3]; - packet->body = (uint8_t *)&((uint32_t *)packet->buffer)[4]; - } - - *(packet->len) += size; - - return 0; -} - -int nss_packet_recv(struct nss_packet *packet, int fd) -{ - size_t rb; - size_t len; - void *buf; - - buf = packet->buffer + packet->iop; - if (packet->iop > 4) len = *packet->len - packet->iop; - else len = packet->memsize - packet->iop; - - /* check for wrapping */ - if (len > packet->memsize) { - return EINVAL; - } - - errno = 0; - rb = recv(fd, buf, len, 0); - - if (rb == -1 && errno == EAGAIN) { - return EAGAIN; - } - - if (rb == 0) { - return ENODATA; - } - - if (*packet->len > packet->memsize) { - return EINVAL; - } - - packet->iop += rb; - if (packet->iop < 4) { - return EAGAIN; - } - - if (packet->iop < *packet->len) { - return EAGAIN; - } - - return EOK; -} - -int nss_packet_send(struct nss_packet *packet, int fd) -{ - size_t rb; - size_t len; - void *buf; - - buf = packet->buffer + packet->iop; - len = *packet->len - packet->iop; - - errno = 0; - rb = send(fd, buf, len, 0); - - if (rb == -1 && errno == EAGAIN) { - return EAGAIN; - } - - if (rb == 0) { - return EIO; - } - - packet->iop += rb; - - if (packet->iop < *packet->len) { - return EAGAIN; - } - - return EOK; -} - -enum sss_nss_command nss_packet_get_cmd(struct nss_packet *packet) -{ - return (enum sss_nss_command)(*packet->cmd); -} - -void nss_packet_get_body(struct nss_packet *packet, uint8_t **body, size_t *blen) -{ - *body = packet->body; - *blen = *packet->len - SSS_NSS_HEADER_SIZE; -} - -void nss_packet_set_error(struct nss_packet *packet, int error) -{ - *(packet->status) = error; -} -- cgit