summaryrefslogtreecommitdiff
path: root/server/nss
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2009-02-24 19:28:40 -0500
committerSimo Sorce <ssorce@redhat.com>2009-02-24 21:00:56 -0500
commit98531e56318b65eb1bb6883fdfe12e771d8a1efe (patch)
treea339a5948604ff62cfafd62a9682130f30df689e /server/nss
parent4c6c0f77a505b6b0790cfa8eedd3133abebd4edb (diff)
downloadsssd-98531e56318b65eb1bb6883fdfe12e771d8a1efe.tar.gz
sssd-98531e56318b65eb1bb6883fdfe12e771d8a1efe.tar.bz2
sssd-98531e56318b65eb1bb6883fdfe12e771d8a1efe.zip
Add PAM responder
Also move responders under server/responder with shared code in server/responder/common Signed-off-by: Simo Sorce <ssorce@redhat.com>
Diffstat (limited to 'server/nss')
-rw-r--r--server/nss/nsssrv.c589
-rw-r--r--server/nss/nsssrv.h122
-rw-r--r--server/nss/nsssrv_cmd.c2237
-rw-r--r--server/nss/nsssrv_dp.c432
-rw-r--r--server/nss/nsssrv_packet.c220
5 files changed, 0 insertions, 3600 deletions
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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <string.h>
-#include <sys/time.h>
-#include <errno.h>
-#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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __NSSSRV_H__
-#define __NSSSRV_H__
-
-#include <stdint.h>
-#include <sys/un.h>
-#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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>.
-*/
-
-#include "util/util.h"
-#include "util/btreemap.h"
-#include "nss/nsssrv.h"
-#include "db/sysdb.h"
-#include <time.h>
-
-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:"<NULL>", (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:"<NULL>", (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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>.
-*/
-
-#include <sys/time.h>
-#include <time.h>
-#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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>.
-*/
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <errno.h>
-#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;
-}