diff options
Diffstat (limited to 'server/responder')
-rw-r--r-- | server/responder/common/responder.h | 152 | ||||
-rw-r--r-- | server/responder/common/responder_cmd.c | 103 | ||||
-rw-r--r-- | server/responder/common/responder_common.c | 589 | ||||
-rw-r--r-- | server/responder/common/responder_dp.c | 590 | ||||
-rw-r--r-- | server/responder/common/responder_packet.c | 253 | ||||
-rw-r--r-- | server/responder/common/responder_packet.h | 43 | ||||
-rw-r--r-- | server/responder/nss/nsssrv.c | 367 | ||||
-rw-r--r-- | server/responder/nss/nsssrv.h | 70 | ||||
-rw-r--r-- | server/responder/nss/nsssrv_cmd.c | 3182 | ||||
-rw-r--r-- | server/responder/nss/nsssrv_nc.c | 321 | ||||
-rw-r--r-- | server/responder/nss/nsssrv_nc.h | 51 | ||||
-rw-r--r-- | server/responder/pam/pam_LOCAL_domain.c | 476 | ||||
-rw-r--r-- | server/responder/pam/pamsrv.c | 224 | ||||
-rw-r--r-- | server/responder/pam/pamsrv.h | 57 | ||||
-rw-r--r-- | server/responder/pam/pamsrv_cmd.c | 1181 | ||||
-rw-r--r-- | server/responder/pam/pamsrv_dp.c | 142 |
16 files changed, 0 insertions, 7801 deletions
diff --git a/server/responder/common/responder.h b/server/responder/common/responder.h deleted file mode 100644 index ea6ba5831..000000000 --- a/server/responder/common/responder.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - SSSD - - SSS Client 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 __SSS_RESPONDER_H__ -#define __SSS_RESPONDER_H__ - -#include <stdint.h> -#include <sys/un.h> -#include <pcre.h> -#include "config.h" -#include "talloc.h" -#include "tevent.h" -#include "ldb.h" -#include "dhash.h" -#include "sbus/sssd_dbus.h" -#include "sss_client/sss_cli.h" - -extern hash_table_t *dp_requests; - -/* if there is a provider other than the special local */ -#define NEED_CHECK_PROVIDER(provider) \ - (provider != NULL && strcmp(provider, "local") != 0) - -/* needed until nsssrv.h is updated */ -struct cli_request { - - /* original request from the wire */ - struct sss_packet *in; - - /* reply data */ - struct sss_packet *out; -}; - -struct cli_protocol_version { - uint32_t version; - const char *date; - const char *description; -}; - -struct be_conn { - struct be_conn *next; - struct be_conn *prev; - - const char *cli_name; - struct sss_domain_info *domain; - - char *sbus_address; - struct sbus_interface *intf; - struct sbus_connection *conn; -}; - -struct resp_ctx { - struct tevent_context *ev; - struct tevent_fd *lfde; - int lfd; - struct tevent_fd *priv_lfde; - int priv_lfd; - struct confdb_ctx *cdb; - const char *sock_name; - const char *priv_sock_name; - - struct sbus_connection *mon_conn; - struct be_conn *be_conns; - - struct sss_domain_info *domains; - struct sysdb_ctx_list *db_list; - - struct sss_cmd_table *sss_cmds; - const char *sss_pipe_name; - const char *confdb_service_path; - - struct sss_names_ctx *names; - - void *pvt_ctx; -}; - -struct cli_ctx { - struct tevent_context *ev; - struct resp_ctx *rctx; - int cfd; - struct tevent_fd *cfde; - struct sockaddr_un addr; - struct cli_request *creq; - struct cli_protocol_version *cli_protocol_version; - int priv; -}; - -struct sss_cmd_table { - enum sss_cli_command cmd; - int (*fn)(struct cli_ctx *cctx); -}; - -/* responder_common.c */ -int sss_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb, - struct sss_cmd_table sss_cmds[], - const char *sss_pipe_name, - const char *sss_priv_pipe_name, - const char *confdb_service_path, - const char *svc_name, - uint16_t svc_version, - struct sbus_interface *monitor_intf, - const char *cli_name, - struct sbus_interface *dp_intf, - struct resp_ctx **responder_ctx); - -int sss_parse_name(TALLOC_CTX *memctx, - struct sss_names_ctx *snctx, - const char *orig, char **domain, char **name); - -int sss_dp_get_domain_conn(struct resp_ctx *rctx, const char *domain, - struct be_conn **_conn); - -/* responder_cmd.c */ -int sss_cmd_execute(struct cli_ctx *cctx, struct sss_cmd_table *sss_cmds); -void sss_cmd_done(struct cli_ctx *cctx, void *freectx); -int sss_cmd_get_version(struct cli_ctx *cctx); -struct cli_protocol_version *register_cli_protocol_version(void); - -#define SSS_DP_USER 1 -#define SSS_DP_GROUP 2 -#define SSS_DP_INITGROUPS 3 - -typedef void (*sss_dp_callback_t)(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -int sss_dp_send_acct_req(struct resp_ctx *rctx, TALLOC_CTX *callback_memctx, - sss_dp_callback_t callback, void *callback_ctx, - int timeout, const char *domain, - bool fast_reply, int type, - const char *opt_name, uint32_t opt_id); - -#endif /* __SSS_RESPONDER_H__ */ diff --git a/server/responder/common/responder_cmd.c b/server/responder/common/responder_cmd.c deleted file mode 100644 index cd9890305..000000000 --- a/server/responder/common/responder_cmd.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - SSSD - - SSS Client 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 <errno.h> -#include "util/util.h" -#include "responder/common/responder.h" -#include "responder/common/responder_packet.h" - - -void sss_cmd_done(struct cli_ctx *cctx, void *freectx) -{ - /* now that the packet is in place, unlock queue - * making the event writable */ - TEVENT_FD_WRITEABLE(cctx->cfde); - - /* free all request related data through the talloc hierarchy */ - talloc_free(freectx); -} - -int sss_cmd_get_version(struct cli_ctx *cctx) -{ - uint8_t *req_body; - size_t req_blen; - uint8_t *body; - size_t blen; - int ret; - uint32_t client_version; - int i; - static struct cli_protocol_version *cli_protocol_version = NULL; - - cctx->cli_protocol_version = NULL; - - if (cli_protocol_version == NULL) { - cli_protocol_version = register_cli_protocol_version(); - } - - if (cli_protocol_version != NULL) { - cctx->cli_protocol_version = &cli_protocol_version[0]; - - sss_packet_get_body(cctx->creq->in, &req_body, &req_blen); - if (req_blen == sizeof(uint32_t)) { - memcpy(&client_version, req_body, sizeof(uint32_t)); - DEBUG(5, ("Received client version [%d].\n", client_version)); - - i=0; - while(cli_protocol_version[i].version>0) { - if (cli_protocol_version[i].version == client_version) { - cctx->cli_protocol_version = &cli_protocol_version[i]; - break; - } - i++; - } - } - } - - /* create response packet */ - ret = sss_packet_new(cctx->creq, sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = cctx->cli_protocol_version!=NULL ? - cctx->cli_protocol_version->version : 0; - DEBUG(5, ("Offered version [%d].\n", ((uint32_t *)body)[0])); - - sss_cmd_done(cctx, NULL); - return EOK; -} - -int sss_cmd_execute(struct cli_ctx *cctx, struct sss_cmd_table *sss_cmds) -{ - enum sss_cli_command cmd; - int i; - - cmd = sss_packet_get_cmd(cctx->creq->in); - - for (i = 0; sss_cmds[i].cmd != SSS_CLI_NULL; i++) { - if (cmd == sss_cmds[i].cmd) { - return sss_cmds[i].fn(cctx); - } - } - - return EINVAL; -} diff --git a/server/responder/common/responder_common.c b/server/responder/common/responder_common.c deleted file mode 100644 index 37bbcb30f..000000000 --- a/server/responder/common/responder_common.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - SSSD - - Common Responder methods - - 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 "db/sysdb.h" -#include "confdb/confdb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "responder/common/responder.h" -#include "responder/common/responder_packet.h" -#include "providers/data_provider.h" -#include "monitor/monitor_interfaces.h" -#include "sbus/sbus_client.h" - -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 tevent_context *ev, struct cli_ctx *cctx) -{ - int ret; - - ret = sss_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 */ - TEVENT_FD_NOT_WRITEABLE(cctx->cfde); - TEVENT_FD_READABLE(cctx->cfde); - talloc_free(cctx->creq); - cctx->creq = NULL; - return; -} - -static void client_recv(struct tevent_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 = sss_packet_new(cctx->creq, SSS_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 = sss_packet_recv(cctx->creq->in, cctx->cfd); - switch (ret) { - case EOK: - /* do not read anymore */ - TEVENT_FD_NOT_READABLE(cctx->cfde); - /* execute command */ - ret = sss_cmd_execute(cctx, cctx->rctx->sss_cmds); - 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 tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *ptr) -{ - struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx); - - if (flags & TEVENT_FD_READ) { - client_recv(ev, cctx); - return; - } - if (flags & TEVENT_FD_WRITE) { - client_send(ev, cctx); - return; - } -} - -/* TODO: this is a copy of accept_fd_handler, maybe both can be put into on - * handler. */ -static void accept_priv_fd_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *ptr) -{ - /* accept and attach new event handler */ - struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx); - struct cli_ctx *cctx; - socklen_t len; - struct stat stat_buf; - int ret; - - ret = stat(rctx->priv_sock_name, &stat_buf); - if (ret == -1) { - DEBUG(1, ("stat on privileged pipe failed: [%d][%s].\n", errno, - strerror(errno))); - return; - } - - if ( ! (stat_buf.st_uid == 0 && stat_buf.st_gid == 0 && - (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) { - DEBUG(1, ("privileged pipe has an illegal status.\n")); -/* TODO: what is the best response to this condition? Terminate? */ - return; - } - - - cctx = talloc_zero(rctx, struct cli_ctx); - if (!cctx) { - struct sockaddr_un addr; - int fd; - DEBUG(0, ("Out of memory trying to setup client context on privileged pipe!\n")); - /* accept and close to signal the client we have a problem */ - memset(&addr, 0, sizeof(addr)); - len = sizeof(addr); - fd = accept(rctx->priv_lfd, (struct sockaddr *)&addr, &len); - if (fd == -1) { - return; - } - close(fd); - return; - } - - len = sizeof(cctx->addr); - cctx->cfd = accept(rctx->priv_lfd, (struct sockaddr *)&cctx->addr, &len); - if (cctx->cfd == -1) { - DEBUG(1, ("Accept failed [%s]", strerror(errno))); - talloc_free(cctx); - return; - } - - cctx->priv = 1; - - cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd, - TEVENT_FD_READ, client_fd_handler, cctx); - if (!cctx->cfde) { - close(cctx->cfd); - talloc_free(cctx); - DEBUG(2, ("Failed to queue client handler on privileged pipe\n")); - } - - cctx->ev = ev; - cctx->rctx = rctx; - - talloc_set_destructor(cctx, client_destructor); - - DEBUG(4, ("Client connected to privileged pipe!\n")); - - return; -} - -static void accept_fd_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *ptr) -{ - /* accept and attach new event handler */ - struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx); - struct cli_ctx *cctx; - socklen_t len; - - cctx = talloc_zero(rctx, 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(rctx->lfd, (struct sockaddr *)&addr, &len); - if (fd == -1) { - return; - } - close(fd); - return; - } - - len = sizeof(cctx->addr); - cctx->cfd = accept(rctx->lfd, (struct sockaddr *)&cctx->addr, &len); - if (cctx->cfd == -1) { - DEBUG(1, ("Accept failed [%s]", strerror(errno))); - talloc_free(cctx); - return; - } - - cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd, - TEVENT_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->rctx = rctx; - - talloc_set_destructor(cctx, client_destructor); - - DEBUG(4, ("Client connected!\n")); - - return; -} - -static int sss_monitor_init(struct resp_ctx *rctx, - struct sbus_interface *intf, - const char *svc_name, - uint16_t svc_version) -{ - char *sbus_address; - int ret; - - /* Set up SBUS connection to the monitor */ - ret = monitor_get_sbus_address(rctx, &sbus_address); - if (ret != EOK) { - DEBUG(0, ("Could not locate monitor address.\n")); - return ret; - } - - ret = sbus_client_init(rctx, rctx->ev, sbus_address, - intf, &rctx->mon_conn, - NULL, NULL); - if (ret != EOK) { - DEBUG(0, ("Failed to connect to monitor services.\n")); - return ret; - } - - /* Identify ourselves to the monitor */ - ret = monitor_common_send_id(rctx->mon_conn, svc_name, svc_version); - if (ret != EOK) { - DEBUG(0, ("Failed to identify to the monitor!\n")); - return ret; - } - - return EOK; -} - -static int sss_dp_init(struct resp_ctx *rctx, - struct sbus_interface *intf, - const char *cli_name, - struct sss_domain_info *domain) -{ - struct be_conn *be_conn; - int ret; - - be_conn = talloc_zero(rctx, struct be_conn); - if (!be_conn) return ENOMEM; - - be_conn->cli_name = cli_name; - be_conn->domain = domain; - be_conn->intf = intf; - - /* Set up SBUS connection to the monitor */ - ret = dp_get_sbus_address(be_conn, &be_conn->sbus_address, domain->name); - if (ret != EOK) { - DEBUG(0, ("Could not locate DP address.\n")); - return ret; - } - ret = sbus_client_init(rctx, rctx->ev, - be_conn->sbus_address, - intf, &be_conn->conn, - NULL, NULL); - if (ret != EOK) { - DEBUG(0, ("Failed to connect to monitor services.\n")); - return ret; - } - - DLIST_ADD_END(rctx->be_conns, be_conn, struct be_conn *); - - /* Identify ourselves to the DP */ - ret = dp_common_send_id(be_conn->conn, - DATA_PROVIDER_VERSION, - cli_name, domain->name); - if (ret != EOK) { - DEBUG(0, ("Failed to identify to the DP!\n")); - return ret; - } - - return EOK; -} - -/* create a unix socket and listen to it */ -static int set_unix_socket(struct resp_ctx *rctx) -{ - struct sockaddr_un addr; - -/* for future use */ -#if 0 - char *default_pipe; - int ret; - - default_pipe = talloc_asprintf(rctx, "%s/%s", PIPE_PATH, - rctx->sss_pipe_name); - if (!default_pipe) { - return ENOMEM; - } - - ret = confdb_get_string(rctx->cdb, rctx, - rctx->confdb_socket_path, "unixSocket", - default_pipe, &rctx->sock_name); - if (ret != EOK) { - talloc_free(default_pipe); - return ret; - } - talloc_free(default_pipe); - - default_pipe = talloc_asprintf(rctx, "%s/private/%s", PIPE_PATH, - rctx->sss_pipe_name); - if (!default_pipe) { - return ENOMEM; - } - - ret = confdb_get_string(rctx->cdb, rctx, - rctx->confdb_socket_path, "privUnixSocket", - default_pipe, &rctx->priv_sock_name); - if (ret != EOK) { - talloc_free(default_pipe); - return ret; - } - talloc_free(default_pipe); -#endif - - if (rctx->sock_name != NULL ) { - rctx->lfd = socket(AF_UNIX, SOCK_STREAM, 0); - if (rctx->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(rctx->lfd); - set_close_on_exec(rctx->lfd); - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, rctx->sock_name, sizeof(addr.sun_path)); - - /* make sure we have no old sockets around */ - unlink(rctx->sock_name); - - if (bind(rctx->lfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - DEBUG(0,("Unable to bind on socket '%s'\n", rctx->sock_name)); - goto failed; - } - if (listen(rctx->lfd, 10) != 0) { - DEBUG(0,("Unable to listen on socket '%s'\n", rctx->sock_name)); - goto failed; - } - - rctx->lfde = tevent_add_fd(rctx->ev, rctx, rctx->lfd, - TEVENT_FD_READ, accept_fd_handler, rctx); - if (!rctx->lfde) { - DEBUG(0, ("Failed to queue handler on pipe\n")); - goto failed; - } - } - - if (rctx->priv_sock_name != NULL ) { - /* create privileged pipe */ - rctx->priv_lfd = socket(AF_UNIX, SOCK_STREAM, 0); - if (rctx->priv_lfd == -1) { - close(rctx->lfd); - return EIO; - } - - umask(0177); - - set_nonblocking(rctx->priv_lfd); - set_close_on_exec(rctx->priv_lfd); - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, rctx->priv_sock_name, sizeof(addr.sun_path)); - - unlink(rctx->priv_sock_name); - - if (bind(rctx->priv_lfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - DEBUG(0,("Unable to bind on socket '%s'\n", rctx->priv_sock_name)); - goto failed; - } - if (listen(rctx->priv_lfd, 10) != 0) { - DEBUG(0,("Unable to listen on socket '%s'\n", rctx->priv_sock_name)); - goto failed; - } - - rctx->priv_lfde = tevent_add_fd(rctx->ev, rctx, rctx->priv_lfd, - TEVENT_FD_READ, accept_priv_fd_handler, rctx); - if (!rctx->priv_lfde) { - DEBUG(0, ("Failed to queue handler on privileged pipe\n")); - goto failed; - } - } - - /* 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(rctx->lfd); - close(rctx->priv_lfd); - return EIO; -} - -int sss_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb, - struct sss_cmd_table sss_cmds[], - const char *sss_pipe_name, - const char *sss_priv_pipe_name, - const char *confdb_service_path, - const char *svc_name, - uint16_t svc_version, - struct sbus_interface *monitor_intf, - const char *cli_name, - struct sbus_interface *dp_intf, - struct resp_ctx **responder_ctx) -{ - struct resp_ctx *rctx; - struct sss_domain_info *dom; - int ret; - - rctx = talloc_zero(mem_ctx, struct resp_ctx); - if (!rctx) { - DEBUG(0, ("fatal error initializing resp_ctx\n")); - return ENOMEM; - } - rctx->ev = ev; - rctx->cdb = cdb; - rctx->sss_cmds = sss_cmds; - rctx->sock_name = sss_pipe_name; - rctx->priv_sock_name = sss_priv_pipe_name; - rctx->confdb_service_path = confdb_service_path; - - ret = confdb_get_domains(rctx->cdb, &rctx->domains); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up domain map\n")); - return ret; - } - - ret = sss_monitor_init(rctx, monitor_intf, svc_name, svc_version); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up message bus\n")); - return ret; - } - - for (dom = rctx->domains; dom; dom = dom->next) { - - /* skip local domain, it doesn't have a backend */ - if (strcasecmp(dom->provider, "local") == 0) { - continue; - } - - ret = sss_dp_init(rctx, dp_intf, cli_name, dom); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up backend connector\n")); - return ret; - } - } - - ret = sysdb_init(rctx, ev, cdb, NULL, false, &rctx->db_list); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing resp_ctx\n")); - return ret; - } - - ret = sss_names_init(rctx, rctx->cdb, &rctx->names); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing regex data\n")); - return ret; - } - - /* after all initializations we are ready to listen on our socket */ - ret = set_unix_socket(rctx); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing socket\n")); - return ret; - } - - DEBUG(1, ("Responder Initialization complete\n")); - - *responder_ctx = rctx; - return EOK; -} - -int sss_dp_get_domain_conn(struct resp_ctx *rctx, const char *domain, - struct be_conn **_conn) -{ - struct be_conn *iter; - - if (!rctx->be_conns) return ENOENT; - - for (iter = rctx->be_conns; iter; iter = iter->next) { - if (strcasecmp(domain, iter->domain->name) == 0) break; - } - - if (!iter) return ENOENT; - - *_conn = iter; - - return EOK; -} - diff --git a/server/responder/common/responder_dp.c b/server/responder/common/responder_dp.c deleted file mode 100644 index 782befb17..000000000 --- a/server/responder/common/responder_dp.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - Authors: - Simo Sorce <ssorce@redhat.com> - Stephen Gallagher <sgallagh@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - - -#include <sys/time.h> -#include <time.h> -#include "util/util.h" -#include "responder/common/responder_packet.h" -#include "responder/common/responder.h" -#include "providers/data_provider.h" -#include "sbus/sbus_client.h" - -hash_table_t *dp_requests = NULL; - -struct sss_dp_req; - -struct sss_dp_callback { - struct sss_dp_callback *prev; - struct sss_dp_callback *next; - - struct sss_dp_req *sdp_req; - - sss_dp_callback_t callback; - void *callback_ctx; -}; - -struct sss_dp_req { - struct tevent_context *ev; - DBusPendingCall *pending_reply; - - char *key; - - struct tevent_timer *tev; - struct sss_dp_callback *cb_list; - - dbus_uint16_t err_maj; - dbus_uint32_t err_min; - char *err_msg; -}; - -static int sss_dp_callback_destructor(void *ptr) -{ - struct sss_dp_callback *cb = talloc_get_type(ptr, struct sss_dp_callback); - - DLIST_REMOVE(cb->sdp_req->cb_list, cb); - - return EOK; -} - -static int sss_dp_req_destructor(void *ptr) -{ - struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req); - struct sss_dp_callback *cb, *next; - hash_key_t key; - - /* Cancel Dbus pending reply if still pending */ - if (sdp_req->pending_reply) { - dbus_pending_call_cancel(sdp_req->pending_reply); - sdp_req->pending_reply = NULL; - } - - /* Destroy the hash entry */ - key.type = HASH_KEY_STRING; - key.str = sdp_req->key; - int hret = hash_delete(dp_requests, &key); - if (hret != HASH_SUCCESS) { - /* This should never happen */ - DEBUG(0, ("Could not clear entry from request queue\n")); - } - - /* Free any remaining callback */ - if (sdp_req->err_maj == DP_ERR_OK) { - sdp_req->err_maj = DP_ERR_FATAL; - sdp_req->err_min = EIO; - sdp_req->err_msg = discard_const_p(char, "Internal Error"); - } - - cb = sdp_req->cb_list; - while (cb) { - cb->callback(sdp_req->err_maj, - sdp_req->err_min, - sdp_req->err_msg, - cb->callback_ctx); - next = cb->next; - talloc_free(cb); - cb = next; - } - - return 0; -} - -static void sdp_req_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval t, void *ptr) -{ - struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req); - - sdp_req->err_maj = DP_ERR_FATAL; - sdp_req->err_min = ETIMEDOUT; - sdp_req->err_msg = discard_const_p(char, "Timed out"); - - /* steal te on NULL because it will be freed as soon as the handler - * returns. Causing a double free if we don't, as te is allocated on - * sdp_req and we are just going to free it */ - talloc_steal(NULL, te); - - talloc_free(sdp_req); -} - -static int sss_dp_get_reply(DBusPendingCall *pending, - dbus_uint16_t *err_maj, - dbus_uint32_t *err_min, - char **err_msg); - -static void sss_dp_invoke_callback(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval t, void *ptr) -{ - struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req); - struct sss_dp_callback *cb; - struct timeval tv; - struct tevent_timer *tev; - - cb = sdp_req->cb_list; - /* Remove the callback from the list, the caller may free it, within the - * callback. */ - talloc_set_destructor((TALLOC_CTX *)cb, NULL); - DLIST_REMOVE(sdp_req->cb_list, cb); - - cb->callback(sdp_req->err_maj, - sdp_req->err_min, - sdp_req->err_msg, - cb->callback_ctx); - - /* Call the next callback if needed */ - if (sdp_req->cb_list != NULL) { - tv = tevent_timeval_current(); - tev = tevent_add_timer(sdp_req->ev, sdp_req, tv, - sss_dp_invoke_callback, sdp_req); - if (!te) { - /* Out of memory or other serious error */ - goto done; - } - - return; - } - - /* No more callbacks to invoke. Destroy the request */ -done: - /* steal te on NULL because it will be freed as soon as the handler - * returns. Causing a double free if we don't, as te is allocated on - * sdp_req and we are just going to free it */ - talloc_steal(NULL, te); - - talloc_zfree(sdp_req); -} - -static void sss_dp_send_acct_callback(DBusPendingCall *pending, void *ptr) -{ - int ret; - struct sss_dp_req *sdp_req; - struct sss_dp_callback *cb; - struct timeval tv; - struct tevent_timer *te; - - sdp_req = talloc_get_type(ptr, struct sss_dp_req); - - /* prevent trying to cancel a reply that we already received */ - sdp_req->pending_reply = NULL; - - ret = sss_dp_get_reply(pending, - &sdp_req->err_maj, - &sdp_req->err_min, - &sdp_req->err_msg); - if (ret != EOK) { - if (ret == ETIME) { - sdp_req->err_maj = DP_ERR_TIMEOUT; - sdp_req->err_min = ret; - sdp_req->err_msg = talloc_strdup(sdp_req, "Request timed out"); - } - else { - sdp_req->err_maj = DP_ERR_FATAL; - sdp_req->err_min = ret; - sdp_req->err_msg = - talloc_strdup(sdp_req, - "Failed to get reply from Data Provider"); - } - } - - /* Check whether we need to issue any callbacks */ - cb = sdp_req->cb_list; - if (sdp_req->cb_list == NULL) { - if (cb == NULL) { - /* No callbacks to invoke. Destroy the hash entry */ - talloc_zfree(sdp_req); - return; - } - } - - /* Queue up all callbacks */ - tv = tevent_timeval_current(); - te = tevent_add_timer(sdp_req->ev, sdp_req, tv, - sss_dp_invoke_callback, sdp_req); - if (!te) { - /* Out of memory or other serious error */ - goto error; - } - - return; - -error: - talloc_zfree(sdp_req); -} - -static int sss_dp_send_acct_req_create(struct resp_ctx *rctx, - TALLOC_CTX *callback_memctx, - const char *domain, - uint32_t be_type, - char *filter, - int timeout, - sss_dp_callback_t callback, - void *callback_ctx, - struct sss_dp_req **ndp); - -int sss_dp_send_acct_req(struct resp_ctx *rctx, TALLOC_CTX *callback_memctx, - sss_dp_callback_t callback, void *callback_ctx, - int timeout, const char *domain, - bool fast_reply, int type, - const char *opt_name, uint32_t opt_id) -{ - int ret, hret; - uint32_t be_type; - char *filter; - hash_key_t key; - hash_value_t value; - TALLOC_CTX *tmp_ctx; - struct timeval tv; - struct sss_dp_req *sdp_req = NULL; - struct sss_dp_callback *cb; - - /* either, or, not both */ - if (opt_name && opt_id) { - return EINVAL; - } - - if (!domain) { - return EINVAL; - } - - switch (type) { - case SSS_DP_USER: - be_type = BE_REQ_USER; - break; - case SSS_DP_GROUP: - be_type = BE_REQ_GROUP; - break; - case SSS_DP_INITGROUPS: - be_type = BE_REQ_INITGROUPS; - break; - default: - return EINVAL; - } - - if (fast_reply) { - be_type |= BE_REQ_FAST; - } - - if (dp_requests == NULL) { - /* Create a hash table to handle queued update requests */ - ret = hash_create(10, &dp_requests, NULL, NULL); - if (ret != HASH_SUCCESS) { - fprintf(stderr, "cannot create hash table (%s)\n", hash_error_string(ret)); - return EIO; - } - } - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - return ENOMEM; - } - - key.type = HASH_KEY_STRING; - key.str = NULL; - - if (opt_name) { - filter = talloc_asprintf(tmp_ctx, "name=%s", opt_name); - key.str = talloc_asprintf(tmp_ctx, "%d%s@%s", type, opt_name, domain); - } else if (opt_id) { - filter = talloc_asprintf(tmp_ctx, "idnumber=%u", opt_id); - key.str = talloc_asprintf(tmp_ctx, "%d%d@%s", type, opt_id, domain); - } else { - filter = talloc_strdup(tmp_ctx, "name=*"); - key.str = talloc_asprintf(tmp_ctx, "%d*@%s", type, domain); - } - if (!filter || !key.str) { - talloc_zfree(tmp_ctx); - return ENOMEM; - } - - /* Check whether there's already a request in progress */ - hret = hash_lookup(dp_requests, &key, &value); - switch (hret) { - case HASH_SUCCESS: - /* Request already in progress - * Add an additional callback if needed and return - */ - DEBUG(2, ("Identical request in progress\n")); - - if (callback) { - /* We have a new request asking for a callback */ - sdp_req = talloc_get_type(value.ptr, struct sss_dp_req); - if (!sdp_req) { - DEBUG(0, ("Could not retrieve DP request context\n")); - ret = EIO; - goto done; - } - - cb = talloc_zero(callback_memctx, struct sss_dp_callback); - if (!cb) { - ret = ENOMEM; - goto done; - } - - cb->callback = callback; - cb->callback_ctx = callback_ctx; - cb->sdp_req = sdp_req; - - DLIST_ADD_END(sdp_req->cb_list, cb, struct sss_dp_callback *); - talloc_set_destructor((TALLOC_CTX *)cb, sss_dp_callback_destructor); - } - - ret = EOK; - break; - - case HASH_ERROR_KEY_NOT_FOUND: - /* No such request in progress - * Create a new request - */ - ret = sss_dp_send_acct_req_create(rctx, callback_memctx, domain, - be_type, filter, timeout, - callback, callback_ctx, - &sdp_req); - if (ret != EOK) { - goto done; - } - - value.type = HASH_VALUE_PTR; - value.ptr = sdp_req; - hret = hash_enter(dp_requests, &key, &value); - if (hret != HASH_SUCCESS) { - DEBUG(0, ("Could not store request query (%s)", - hash_error_string(hret))); - talloc_zfree(sdp_req); - ret = EIO; - goto done; - } - - sdp_req->key = talloc_strdup(sdp_req, key.str); - - tv = tevent_timeval_current_ofs(timeout, 0); - sdp_req->tev = tevent_add_timer(sdp_req->ev, sdp_req, tv, - sdp_req_timeout, sdp_req); - if (!sdp_req->tev) { - DEBUG(0, ("Out of Memory!?")); - talloc_zfree(sdp_req); - ret = ENOMEM; - goto done; - } - - talloc_set_destructor((TALLOC_CTX *)sdp_req, sss_dp_req_destructor); - - ret = EOK; - break; - - default: - DEBUG(0,("Could not query request list (%s)\n", - hash_error_string(hret))); - talloc_zfree(sdp_req); - ret = EIO; - } - -done: - talloc_zfree(tmp_ctx); - return ret; -} - -static int sss_dp_send_acct_req_create(struct resp_ctx *rctx, - TALLOC_CTX *callback_memctx, - const char *domain, - uint32_t be_type, - char *filter, - int timeout, - sss_dp_callback_t callback, - void *callback_ctx, - struct sss_dp_req **ndp) -{ - DBusConnection *dbus_conn; - DBusMessage *msg; - DBusPendingCall *pending_reply; - dbus_bool_t dbret; - struct sss_dp_callback *cb; - struct sss_dp_req *sdp_req; - uint32_t attrs = BE_ATTR_CORE; - struct be_conn *be_conn; - int ret; - - /* double check dp_ctx has actually been initialized. - * in some pathological cases it may happen that nss starts up before - * dp connection code is actually able to establish a connection. - */ - ret = sss_dp_get_domain_conn(rctx, domain, &be_conn); - if (ret != EOK) { - DEBUG(1, ("The Data Provider connection for %s is not available!" - " This maybe a bug, it shouldn't happen!\n", domain)); - return EIO; - } - dbus_conn = sbus_get_connection(be_conn->conn); - - /* create the message */ - msg = dbus_message_new_method_call(NULL, - DP_PATH, - DP_INTERFACE, - DP_METHOD_GETACCTINFO); - if (msg == NULL) { - DEBUG(0,("Out of memory?!\n")); - return ENOMEM; - } - - DEBUG(4, ("Sending request for [%s][%u][%d][%s]\n", - domain, be_type, attrs, filter)); - - dbret = dbus_message_append_args(msg, - DBUS_TYPE_UINT32, &be_type, - DBUS_TYPE_UINT32, &attrs, - DBUS_TYPE_STRING, &filter, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(1,("Failed to build message\n")); - return EIO; - } - - dbret = dbus_connection_send_with_reply(dbus_conn, msg, - &pending_reply, timeout); - if (!dbret || pending_reply == NULL) { - /* - * 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; - } - - sdp_req = talloc_zero(rctx, struct sss_dp_req); - if (!sdp_req) { - dbus_message_unref(msg); - return ENOMEM; - } - sdp_req->ev = rctx->ev; - sdp_req->pending_reply = pending_reply; - - if (callback) { - cb = talloc_zero(callback_memctx, struct sss_dp_callback); - if (!cb) { - dbus_message_unref(msg); - talloc_zfree(sdp_req); - return ENOMEM; - } - cb->callback = callback; - cb->callback_ctx = callback_ctx; - cb->sdp_req = sdp_req; - - DLIST_ADD(sdp_req->cb_list, cb); - talloc_set_destructor((TALLOC_CTX *)cb, sss_dp_callback_destructor); - } - - /* Set up the reply handler */ - dbret = dbus_pending_call_set_notify(pending_reply, - sss_dp_send_acct_callback, - sdp_req, NULL); - if (!dbret) { - DEBUG(0, ("Could not queue up pending request!")); - talloc_zfree(sdp_req); - dbus_pending_call_cancel(pending_reply); - dbus_message_unref(msg); - return EIO; - } - - dbus_message_unref(msg); - - *ndp = sdp_req; - - return EOK; -} - -static int sss_dp_get_reply(DBusPendingCall *pending, - dbus_uint16_t *err_maj, - dbus_uint32_t *err_min, - 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,("Failed 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: - if (strcmp(dbus_message_get_error_name(reply), - DBUS_ERROR_NO_REPLY) == 0) { - err = ETIME; - goto done; - } - 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; -} - diff --git a/server/responder/common/responder_packet.c b/server/responder/common/responder_packet.c deleted file mode 100644 index 6e581a3c9..000000000 --- a/server/responder/common/responder_packet.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - SSSD - - SSS Client 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 "responder/common/responder_packet.h" - -#define SSSSRV_PACKET_MEM_SIZE 512 - -struct sss_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 - * SSSSRV_PACKET_MEM_SIZE bytes. - */ -int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size, - enum sss_cli_command cmd, - struct sss_packet **rpacket) -{ - struct sss_packet *packet; - - packet = talloc(mem_ctx, struct sss_packet); - if (!packet) return ENOMEM; - - if (size) { - int n = (size + SSS_NSS_HEADER_SIZE) % SSSSRV_PACKET_MEM_SIZE; - packet->memsize = (n + 1) * SSSSRV_PACKET_MEM_SIZE; - } else { - packet->memsize = SSSSRV_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 SSSSRV_PACKET_MEM_SIZE chunks */ -int sss_packet_grow(struct sss_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 % SSSSRV_PACKET_MEM_SIZE + 1; - totlen += n * SSSSRV_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; - - /* re-set pointers if realloc had to move memory */ - if (newmem != packet->buffer) { - 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; -} - -/* reclaim backet previously resrved space in the packet - * usually done in functione recovering from not fatal erros */ -int sss_packet_shrink(struct sss_packet *packet, size_t size) -{ - size_t newlen; - - if (size > *(packet->len)) return EINVAL; - - newlen = *(packet->len) - size; - if (newlen < SSS_NSS_HEADER_SIZE) return EINVAL; - - *(packet->len) = newlen; - return 0; -} - -int sss_packet_set_size(struct sss_packet *packet, size_t size) -{ - size_t newlen; - - newlen = SSS_NSS_HEADER_SIZE + size; - - /* make sure we do not overflow */ - if (packet->memsize < newlen) return EINVAL; - - *(packet->len) = newlen; - - return 0; -} - -int sss_packet_recv(struct sss_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 sss_packet_send(struct sss_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_cli_command sss_packet_get_cmd(struct sss_packet *packet) -{ - return (enum sss_cli_command)(*packet->cmd); -} - -void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen) -{ - *body = packet->body; - *blen = *packet->len - SSS_NSS_HEADER_SIZE; -} - -void sss_packet_set_error(struct sss_packet *packet, int error) -{ - *(packet->status) = error; -} diff --git a/server/responder/common/responder_packet.h b/server/responder/common/responder_packet.h deleted file mode 100644 index 2bfdc8a32..000000000 --- a/server/responder/common/responder_packet.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - SSSD - - SSS Client 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 __SSSSRV_PACKET_H__ -#define __SSSSRV_PACKET_H__ - -#include "sss_client/sss_cli.h" - -#define SSS_PACKET_MAX_RECV_SIZE 1024 - -struct sss_packet; - -int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size, - enum sss_cli_command cmd, - struct sss_packet **rpacket); -int sss_packet_grow(struct sss_packet *packet, size_t size); -int sss_packet_shrink(struct sss_packet *packet, size_t size); -int sss_packet_set_size(struct sss_packet *packet, size_t size); -int sss_packet_recv(struct sss_packet *packet, int fd); -int sss_packet_send(struct sss_packet *packet, int fd); -enum sss_cli_command sss_packet_get_cmd(struct sss_packet *packet); -void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen); -void sss_packet_set_error(struct sss_packet *packet, int error); - -#endif /* __SSSSRV_PACKET_H__ */ diff --git a/server/responder/nss/nsssrv.c b/server/responder/nss/nsssrv.c deleted file mode 100644 index 7de346f0c..000000000 --- a/server/responder/nss/nsssrv.c +++ /dev/null @@ -1,367 +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 "responder/nss/nsssrv.h" -#include "responder/nss/nsssrv_nc.h" -#include "db/sysdb.h" -#include "confdb/confdb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "responder/common/responder_packet.h" -#include "providers/data_provider.h" -#include "monitor/monitor_interfaces.h" -#include "sbus/sbus_client.h" - -#define SSS_NSS_PIPE_NAME "nss" - -#define DEFAULT_PWFIELD "*" - -static int service_reload(DBusMessage *message, struct sbus_connection *conn); - -struct sbus_method monitor_nss_methods[] = { - { MON_CLI_METHOD_PING, monitor_common_pong }, - { MON_CLI_METHOD_RELOAD, service_reload }, - { MON_CLI_METHOD_RES_INIT, monitor_common_res_init }, - { NULL, NULL } -}; - -struct sbus_interface monitor_nss_interface = { - MONITOR_INTERFACE, - MONITOR_PATH, - SBUS_DEFAULT_VTABLE, - monitor_nss_methods, - NULL -}; - -static int service_reload(DBusMessage *message, struct sbus_connection *conn) -{ - /* 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 monitor_common_pong(message, conn); -} - -static int nss_get_config(struct nss_ctx *nctx, - struct resp_ctx *rctx, - struct confdb_ctx *cdb) -{ - TALLOC_CTX *tmpctx; - struct sss_domain_info *dom; - char *domain, *name; - char **filter_list; - int ret, i; - - tmpctx = talloc_new(nctx); - if (!tmpctx) return ENOMEM; - - ret = confdb_get_int(cdb, nctx, CONFDB_NSS_CONF_ENTRY, - CONFDB_NSS_ENUM_CACHE_TIMEOUT, 120, - &nctx->enum_cache_timeout); - if (ret != EOK) goto done; - - ret = confdb_get_int(cdb, nctx, CONFDB_NSS_CONF_ENTRY, - CONFDB_NSS_ENTRY_NEG_TIMEOUT, 15, - &nctx->neg_timeout); - if (ret != EOK) goto done; - - ret = confdb_get_bool(cdb, nctx, CONFDB_NSS_CONF_ENTRY, - CONFDB_NSS_FILTER_USERS_IN_GROUPS, true, - &nctx->filter_users_in_groups); - if (ret != EOK) goto done; - - - ret = confdb_get_int(cdb, nctx, CONFDB_NSS_CONF_ENTRY, - CONFDB_NSS_ENTRY_CACHE_NOWAIT_PERCENTAGE, 0, - &nctx->cache_refresh_percent); - if (ret != EOK) goto done; - if (nctx->cache_refresh_percent < 0 || - nctx->cache_refresh_percent > 99) { - DEBUG(0,("Configuration error: entry_cache_nowait_percentage is" - "invalid. Disabling feature.\n")); - nctx->cache_refresh_percent = 0; - } - - ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, - CONFDB_NSS_FILTER_USERS, &filter_list); - if (ret == ENOENT) { - filter_list = talloc_array(tmpctx, char *, 2); - filter_list[0] = talloc_strdup(tmpctx, "root"); - filter_list[1] = NULL; - if (!filter_list || !filter_list[0]) { - ret = ENOMEM; - goto done; - } - ret = EOK; - } - else if (ret != EOK) goto done; - - for (i = 0; (filter_list && filter_list[i]); i++) { - ret = sss_parse_name(tmpctx, nctx->rctx->names, - filter_list[i], &domain, &name); - if (ret != EOK) { - DEBUG(1, ("Invalid name in filterUsers list: [%s] (%d)\n", - filter_list[i], ret)); - continue; - } - if (domain) { - ret = nss_ncache_set_user(nctx->ncache, true, domain, name); - if (ret != EOK) { - DEBUG(1, ("Failed to store permanent user filter for [%s]" - " (%d [%s])\n", filter_list[i], - ret, strerror(ret))); - continue; - } - } else { - for (dom = rctx->domains; dom; dom = dom->next) { - ret = nss_ncache_set_user(nctx->ncache, true, dom->name, name); - if (ret != EOK) { - DEBUG(1, ("Failed to store permanent user filter for" - " [%s:%s] (%d [%s])\n", - dom->name, filter_list[i], - ret, strerror(ret))); - continue; - } - } - } - } - - ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, - CONFDB_NSS_FILTER_GROUPS, &filter_list); - if (ret == ENOENT) { - filter_list = talloc_array(tmpctx, char *, 2); - filter_list[0] = talloc_strdup(tmpctx, "root"); - filter_list[1] = NULL; - if (!filter_list || !filter_list[0]) { - ret = ENOMEM; - goto done; - } - ret = EOK; - } - else if (ret != EOK) goto done; - - for (i = 0; (filter_list && filter_list[i]); i++) { - ret = sss_parse_name(tmpctx, nctx->rctx->names, - filter_list[i], &domain, &name); - if (ret != EOK) { - DEBUG(1, ("Invalid name in filterGroups list: [%s] (%d)\n", - filter_list[i], ret)); - continue; - } - if (domain) { - ret = nss_ncache_set_group(nctx->ncache, true, domain, name); - if (ret != EOK) { - DEBUG(1, ("Failed to store permanent group filter for" - " [%s] (%d [%s])\n", filter_list[i], - ret, strerror(ret))); - continue; - } - } else { - for (dom = rctx->domains; dom; dom = dom->next) { - ret = nss_ncache_set_group(nctx->ncache, true, dom->name, name); - if (ret != EOK) { - DEBUG(1, ("Failed to store permanent group filter for" - " [%s:%s] (%d [%s])\n", - dom->name, filter_list[i], - ret, strerror(ret))); - continue; - } - } - } - } - - ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY, - CONFDB_NSS_PWFIELD, DEFAULT_PWFIELD, - &nctx->pwfield); - if (ret != EOK) goto done; - - ret = 0; -done: - talloc_free(tmpctx); - return ret; -} - -static struct sbus_method nss_dp_methods[] = { - { NULL, NULL } -}; - -struct sbus_interface nss_dp_interface = { - DP_INTERFACE, - DP_PATH, - SBUS_DEFAULT_VTABLE, - nss_dp_methods, - NULL -}; - - -static void nss_dp_reconnect_init(struct sbus_connection *conn, - int status, void *pvt) -{ - struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn); - int ret; - - /* Did we reconnect successfully? */ - if (status == SBUS_RECONNECT_SUCCESS) { - DEBUG(1, ("Reconnected to the Data Provider.\n")); - - /* Identify ourselves to the data provider */ - ret = dp_common_send_id(be_conn->conn, - DATA_PROVIDER_VERSION, - "NSS", be_conn->domain->name); - /* all fine */ - if (ret == EOK) return; - } - - /* Failed to reconnect */ - DEBUG(0, ("Could not reconnect to %s provider.\n", - be_conn->domain->name)); - - /* FIXME: kill the frontend and let the monitor restart it ? */ - /* nss_shutdown(rctx); */ -} - -int nss_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb) -{ - struct sss_cmd_table *nss_cmds; - struct be_conn *iter; - struct nss_ctx *nctx; - int ret, max_retries; - - nctx = talloc_zero(mem_ctx, struct nss_ctx); - if (!nctx) { - DEBUG(0, ("fatal error initializing nss_ctx\n")); - return ENOMEM; - } - - ret = nss_ncache_init(nctx, &nctx->ncache); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing negative cache\n")); - return ret; - } - - nss_cmds = get_nss_cmds(); - - ret = sss_process_init(nctx, ev, cdb, - nss_cmds, - SSS_NSS_SOCKET_NAME, NULL, - CONFDB_NSS_CONF_ENTRY, - NSS_SBUS_SERVICE_NAME, - NSS_SBUS_SERVICE_VERSION, - &monitor_nss_interface, - "NSS", &nss_dp_interface, - &nctx->rctx); - if (ret != EOK) { - return ret; - } - nctx->rctx->pvt_ctx = nctx; - - ret = nss_get_config(nctx, nctx->rctx, cdb); - if (ret != EOK) { - DEBUG(0, ("fatal error getting nss config\n")); - return ret; - } - - /* Enable automatic reconnection to the Data Provider */ - ret = confdb_get_int(nctx->rctx->cdb, nctx->rctx, - CONFDB_NSS_CONF_ENTRY, - CONFDB_SERVICE_RECON_RETRIES, - 3, &max_retries); - if (ret != EOK) { - DEBUG(0, ("Failed to set up automatic reconnection\n")); - return ret; - } - - for (iter = nctx->rctx->be_conns; iter; iter = iter->next) { - sbus_reconnect_init(iter->conn, max_retries, - nss_dp_reconnect_init, iter); - } - - 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... */ - debug_log_file = "sssd_nss"; - - ret = server_setup("sssd[nss]", 0, CONFDB_NSS_CONF_ENTRY, &main_ctx); - if (ret != EOK) return 2; - - ret = die_if_parent_died(); - if (ret != EOK) { - /* This is not fatal, don't return */ - DEBUG(2, ("Could not set up to exit when parent process does\n")); - } - - 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/responder/nss/nsssrv.h b/server/responder/nss/nsssrv.h deleted file mode 100644 index a6c661835..000000000 --- a/server/responder/nss/nsssrv.h +++ /dev/null @@ -1,70 +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 "config.h" -#include "talloc.h" -#include "tevent.h" -#include "ldb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "responder/common/responder_packet.h" -#include "responder/common/responder.h" -#include "responder/nss/nsssrv_nc.h" - -#define NSS_SBUS_SERVICE_VERSION 0x0001 -#define NSS_SBUS_SERVICE_NAME "nss" - -#define NSS_PACKET_MAX_RECV_SIZE 1024 - -struct getent_ctx; - -struct nss_ctx { - struct resp_ctx *rctx; - - int neg_timeout; - struct nss_nc_ctx *ncache; - - int cache_refresh_percent; - - int enum_cache_timeout; - time_t last_user_enum; - time_t last_group_enum; - - struct getent_ctx *pctx; - struct getent_ctx *gctx; - - bool filter_users_in_groups; - - char *pwfield; -}; - -struct nss_packet; - -int nss_cmd_execute(struct cli_ctx *cctx); - -struct sss_cmd_table *get_nss_cmds(void); - -#endif /* __NSSSRV_H__ */ diff --git a/server/responder/nss/nsssrv_cmd.c b/server/responder/nss/nsssrv_cmd.c deleted file mode 100644 index 46d4a2361..000000000 --- a/server/responder/nss/nsssrv_cmd.c +++ /dev/null @@ -1,3182 +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 "responder/nss/nsssrv.h" -#include "confdb/confdb.h" -#include "db/sysdb.h" -#include <time.h> - -struct nss_cmd_ctx { - struct cli_ctx *cctx; - char *name; - uint32_t id; - - bool immediate; - bool check_next; - bool enum_cached; -}; - -struct dom_ctx { - struct sss_domain_info *domain; - struct ldb_result *res; - int cur; -}; - -struct getent_ctx { - struct dom_ctx *doms; - int num; - int cur; -}; - -struct nss_dom_ctx { - struct nss_cmd_ctx *cmdctx; - struct sss_domain_info *domain; - - bool check_provider; - - /* cache results */ - struct ldb_result *res; -}; - -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 = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - sss_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) - -#define NSS_CMD_FATAL_ERROR_CODE(cctx, ret) do { \ - DEBUG(1,("Fatal error, killing connection!")); \ - talloc_free(cctx); \ - return ret; \ -} while(0) - -static struct sss_domain_info *nss_get_dom(struct sss_domain_info *doms, - const char *domain) -{ - struct sss_domain_info *dom; - - for (dom = doms; dom; dom = dom->next) { - if (strcasecmp(dom->name, domain) == 0) break; - } - if (!dom) DEBUG(2, ("Unknown domain [%s]!\n", domain)); - - return dom; -} - -static int fill_empty(struct sss_packet *packet) -{ - uint8_t *body; - size_t blen; - int ret; - - ret = sss_packet_grow(packet, 2*sizeof(uint32_t)); - if (ret != EOK) return ret; - - sss_packet_get_body(packet, &body, &blen); - ((uint32_t *)body)[0] = 0; /* num results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - - return EOK; -} - -/**************************************************************************** - * PASSWD db related functions - ***************************************************************************/ - -static int fill_pwent(struct sss_packet *packet, - struct sss_domain_info *dom, - struct nss_ctx *nctx, - bool filter_users, - struct ldb_message **msgs, - int count) -{ - struct ldb_message *msg; - uint8_t *body; - const char *name; - const char *gecos; - const char *homedir; - const char *shell; - uint32_t uid; - uint32_t gid; - size_t rsize, rp, blen; - size_t s1, s2, s3, s4, s5; - size_t dom_len = 0; - int delim = 1; - int i, ret, num, t; - bool add_domain = dom->fqnames; - const char *domain = dom->name; - const char *namefmt = nctx->rctx->names->fq_fmt; - bool packet_initialized = false; - int ncret; - - if (add_domain) dom_len = strlen(domain); - - 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_NAME, NULL); - uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0); - gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0); - - if (!name || !uid || !gid) { - DEBUG(1, ("Incomplete user object for %s[%llu]! Skipping\n", - name?name:"<NULL>", (unsigned long long int)uid)); - continue; - } - - if (filter_users) { - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - domain, name); - if (ncret == EEXIST) { - DEBUG(4, ("User [%s@%s] filtered out! (negative cache)\n", - name, domain)); - continue; - } - } - - if (!packet_initialized) { - /* first 2 fields (len and reserved), filled up later */ - ret = sss_packet_grow(packet, 2*sizeof(uint32_t)); - if (ret != EOK) return ret; - packet_initialized = true; - } - - gecos = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL); - homedir = ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL); - shell = ldb_msg_find_attr_as_string(msg, SYSDB_SHELL, NULL); - - if (!gecos) gecos = ""; - if (!homedir) homedir = "/"; - if (!shell) shell = ""; - - s1 = strlen(name) + 1; - s2 = strlen(gecos) + 1; - s3 = strlen(homedir) + 1; - s4 = strlen(shell) + 1; - s5 = strlen(nctx->pwfield) + 1; - if (add_domain) s1 += delim + dom_len; - - rsize = 2*sizeof(uint32_t) +s1 + s2 + s3 + s4 + s5; - - ret = sss_packet_grow(packet, rsize); - if (ret != EOK) { - num = 0; - goto done; - } - sss_packet_get_body(packet, &body, &blen); - - ((uint32_t *)(&body[rp]))[0] = uid; - ((uint32_t *)(&body[rp]))[1] = gid; - rp += 2*sizeof(uint32_t); - - if (add_domain) { - ret = snprintf((char *)&body[rp], s1, namefmt, name, domain); - if (ret >= s1) { - /* need more space, got creative with the print format ? */ - t = ret - s1 + 1; - ret = sss_packet_grow(packet, t); - if (ret != EOK) { - num = 0; - goto done; - } - delim += t; - s1 += t; - sss_packet_get_body(packet, &body, &blen); - - /* retry */ - ret = snprintf((char *)&body[rp], s1, namefmt, name, domain); - } - - if (ret != s1-1) { - DEBUG(1, ("Failed to generate a fully qualified name for user " - "[%s] in [%s]! Skipping user.\n", name, domain)); - continue; - } - } else { - memcpy(&body[rp], name, s1); - } - rp += s1; - - memcpy(&body[rp], nctx->pwfield, s5); - rp += s5; - memcpy(&body[rp], gecos, s2); - rp += s2; - memcpy(&body[rp], homedir, s3); - rp += s3; - memcpy(&body[rp], shell, s4); - rp += s4; - - num++; - } - -done: - /* if there are no results just return ENOENT, - * let the caller decide if this is the last packet or not */ - if (!packet_initialized) return ENOENT; - - sss_packet_get_body(packet, &body, &blen); - ((uint32_t *)body)[0] = num; /* num results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - - return EOK; -} - -static errno_t check_cache(struct nss_dom_ctx *dctx, - struct nss_ctx *nctx, - struct ldb_result *res, - int req_type, - const char *opt_name, - uint32_t opt_id, - sss_dp_callback_t callback) -{ - errno_t ret; - int timeout; - time_t now; - uint64_t lastUpdate; - uint64_t cacheExpire = 0; - uint64_t midpoint_refresh; - struct nss_cmd_ctx *cmdctx = dctx->cmdctx; - struct cli_ctx *cctx = cmdctx->cctx; - bool off_band_update = false; - - /* when searching for a user, more than one reply is a db error */ - if ((req_type == SSS_DP_USER) && (res->count > 1)) { - DEBUG(1, ("getpwXXX call returned more than one result!" - " DB Corrupted?\n")); - ret = nss_cmd_send_error(cmdctx, ENOENT); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR_CODE(cctx, ENOENT); - } - sss_cmd_done(cctx, cmdctx); - return ENOENT; - } - - /* if we have any reply let's check cache validity */ - if (res->count > 0) { - - now = time(NULL); - - lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_LAST_UPDATE, 0); - if (req_type == SSS_DP_INITGROUPS) { - cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_INITGR_EXPIRE, 1); - } - if (cacheExpire == 0) { - cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_CACHE_EXPIRE, 0); - } - - midpoint_refresh = 0; - if(nctx->cache_refresh_percent) { - midpoint_refresh = lastUpdate + - (cacheExpire - lastUpdate)*nctx->cache_refresh_percent/100; - if (midpoint_refresh - lastUpdate < 10) { - /* If the percentage results in an expiration - * less than ten seconds after the lastUpdate time, - * that's too often we will simply set it to 10s - */ - midpoint_refresh = lastUpdate+10; - } - } - - if (cacheExpire > now) { - /* cache still valid */ - - if (midpoint_refresh && midpoint_refresh < now) { - /* We're past the the cache refresh timeout - * We'll return the value from the cache, but we'll also - * queue the cache entry for update out-of-band. - */ - DEBUG(6, ("Performing midpoint cache update on [%s]\n", - opt_name)); - off_band_update = true; - } - else { - - /* Cache is still valid. Just return it. */ - return EOK; - } - } - } - - if (off_band_update) { - - timeout = SSS_CLI_SOCKET_TIMEOUT/2; - - /* No callback required - * This was an out-of-band update. We'll return EOK - * so the calling function can return the cached entry - * immediately. - */ - ret = sss_dp_send_acct_req(cctx->rctx, NULL, NULL, NULL, - timeout, dctx->domain->name, - true, req_type, - opt_name, opt_id); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - } else { - - DEBUG(3, ("Updating cache out-of-band\n")); - } - - } else { - /* This is a cache miss. Or the cache is expired. - * We need to get the updated user information before returning it. - */ - - /* dont loop forever :-) */ - dctx->check_provider = false; - timeout = SSS_CLI_SOCKET_TIMEOUT/2; - - /* keep around current data in case backend is offline */ - if (res->count) { - dctx->res = talloc_steal(dctx, res); - } - - ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, - callback, dctx, timeout, - dctx->domain->name, - true, req_type, - opt_name, opt_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_CODE(cctx, EIO); - } - sss_cmd_done(cctx, cmdctx); - return EIO; - } - - return EAGAIN; - } - - 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; - struct sysdb_ctx *sysdb; - struct sss_domain_info *dom; - struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - bool neghit = false; - int ncret; - int ret; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - if (dctx->check_provider) { - ret = check_cache(dctx, nctx, res, - SSS_DP_USER, cmdctx->name, 0, - nss_cmd_getpwnam_dp_callback); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return; - } - } - - switch (res->count) { - case 0: - if (cmdctx->check_next) { - - ret = EOK; - - /* skip domains that require FQnames or have negative caches */ - for (dom = dctx->domain->next; dom; dom = dom->next) { - - if (dom->fqnames) continue; - - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", - cmdctx->name)); - ret = ENOENT; - } - if (dom == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", - cmdctx->name)); - ret = ENOENT; - } - - if (ret == EOK) { - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - if (dctx->res) talloc_free(res); - dctx->res = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getpwnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getpwnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } - - /* we made another call, end here */ - if (ret == EOK) return; - } - - DEBUG(2, ("No results for getpwnam call\n")); - - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_user(nctx->ncache, false, - dctx->domain->name, cmdctx->name); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - case 1: - DEBUG(6, ("Returning info for user [%s]\n", cmdctx->name)); - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - ret = fill_pwent(cctx->creq->out, - dctx->domain, - nctx, false, - res->msgs, res->count); - if (ret == ENOENT) { - ret = fill_empty(cctx->creq->out); - } - sss_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, ENOENT); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - - sss_cmd_done(cctx, 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; - struct sysdb_ctx *sysdb; - 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)); - - if (!dctx->res) { - /* return 0 results */ - dctx->res = talloc_zero(dctx, struct ldb_result); - if (!dctx->res) { - ret = ENOMEM; - goto done; - } - } - - nss_cmd_getpwnam_callback(dctx, LDB_SUCCESS, dctx->res); - return; - } - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getpwnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getpwnam_callback, dctx); - -done: - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache! (%d [%s])\n", - ret, strerror(ret))); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - } -} - -static int nss_cmd_getpwnam(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - const char *rawname; - char *domname; - uint8_t *body; - size_t blen; - int ret; - int ncret; - bool neghit = false; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - 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) { - ret = ENOMEM; - goto done; - } - dctx->cmdctx = cmdctx; - - /* get user name to query */ - sss_packet_get_body(cctx->creq->in, &body, &blen); - - /* if not terminated fail */ - if (body[blen -1] != '\0') { - ret = EINVAL; - goto done; - } - rawname = (const char *)body; - - domname = NULL; - ret = sss_parse_name(cmdctx, cctx->rctx->names, rawname, - &domname, &cmdctx->name); - if (ret != EOK) { - DEBUG(2, ("Invalid name received [%s]\n", rawname)); - ret = ENOENT; - goto done; - } - - DEBUG(4, ("Requesting info for [%s] from [%s]\n", - cmdctx->name, domname?domname:"<ALL>")); - - if (domname) { - dctx->domain = nss_get_dom(cctx->rctx->domains, domname); - if (!dctx->domain) { - ret = ENOENT; - goto done; - } - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - dctx->domain->name, cmdctx->name); - if (ncret == EEXIST) { - neghit = true; - } - } - else { - /* skip domains that require FQnames or have negative caches */ - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - - if (dom->fqnames) continue; - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - dctx->domain = dom; - } - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", rawname)); - ret = ENOENT; - goto done; - } - if (dctx->domain == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", rawname)); - ret = ENOENT; - goto done; - } - - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - - if (!domname) { - /* this is a multidomain search */ - cmdctx->check_next = true; - } - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_getpwnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getpwnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - -done: - if (ret != EOK) { - if (ret == ENOENT) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, 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; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - bool neghit = false; - int ret; - int ncret; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - if (dctx->check_provider) { - ret = check_cache(dctx, nctx, res, - SSS_DP_USER, NULL, cmdctx->id, - nss_cmd_getpwuid_dp_callback); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return; - } - } - - switch (res->count) { - case 0: - if (cmdctx->check_next) { - - ret = EOK; - - dom = dctx->domain->next; - ncret = nss_ncache_check_uid(nctx->ncache, nctx->neg_timeout, - cmdctx->id); - if (ncret == EEXIST) { - DEBUG(3, ("Uid [%lu] does not exist! (negative cache)\n", - (unsigned long)cmdctx->id)); - ret = ENOENT; - } - if (dom == NULL) { - DEBUG(0, ("No matching domain found for [%lu], fail!\n", - (unsigned long)cmdctx->id)); - ret = ENOENT; - } - - if (ret == EOK) { - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - if (dctx->res) talloc_free(res); - dctx->res = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getpwuid(cmdctx, sysdb, - dctx->domain, cmdctx->id, - nss_cmd_getpwuid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } - - /* we made another call, end here */ - if (ret == EOK) return; - } - - DEBUG(2, ("No results for getpwuid call\n")); - - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_uid(nctx->ncache, false, cmdctx->id); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - case 1: - DEBUG(6, ("Returning info for user [%u]\n", (unsigned)cmdctx->id)); - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - - ret = fill_pwent(cctx->creq->out, - dctx->domain, - nctx, true, - res->msgs, res->count); - if (ret == ENOENT) { - ret = fill_empty(cctx->creq->out); - } - sss_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, ENOENT); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - - sss_cmd_done(cctx, 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; - struct sysdb_ctx *sysdb; - 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)); - - if (!dctx->res) { - /* return 0 results */ - dctx->res = talloc_zero(dctx, struct ldb_result); - if (!dctx->res) { - ret = ENOMEM; - goto done; - } - } - - nss_cmd_getpwuid_callback(dctx, LDB_SUCCESS, dctx->res); - return; - } - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getpwuid(cmdctx, sysdb, - dctx->domain, cmdctx->id, - nss_cmd_getpwuid_callback, dctx); - -done: - 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); - } - sss_cmd_done(cctx, cmdctx); - } -} - -static int nss_cmd_getpwuid(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - int ret; - int ncret; - - ret = ENOENT; - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - 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) { - ret = ENOMEM; - goto done; - } - dctx->cmdctx = cmdctx; - - /* get uid to query */ - sss_packet_get_body(cctx->creq->in, &body, &blen); - - if (blen != sizeof(uint32_t)) { - ret = EINVAL; - goto done; - } - cmdctx->id = *((uint32_t *)body); - - /* this is a multidomain search */ - cmdctx->check_next = true; - - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_uid(nctx->ncache, nctx->neg_timeout, - cmdctx->id); - if (ncret == EEXIST) { - DEBUG(3, ("Uid [%lu] does not exist! (negative cache)\n", - (unsigned long)cmdctx->id)); - continue; - } - - /* check that the uid is valid for this domain */ - if ((dom->id_min && (cmdctx->id < dom->id_min)) || - (dom->id_max && (cmdctx->id > dom->id_max))) { - DEBUG(4, ("Uid [%lu] does not exist in domain [%s]! " - "(id out of range)\n", - (unsigned long)cmdctx->id, dom->name)); - continue; - } - - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - - DEBUG(4, ("Requesting info for [%lu@%s]\n", - cmdctx->id, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_getpwuid(cmdctx, sysdb, - dctx->domain, cmdctx->id, - nss_cmd_getpwuid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - - break; - } - -done: - if (ret != EOK) { - if (ret == ENOENT) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, 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 int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx); - -static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static void nss_cmd_setpwent_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; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct getent_ctx *pctx; - struct nss_ctx *nctx; - int timeout; - int ret; - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, ENOENT); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - pctx = nctx->pctx; - if (pctx == NULL) { - pctx = talloc_zero(nctx, struct getent_ctx); - if (!pctx) { - ret = nss_cmd_send_error(cmdctx, ENOMEM); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - nctx->pctx = pctx; - } - - pctx->doms = talloc_realloc(pctx, pctx->doms, struct dom_ctx, pctx->num +1); - if (!pctx->doms) { - talloc_free(pctx); - nctx->pctx = NULL; - NSS_CMD_FATAL_ERROR(cctx); - } - - pctx->doms[pctx->num].domain = dctx->domain; - pctx->doms[pctx->num].res = talloc_steal(pctx->doms, res); - pctx->doms[pctx->num].cur = 0; - - pctx->num++; - - /* do not reply until all domain searches are done */ - for (dom = dctx->domain->next; dom; dom = dom->next) { - if (dom->enumerate != 0) break; - } - dctx->domain = dom; - - if (dctx->domain != NULL) { - if (cmdctx->enum_cached) { - dctx->check_provider = false; - } else { - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - } - - if (dctx->check_provider) { - timeout = SSS_CLI_SOCKET_TIMEOUT; - ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, - nss_cmd_setpw_dp_callback, dctx, - timeout, dom->name, true, - SSS_DP_USER, NULL, 0); - } else { - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_enumpwent(dctx, sysdb, - dctx->domain, NULL, - nss_cmd_setpwent_callback, dctx); - } - if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", - dom->name)); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - } - return; - } - - /* set cache mark */ - nctx->last_user_enum = time(NULL); - - if (cmdctx->immediate) { - /* this was a getpwent call w/o setpwent, - * return immediately one result */ - ret = nss_cmd_getpwent_immediate(cmdctx); - if (ret != EOK) NSS_CMD_FATAL_ERROR(cctx); - return; - } - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, 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; - struct sysdb_ctx *sysdb; - 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_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_enumpwent(cmdctx, sysdb, - dctx->domain, NULL, - nss_cmd_setpwent_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); - } - sss_cmd_done(cctx, cmdctx); - } -} - -static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate) -{ - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct nss_ctx *nctx; - time_t now = time(NULL); - int timeout; - uint8_t *body; - size_t blen; - int ret; - - DEBUG(4, ("Requesting info for all users\n")); - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - talloc_free(nctx->pctx); - nctx->pctx = NULL; - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - cmdctx->immediate = immediate; - - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) { - ret = ENOMEM; - goto done; - } - dctx->cmdctx = cmdctx; - - /* do not query backends if we have a recent enumeration */ - if (nctx->enum_cache_timeout) { - if (nctx->last_user_enum + - nctx->enum_cache_timeout > now) { - cmdctx->enum_cached = true; - } - } - - /* check if enumeration is enabled in any domain */ - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - if (dom->enumerate != 0) break; - } - dctx->domain = dom; - - if (dctx->domain == NULL) { - DEBUG(2, ("Enumeration disabled on all domains!\n")); - ret = ENOENT; - goto done; - } - - if (cmdctx->enum_cached) { - dctx->check_provider = false; - } else { - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - } - - if (dctx->check_provider) { - timeout = SSS_CLI_SOCKET_TIMEOUT; - ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, - nss_cmd_setpw_dp_callback, dctx, - timeout, dom->name, true, - SSS_DP_USER, NULL, 0); - } else { - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_enumpwent(dctx, sysdb, - dctx->domain, NULL, - nss_cmd_setpwent_callback, dctx); - } - if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", - dom->name)); - } - -done: - if (ret != EOK) { - if (ret == ENOENT) { - if (cmdctx->immediate) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - else { - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, cmdctx); - } - return ret; - } - - return EOK; -} - -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 nss_ctx *nctx; - struct getent_ctx *pctx; - struct ldb_message **msgs = NULL; - struct dom_ctx *pdom = NULL; - int n = 0; - int ret; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - pctx = nctx->pctx; - -retry: - if (pctx->cur >= pctx->num) goto none; - - pdom = &pctx->doms[pctx->cur]; - - n = pdom->res->count - pdom->cur; - if (n == 0 && (pctx->cur+1 < pctx->num)) { - pctx->cur++; - pdom = &pctx->doms[pctx->cur]; - n = pdom->res->count - pdom->cur; - } - - if (!n) goto none; - - if (n > num) n = num; - - msgs = &(pdom->res->msgs[pdom->cur]); - pdom->cur += n; - - ret = fill_pwent(cctx->creq->out, pdom->domain, nctx, true, msgs, n); - if (ret == ENOENT) goto retry; - return ret; - -none: - return fill_empty(cctx->creq->out); -} - -/* used only if a process calls getpwent() without first calling setpwent() - */ -static int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx) -{ - struct cli_ctx *cctx = cmdctx->cctx; - uint8_t *body; - size_t blen; - uint32_t num; - int ret; - - /* get max num of entries to return in one call */ - sss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen != sizeof(uint32_t)) { - return EINVAL; - } - num = *((uint32_t *)body); - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - ret = nss_cmd_retpwent(cctx, num); - - sss_packet_set_error(cctx->creq->out, ret); - sss_cmd_done(cctx, cmdctx); - - return EOK; -} - -static int nss_cmd_getpwent(struct cli_ctx *cctx) -{ - struct nss_ctx *nctx; - struct nss_cmd_ctx *cmdctx; - - DEBUG(4, ("Requesting info for all accounts\n")); - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - /* see if we need to trigger an implicit setpwent() */ - if (nctx->pctx == NULL) { - nctx->pctx = talloc_zero(nctx, struct getent_ctx); - if (!nctx->pctx) return ENOMEM; - - return nss_cmd_setpwent_ext(cctx, true); - } - - cmdctx = talloc(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - return nss_cmd_getpwent_immediate(cmdctx); -} - -static int nss_cmd_endpwent(struct cli_ctx *cctx) -{ - struct nss_ctx *nctx; - int ret; - - DEBUG(4, ("Terminating request info for all accounts\n")); - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - - if (nctx->pctx == NULL) goto done; - - /* free results and reset */ - talloc_free(nctx->pctx); - nctx->pctx = NULL; - -done: - sss_cmd_done(cctx, NULL); - return EOK; -} - -/**************************************************************************** - * GROUP db related functions - ***************************************************************************/ - -#define GID_ROFFSET 0 -#define MNUM_ROFFSET sizeof(uint32_t) -#define STRS_ROFFSET 2*sizeof(uint32_t) - -static int fill_grent(struct sss_packet *packet, - struct sss_domain_info *dom, - struct nss_ctx *nctx, - bool filter_groups, - struct ldb_message **msgs, - int max, int *count) -{ - struct ldb_message *msg; - struct ldb_message_element *el; - uint8_t *body; - size_t blen; - uint32_t gid; - const char *name; - size_t nsize; - size_t delim; - size_t dom_len; - size_t pwlen; - int i = 0; - int j = 0; - int ret, num, memnum; - size_t rzero, rsize; - bool add_domain = dom->fqnames; - const char *domain = dom->name; - const char *namefmt = nctx->rctx->names->fq_fmt; - - if (add_domain) { - delim = 1; - dom_len = strlen(domain); - } else { - delim = 0; - dom_len = 0; - } - - num = 0; - pwlen = strlen(nctx->pwfield) + 1; - - /* first 2 fields (len and reserved), filled up later */ - ret = sss_packet_grow(packet, 2*sizeof(uint32_t)); - if (ret != EOK) { - goto done; - } - sss_packet_get_body(packet, &body, &blen); - rzero = 2*sizeof(uint32_t); - rsize = 0; - - for (i = 0; i < *count; i++) { - msg = msgs[i]; - - /* new group */ - if (!ldb_msg_check_string_attribute(msg, "objectClass", - SYSDB_GROUP_CLASS)) { - DEBUG(1, ("Wrong object (%s) found on stack!\n", - ldb_dn_get_linearized(msg->dn))); - continue; - } - - /* if we reached the max allowed entries, simply return */ - if (num >= max) { - goto done; - } - - /* new result starts at end of previous result */ - rzero += rsize; - rsize = 0; - - /* find group name/gid */ - name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); - gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0); - if (!name || !gid) { - DEBUG(1, ("Incomplete group object for %s[%llu]! Skipping\n", - name?name:"<NULL>", (unsigned long long int)gid)); - continue; - } - - if (filter_groups) { - ret = nss_ncache_check_group(nctx->ncache, - nctx->neg_timeout, domain, name); - if (ret == EEXIST) { - DEBUG(4, ("Group [%s@%s] filtered out! (negative cache)\n", - name, domain)); - continue; - } - } - - nsize = strlen(name) + 1; /* includes terminating \0 */ - if (add_domain) nsize += delim + dom_len; - - /* fill in gid and name and set pointer for number of members */ - rsize = STRS_ROFFSET + nsize + pwlen; /* name\0x\0 */ - - ret = sss_packet_grow(packet, rsize); - if (ret != EOK) { - num = 0; - goto done; - } - sss_packet_get_body(packet, &body, &blen); - - /* 0-3: 32bit number gid */ - ((uint32_t *)(&body[rzero+GID_ROFFSET]))[0] = gid; - - /* 4-7: 32bit unsigned number of members */ - ((uint32_t *)(&body[rzero+MNUM_ROFFSET]))[0] = 0; - - /* 8-X: sequence of strings (name, passwd, mem..) */ - if (add_domain) { - ret = snprintf((char *)&body[rzero+STRS_ROFFSET], - nsize, namefmt, name, domain); - if (ret >= nsize) { - /* need more space, got creative with the print format ? */ - int t = ret - nsize + 1; - ret = sss_packet_grow(packet, t); - if (ret != EOK) { - num = 0; - goto done; - } - sss_packet_get_body(packet, &body, &blen); - rsize += t; - delim += t; - nsize += t; - - /* retry */ - ret = snprintf((char *)&body[rzero+STRS_ROFFSET], - nsize, namefmt, name, domain); - } - - if (ret != nsize-1) { - DEBUG(1, ("Failed to generate a fully qualified name for" - " group [%s] in [%s]! Skipping\n", name, domain)); - /* reclaim space */ - ret = sss_packet_shrink(packet, rsize); - if (ret != EOK) { - num = 0; - goto done; - } - rsize = 0; - continue; - } - } else { - memcpy(&body[rzero+STRS_ROFFSET], name, nsize); - } - - /* group passwd field */ - memcpy(&body[rzero + rsize -pwlen], nctx->pwfield, pwlen); - - el = ldb_msg_find_element(msg, SYSDB_MEMBERUID); - if (el) { - memnum = 0; - - for (j = 0; j < el->num_values; j++) { - name = (const char *)el->values[j].data; - - if (nctx->filter_users_in_groups) { - ret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - domain, name); - if (ret == EEXIST) { - DEBUG(6, ("Group [%s] member [%s@%s] filtered out!" - " (negative cache)\n", - (char *)&body[rzero+STRS_ROFFSET], - name, domain)); - continue; - } - } - - nsize = strlen(name) + 1; /* includes terminating \0 */ - if (add_domain) nsize += delim + dom_len; - - ret = sss_packet_grow(packet, nsize); - if (ret != EOK) { - num = 0; - goto done; - } - sss_packet_get_body(packet, &body, &blen); - - if (add_domain) { - ret = snprintf((char *)&body[rzero + rsize], - nsize, namefmt, name, domain); - if (ret >= nsize) { - /* need more space, - * got creative with the print format ? */ - int t = ret - nsize + 1; - ret = sss_packet_grow(packet, t); - if (ret != EOK) { - num = 0; - goto done; - } - sss_packet_get_body(packet, &body, &blen); - delim += t; - nsize += t; - - /* retry */ - ret = snprintf((char *)&body[rzero + rsize], - nsize, namefmt, name, domain); - } - - if (ret != nsize-1) { - DEBUG(1, ("Failed to generate a fully qualified name" - " for member [%s@%s] of group [%s]!" - " Skipping\n", name, domain, - (char *)&body[rzero+STRS_ROFFSET])); - /* reclaim space */ - ret = sss_packet_shrink(packet, nsize); - if (ret != EOK) { - num = 0; - goto done; - } - continue; - } - - } else { - memcpy(&body[rzero + rsize], name, nsize); - } - - rsize += nsize; - - memnum++; - } - - if (memnum) { - /* set num of members */ - ((uint32_t *)(&body[rzero+MNUM_ROFFSET]))[0] = memnum; - } - } - - num++; - continue; - } - -done: - *count = i; - - if (num == 0) { - /* if num is 0 most probably something went wrong, - * reset packet and return ENOENT */ - ret = sss_packet_set_size(packet, 0); - if (ret != EOK) return ret; - return ENOENT; - } - - ((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; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - bool neghit = false; - int ncret; - int i, ret; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - if (dctx->check_provider) { - ret = check_cache(dctx, nctx, res, - SSS_DP_GROUP, cmdctx->name, 0, - nss_cmd_getgrnam_dp_callback); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return; - } - } - - switch (res->count) { - case 0: - if (cmdctx->check_next) { - - ret = EOK; - - /* skip domains that require FQnames or have negative caches */ - for (dom = dctx->domain->next; dom; dom = dom->next) { - - if (dom->fqnames) continue; - - ncret = nss_ncache_check_group(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - if (neghit) { - DEBUG(2, ("Group [%s] does not exist! (negative cache)\n", - cmdctx->name)); - ret = ENOENT; - } - if (dom == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", - cmdctx->name)); - ret = ENOENT; - } - - if (ret == EOK) { - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - if (dctx->res) talloc_free(res); - dctx->res = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getgrnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getgrnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } - - /* we made another call, end here */ - if (ret == EOK) return; - } - - - DEBUG(2, ("No results for getgrnam call\n")); - - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_group(nctx->ncache, false, - dctx->domain->name, cmdctx->name); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_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 = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - i = res->count; - ret = fill_grent(cctx->creq->out, - dctx->domain, - nctx, false, - res->msgs, 1, &i); - if (ret == ENOENT) { - ret = fill_empty(cctx->creq->out); - } - sss_packet_set_error(cctx->creq->out, ret); - } - - sss_cmd_done(cctx, 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; - struct sysdb_ctx *sysdb; - 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)); - - if (!dctx->res) { - /* return 0 results */ - dctx->res = talloc_zero(dctx, struct ldb_result); - if (!dctx->res) { - ret = ENOMEM; - goto done; - } - } - - nss_cmd_getgrnam_callback(dctx, LDB_SUCCESS, dctx->res); - return; - } - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getgrnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getgrnam_callback, dctx); - -done: - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache! (%d [%s])\n", - ret, strerror(ret))); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - } -} - -static int nss_cmd_getgrnam(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - const char *rawname; - char *domname; - uint8_t *body; - size_t blen; - int ret; - int ncret; - bool neghit = false; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - 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) { - ret = ENOMEM; - goto done; - } - dctx->cmdctx = cmdctx; - - /* get user name to query */ - sss_packet_get_body(cctx->creq->in, &body, &blen); - - /* if not terminated fail */ - if (body[blen -1] != '\0') { - ret = EINVAL; - goto done; - } - rawname = (const char *)body; - - domname = NULL; - ret = sss_parse_name(cmdctx, cctx->rctx->names, rawname, - &domname, &cmdctx->name); - if (ret != EOK) { - DEBUG(2, ("Invalid name received [%s]\n", rawname)); - ret = ENOENT; - goto done; - } - - DEBUG(4, ("Requesting info for [%s] from [%s]\n", - cmdctx->name, domname?domname:"<ALL>")); - - if (domname) { - dctx->domain = nss_get_dom(cctx->rctx->domains, domname); - if (!dctx->domain) { - ret = ENOENT; - goto done; - } - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_group(nctx->ncache, nctx->neg_timeout, - dctx->domain->name, cmdctx->name); - if (ncret == EEXIST) { - neghit = true; - } - } - else { - /* skip domains that require FQnames or have negative caches */ - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - - if (dom->fqnames) continue; - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_group(nctx->ncache, nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - dctx->domain = dom; - } - if (neghit) { - DEBUG(2, ("Group [%s] does not exist! (negative cache)\n", rawname)); - ret = ENOENT; - goto done; - } - if (dctx->domain == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", rawname)); - ret = ENOENT; - goto done; - } - - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - - if (!domname) { - /* this is a multidomain search */ - cmdctx->check_next = true; - } - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_getgrnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getgrnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - -done: - if (ret != EOK) { - if (ret == ENOENT) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, 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; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - bool neghit = false; - int i, ret; - int ncret; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - if (dctx->check_provider) { - ret = check_cache(dctx, nctx, res, - SSS_DP_GROUP, NULL, cmdctx->id, - nss_cmd_getgrgid_dp_callback); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return; - } - } - - switch (res->count) { - case 0: - if (cmdctx->check_next) { - - ret = EOK; - - dom = dctx->domain->next; - - ncret = nss_ncache_check_gid(nctx->ncache, nctx->neg_timeout, - cmdctx->id); - if (ncret == EEXIST) { - DEBUG(3, ("Gid [%lu] does not exist! (negative cache)\n", - (unsigned long)cmdctx->id)); - ret = ENOENT; - } - if (dom == NULL) { - DEBUG(0, ("No matching domain found for [%lu], fail!\n", - (unsigned long)cmdctx->id)); - ret = ENOENT; - } - - if (ret == EOK) { - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - if (dctx->res) talloc_free(res); - dctx->res = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getgrgid(cmdctx, sysdb, - dctx->domain, cmdctx->id, - nss_cmd_getgrgid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } - - /* we made another call, end here */ - if (ret == EOK) return; - } - - DEBUG(2, ("No results for getgrgid call\n")); - - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_gid(nctx->ncache, false, cmdctx->id); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_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 = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - i = res->count; - ret = fill_grent(cctx->creq->out, - dctx->domain, - nctx, true, - res->msgs, 1, &i); - if (ret == ENOENT) { - ret = fill_empty(cctx->creq->out); - } - sss_packet_set_error(cctx->creq->out, ret); - } - - sss_cmd_done(cctx, 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; - struct sysdb_ctx *sysdb; - 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)); - - if (!dctx->res) { - /* return 0 results */ - dctx->res = talloc_zero(dctx, struct ldb_result); - if (!dctx->res) { - ret = ENOMEM; - goto done; - } - } - - nss_cmd_getgrgid_callback(dctx, LDB_SUCCESS, dctx->res); - return; - } - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_getgrgid(cmdctx, sysdb, - dctx->domain, cmdctx->id, - nss_cmd_getgrgid_callback, dctx); - -done: - 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); - } - sss_cmd_done(cctx, cmdctx); - } -} - -static int nss_cmd_getgrgid(struct cli_ctx *cctx) -{ - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - int ret; - int ncret; - - ret = ENOENT; - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - 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) { - ret = ENOMEM; - goto done; - } - dctx->cmdctx = cmdctx; - - /* get uid to query */ - sss_packet_get_body(cctx->creq->in, &body, &blen); - - if (blen != sizeof(uint32_t)) { - ret = EINVAL; - goto done; - } - cmdctx->id = *((uint32_t *)body); - - /* this is a multidomain search */ - cmdctx->check_next = true; - - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_gid(nctx->ncache, nctx->neg_timeout, - cmdctx->id); - if (ncret == EEXIST) { - DEBUG(3, ("Gid [%lu] does not exist! (negative cache)\n", - (unsigned long)cmdctx->id)); - continue; - } - - /* check that the uid is valid for this domain */ - if ((dom->id_min && (cmdctx->id < dom->id_min)) || - (dom->id_max && (cmdctx->id > dom->id_max))) { - DEBUG(4, ("Gid [%lu] does not exist in domain [%s]! " - "(id out of range)\n", - (unsigned long)cmdctx->id, dom->name)); - continue; - } - - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - - DEBUG(4, ("Requesting info for [%lu@%s]\n", - cmdctx->id, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_getgrgid(cmdctx, sysdb, - dctx->domain, cmdctx->id, - nss_cmd_getgrgid_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - - break; - } - -done: - if (ret != EOK) { - if (ret == ENOENT) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, 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 int nss_cmd_getgrent_immediate(struct nss_cmd_ctx *cmdctx); - -static void nss_cmd_setgr_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static void nss_cmd_setgrent_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; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct getent_ctx *gctx; - struct nss_ctx *nctx; - int timeout; - int ret; - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, ENOENT); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - gctx = nctx->gctx; - if (gctx == NULL) { - gctx = talloc_zero(nctx, struct getent_ctx); - if (!gctx) { - ret = nss_cmd_send_error(cmdctx, ENOMEM); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - nctx->gctx = gctx; - } - - gctx->doms = talloc_realloc(gctx, gctx->doms, struct dom_ctx, gctx->num +1); - if (!gctx->doms) NSS_CMD_FATAL_ERROR(cctx); - - gctx->doms[gctx->num].domain = dctx->domain; - gctx->doms[gctx->num].res = talloc_steal(gctx->doms, res); - gctx->doms[gctx->num].cur = 0; - - gctx->num++; - - /* do not reply until all domain searches are done */ - for (dom = dctx->domain->next; dom; dom = dom->next) { - if (dom->enumerate != 0) break; - } - dctx->domain = dom; - - if (dctx->domain != NULL) { - if (cmdctx->enum_cached) { - dctx->check_provider = false; - } else { - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - } - - if (dctx->check_provider) { - timeout = SSS_CLI_SOCKET_TIMEOUT; - ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, - nss_cmd_setgr_dp_callback, dctx, - timeout, dom->name, true, - SSS_DP_GROUP, NULL, 0); - } else { - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_enumgrent(dctx, sysdb, - dctx->domain, - nss_cmd_setgrent_callback, dctx); - } - if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", - dom->name)); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - } - return; - } - - /* set cache mark */ - nctx->last_group_enum = time(NULL); - - if (cmdctx->immediate) { - /* this was a getgrent call w/o setgrent, - * return immediately one result */ - ret = nss_cmd_getgrent_immediate(cmdctx); - if (ret != EOK) NSS_CMD_FATAL_ERROR(cctx); - return; - } - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, 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; - struct sysdb_ctx *sysdb; - 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_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_enumgrent(dctx, sysdb, - dctx->domain, - nss_cmd_setgrent_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); - } - sss_cmd_done(cctx, cmdctx); - } -} - -static int nss_cmd_setgrent_ext(struct cli_ctx *cctx, bool immediate) -{ - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_cmd_ctx *cmdctx; - struct nss_dom_ctx *dctx; - struct nss_ctx *nctx; - time_t now = time(NULL); - int timeout; - uint8_t *body; - size_t blen; - int ret; - - DEBUG(4, ("Requesting info for all groups\n")); - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - talloc_free(nctx->gctx); - nctx->gctx = NULL; - - cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - cmdctx->immediate = immediate; - - dctx = talloc_zero(cmdctx, struct nss_dom_ctx); - if (!dctx) { - ret = ENOMEM; - goto done; - } - dctx->cmdctx = cmdctx; - - /* do not query backends if we have a recent enumeration */ - if (nctx->enum_cache_timeout) { - if (nctx->last_group_enum + - nctx->enum_cache_timeout > now) { - cmdctx->enum_cached = true; - } - } - - /* check if enumeration is enabled in any domain */ - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - if (dom->enumerate != 0) break; - } - dctx->domain = dom; - - if (dctx->domain == NULL) { - DEBUG(2, ("Enumeration disabled on all domains!\n")); - ret = ENOENT; - goto done; - } - - if (cmdctx->enum_cached) { - dctx->check_provider = false; - } else { - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - } - - if (dctx->check_provider) { - timeout = SSS_CLI_SOCKET_TIMEOUT; - ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, - nss_cmd_setgr_dp_callback, dctx, - timeout, dom->name, true, - SSS_DP_GROUP, NULL, 0); - } else { - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_enumgrent(dctx, sysdb, - dctx->domain, - nss_cmd_setgrent_callback, dctx); - } - if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", - dom->name)); - } - -done: - if (ret != EOK) { - if (ret == ENOENT) { - if (cmdctx->immediate) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - else { - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, cmdctx); - } - return ret; - } - - return EOK; -} - -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 nss_ctx *nctx; - struct getent_ctx *gctx; - struct ldb_message **msgs = NULL; - struct dom_ctx *gdom = NULL; - int n = 0; - int ret; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - gctx = nctx->gctx; - - do { - if (gctx->cur >= gctx->num) goto none; - - gdom = &gctx->doms[gctx->cur]; - - n = gdom->res->count - gdom->cur; - if (n == 0 && (gctx->cur+1 < gctx->num)) { - gctx->cur++; - gdom = &gctx->doms[gctx->cur]; - n = gdom->res->count - gdom->cur; - } - - if (!n) goto none; - - msgs = &(gdom->res->msgs[gdom->cur]); - - ret = fill_grent(cctx->creq->out, gdom->domain, nctx, true, msgs, num, &n); - - gdom->cur += n; - - } while(ret == ENOENT); - - return ret; - -none: - return fill_empty(cctx->creq->out); -} - -/* used only if a process calls getpwent() without first calling setpwent() - */ -static int nss_cmd_getgrent_immediate(struct nss_cmd_ctx *cmdctx) -{ - struct cli_ctx *cctx = cmdctx->cctx; - uint8_t *body; - size_t blen; - uint32_t num; - int ret; - - /* get max num of entries to return in one call */ - sss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen != sizeof(uint32_t)) { - return EINVAL; - } - num = *((uint32_t *)body); - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - return ret; - } - - ret = nss_cmd_retgrent(cctx, num); - - sss_packet_set_error(cctx->creq->out, ret); - sss_cmd_done(cctx, cmdctx); - - return EOK; -} - -static int nss_cmd_getgrent(struct cli_ctx *cctx) -{ - struct nss_ctx *nctx; - struct nss_cmd_ctx *cmdctx; - - DEBUG(4, ("Requesting info for all groups\n")); - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - /* see if we need to trigger an implicit setpwent() */ - if (nctx->gctx == NULL) { - nctx->gctx = talloc_zero(nctx, struct getent_ctx); - if (!nctx->gctx) return ENOMEM; - - return nss_cmd_setgrent_ext(cctx, true); - } - - cmdctx = talloc(cctx, struct nss_cmd_ctx); - if (!cmdctx) { - return ENOMEM; - } - cmdctx->cctx = cctx; - - return nss_cmd_getgrent_immediate(cmdctx); -} - -static int nss_cmd_endgrent(struct cli_ctx *cctx) -{ - struct nss_ctx *nctx; - int ret; - - DEBUG(4, ("Terminating request info for all groups\n")); - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - - if (nctx->gctx == NULL) goto done; - - /* free results and reset */ - talloc_free(nctx->gctx); - nctx->gctx = NULL; - -done: - sss_cmd_done(cctx, NULL); - return EOK; -} - -static int fill_initgr(struct sss_packet *packet, struct ldb_result *res) -{ - uint8_t *body; - size_t blen; - gid_t gid; - int ret, i, num; - - if (res->count == 0) { - return ENOENT; - } - - /* one less, the first one is the user entry */ - num = res->count -1; - - ret = sss_packet_grow(packet, (2 + res->count) * sizeof(uint32_t)); - if (ret != EOK) { - return ret; - } - sss_packet_get_body(packet, &body, &blen); - - /* skip first entry, it's the user entry */ - for (i = 0; i < num; i++) { - gid = ldb_msg_find_attr_as_uint64(res->msgs[i + 1], SYSDB_GIDNUM, 0); - if (!gid) { - DEBUG(1, ("Incomplete group object for initgroups! Aborting\n")); - return EFAULT; - } - ((uint32_t *)body)[2 + i] = gid; - } - - ((uint32_t *)body)[0] = num; /* num results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - - return EOK; -} - -static void nss_cmd_getinitgr_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static void nss_cmd_getinitgr_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; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - bool neghit = false; - int ncret; - int ret; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - if (dctx->check_provider) { - ret = check_cache(dctx, nctx, res, - SSS_DP_INITGROUPS, cmdctx->name, 0, - nss_cmd_getinitgr_dp_callback); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return; - } - } - - switch (res->count) { - case 0: - if (cmdctx->check_next) { - - ret = EOK; - - /* skip domains that require FQnames or have negative caches */ - for (dom = dctx->domain->next; dom; dom = dom->next) { - - if (dom->fqnames) continue; - - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", - cmdctx->name)); - ret = ENOENT; - } - if (dom == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", - cmdctx->name)); - ret = ENOENT; - } - - if (ret == EOK) { - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - if (dctx->res) talloc_free(res); - dctx->res = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_initgroups(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getinitgr_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } - - /* we made another call, end here */ - if (ret == EOK) return; - } - - DEBUG(2, ("No results for initgroups call\n")); - - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_user(nctx->ncache, false, - dctx->domain->name, cmdctx->name); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } - - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_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 initgr for user [%s]\n", cmdctx->name)); - - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - ret = fill_initgr(cctx->creq->out, res); - if (ret == ENOENT) { - ret = fill_empty(cctx->creq->out); - } - sss_packet_set_error(cctx->creq->out, ret); - } - - sss_cmd_done(cctx, cmdctx); -} - -static void nss_cmd_getinitgr_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; - struct sysdb_ctx *sysdb; - 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)); - - if (!dctx->res) { - /* return 0 results */ - dctx->res = talloc_zero(dctx, struct ldb_result); - if (!dctx->res) { - ret = ENOMEM; - goto done; - } - } - - nss_cmd_getinitgr_callback(dctx, LDB_SUCCESS, dctx->res); - return; - } - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_initgroups(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getinitgr_callback, dctx); - -done: - 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); - } - sss_cmd_done(cctx, 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; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; - const char *rawname; - char *domname; - uint8_t *body; - size_t blen; - int ret; - int ncret; - bool neghit = false; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - - 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) { - ret = ENOMEM; - goto done; - } - dctx->cmdctx = cmdctx; - - /* get user name to query */ - sss_packet_get_body(cctx->creq->in, &body, &blen); - - /* if not terminated fail */ - if (body[blen -1] != '\0') { - ret = EINVAL; - goto done; - } - rawname = (const char *)body; - - domname = NULL; - ret = sss_parse_name(cmdctx, cctx->rctx->names, rawname, - &domname, &cmdctx->name); - if (ret != EOK) { - DEBUG(2, ("Invalid name received [%s]\n", rawname)); - ret = ENOENT; - goto done; - } - - DEBUG(4, ("Requesting info for [%s] from [%s]\n", - cmdctx->name, domname ? : "<ALL>")); - - if (domname) { - dctx->domain = nss_get_dom(cctx->rctx->domains, domname); - if (!dctx->domain) { - ret = ENOENT; - goto done; - } - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - domname, cmdctx->name); - if (ncret == EEXIST) { - neghit = true; - } - } - else { - /* skip domains that require FQnames or have negative caches */ - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - - if (dom->fqnames) continue; - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - dctx->domain = dom; - } - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", rawname)); - ret = ENOENT; - goto done; - } - if (dctx->domain == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", rawname)); - ret = ENOENT; - goto done; - } - - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - - if (!domname) { - /* this is a multidomain search */ - cmdctx->check_next = true; - } - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_initgroups(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getinitgr_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - -done: - if (ret != EOK) { - if (ret == ENOENT) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, cmdctx); - } - return ret; - } - - return EOK; -} - -struct cli_protocol_version *register_cli_protocol_version(void) -{ - static struct cli_protocol_version nss_cli_protocol_version[] = { - {1, "2008-09-05", "initial version, \\0 terminated strings"}, - {0, NULL, NULL} - }; - - return nss_cli_protocol_version; -} - -static struct sss_cmd_table nss_cmds[] = { - {SSS_GET_VERSION, sss_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_CLI_NULL, NULL} -}; - -struct sss_cmd_table *get_nss_cmds(void) { - return nss_cmds; -} - -int nss_cmd_execute(struct cli_ctx *cctx) -{ - enum sss_cli_command cmd; - int i; - - cmd = sss_packet_get_cmd(cctx->creq->in); - - for (i = 0; nss_cmds[i].cmd != SSS_CLI_NULL; i++) { - if (cmd == nss_cmds[i].cmd) { - return nss_cmds[i].fn(cctx); - } - } - - return EINVAL; -} - diff --git a/server/responder/nss/nsssrv_nc.c b/server/responder/nss/nsssrv_nc.c deleted file mode 100644 index 1fa7d612f..000000000 --- a/server/responder/nss/nsssrv_nc.c +++ /dev/null @@ -1,321 +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 <fcntl.h> -#include <time.h> -#include "tdb.h" - -#define NC_ENTRY_PREFIX "NCE/" -#define NC_USER_PREFIX NC_ENTRY_PREFIX"USER" -#define NC_GROUP_PREFIX NC_ENTRY_PREFIX"GROUP" -#define NC_UID_PREFIX NC_ENTRY_PREFIX"UID" -#define NC_GID_PREFIX NC_ENTRY_PREFIX"GID" - -struct nss_nc_ctx { - struct tdb_context *tdb; -}; - -static int string_to_tdb_data(char *str, TDB_DATA *ret) -{ - if (!str || !ret) return EINVAL; - - ret->dptr = (uint8_t *)str; - ret->dsize = strlen(str)+1; - - return EOK; -} - -int nss_ncache_init(TALLOC_CTX *memctx, struct nss_nc_ctx **_ctx) -{ - struct nss_nc_ctx *ctx; - - ctx = talloc_zero(memctx, struct nss_nc_ctx); - if (!ctx) return ENOMEM; - - errno = 0; - /* open a memory only tdb with default hash size */ - ctx->tdb = tdb_open("memcache", 0, TDB_INTERNAL, O_RDWR|O_CREAT, 0); - if (!ctx->tdb) return errno; - - *_ctx = ctx; - return EOK; -}; - -static int nss_ncache_check_str(struct nss_nc_ctx *ctx, char *str, int ttl) -{ - TDB_DATA key; - TDB_DATA data; - unsigned long long int timestamp; - bool expired = false; - char *ep; - int ret; - - ret = string_to_tdb_data(str, &key); - if (ret != EOK) goto done; - - data = tdb_fetch(ctx->tdb, key); - - if (!data.dptr) { - ret = ENOENT; - goto done; - } - - if (ttl == -1) { - /* a negative ttl means: never expires */ - ret = EEXIST; - goto done; - } - - errno = 0; - timestamp = strtoull((const char *)data.dptr, &ep, 0); - if (errno != 0 || *ep != '\0') { - /* Malformed entry, remove it and return no entry */ - expired = true; - goto done; - } - - if (timestamp == 0) { - /* a 0 timestamp means this is a permanent entry */ - ret = EEXIST; - goto done; - } - - if (timestamp + ttl > time(NULL)) { - /* still valid */ - ret = EEXIST; - goto done; - } - - expired = true; - -done: - if (expired) { - /* expired, remove and return no entry */ - tdb_delete(ctx->tdb, key); - ret = ENOENT; - } - - return ret; -} - -static int nss_ncache_set_str(struct nss_nc_ctx *ctx, - char *str, bool permanent) -{ - TDB_DATA key; - TDB_DATA data; - char *timest; - int ret; - - ret = string_to_tdb_data(str, &key); - if (ret != EOK) return ret; - - if (permanent) { - timest = talloc_strdup(ctx, "0"); - } else { - timest = talloc_asprintf(ctx, "%llu", - (unsigned long long int)time(NULL)); - } - if (!timest) return ENOMEM; - - ret = string_to_tdb_data(timest, &data); - if (ret != EOK) goto done; - - ret = tdb_store(ctx->tdb, key, data, TDB_REPLACE); - if (ret != 0) { - DEBUG(1, ("Negative cache failed to set entry: [%s]", - tdb_errorstr(ctx->tdb))); - ret = EFAULT; - } - -done: - talloc_free(timest); - return ret; -} - -int nss_ncache_check_user(struct nss_nc_ctx *ctx, int ttl, - const char *domain, const char *name) -{ - char *str; - int ret; - - if (!name || !*name) return EINVAL; - - str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name); - if (!str) return ENOMEM; - - ret = nss_ncache_check_str(ctx, str, ttl); - - talloc_free(str); - return ret; -} - -int nss_ncache_check_group(struct nss_nc_ctx *ctx, int ttl, - const char *domain, const char *name) -{ - char *str; - int ret; - - if (!name || !*name) return EINVAL; - - str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name); - if (!str) return ENOMEM; - - ret = nss_ncache_check_str(ctx, str, ttl); - - talloc_free(str); - return ret; -} - -int nss_ncache_check_uid(struct nss_nc_ctx *ctx, int ttl, uid_t uid) -{ - char *str; - int ret; - - str = talloc_asprintf(ctx, "%s/%u", NC_UID_PREFIX, uid); - if (!str) return ENOMEM; - - ret = nss_ncache_check_str(ctx, str, ttl); - - talloc_free(str); - return ret; -} - -int nss_ncache_check_gid(struct nss_nc_ctx *ctx, int ttl, gid_t gid) -{ - char *str; - int ret; - - str = talloc_asprintf(ctx, "%s/%u", NC_GID_PREFIX, gid); - if (!str) return ENOMEM; - - ret = nss_ncache_check_str(ctx, str, ttl); - - talloc_free(str); - return ret; -} - -int nss_ncache_set_user(struct nss_nc_ctx *ctx, bool permanent, - const char *domain, const char *name) -{ - char *str; - int ret; - - if (!name || !*name) return EINVAL; - - str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name); - if (!str) return ENOMEM; - - ret = nss_ncache_set_str(ctx, str, permanent); - - talloc_free(str); - return ret; -} - -int nss_ncache_set_group(struct nss_nc_ctx *ctx, bool permanent, - const char *domain, const char *name) -{ - char *str; - int ret; - - if (!name || !*name) return EINVAL; - - str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name); - if (!str) return ENOMEM; - - ret = nss_ncache_set_str(ctx, str, permanent); - - talloc_free(str); - return ret; -} - -int nss_ncache_set_uid(struct nss_nc_ctx *ctx, bool permanent, uid_t uid) -{ - char *str; - int ret; - - str = talloc_asprintf(ctx, "%s/%u", NC_UID_PREFIX, uid); - if (!str) return ENOMEM; - - ret = nss_ncache_set_str(ctx, str, permanent); - - talloc_free(str); - return ret; -} - -int nss_ncache_set_gid(struct nss_nc_ctx *ctx, bool permanent, gid_t gid) -{ - char *str; - int ret; - - str = talloc_asprintf(ctx, "%s/%u", NC_GID_PREFIX, gid); - if (!str) return ENOMEM; - - ret = nss_ncache_set_str(ctx, str, permanent); - - talloc_free(str); - return ret; -} - -static int delete_permanent(struct tdb_context *tdb, - TDB_DATA key, TDB_DATA data, void *state) -{ - unsigned long long int timestamp; - bool remove_key = false; - char *ep; - - if (strncmp((char *)key.dptr, - NC_ENTRY_PREFIX, sizeof(NC_ENTRY_PREFIX)) != 0) { - /* not interested in this key */ - return 0; - } - - errno = 0; - timestamp = strtoull((const char *)data.dptr, &ep, 0); - if (errno != 0 || *ep != '\0') { - /* Malformed entry, remove it */ - remove_key = true; - goto done; - } - - if (timestamp == 0) { - /* a 0 timestamp means this is a permanent entry */ - remove_key = true; - } - -done: - if (remove_key) { - return tdb_delete(tdb, key); - } - - return 0; -} - -int nss_ncache_reset_permament(struct nss_nc_ctx *ctx) -{ - int ret; - - ret = tdb_traverse(ctx->tdb, delete_permanent, NULL); - if (ret < 0) - return EIO; - - return EOK; -} diff --git a/server/responder/nss/nsssrv_nc.h b/server/responder/nss/nsssrv_nc.h deleted file mode 100644 index c0fa197c2..000000000 --- a/server/responder/nss/nsssrv_nc.h +++ /dev/null @@ -1,51 +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/>. -*/ - -#ifndef _NSS_NEG_CACHE_H_ -#define _NSS_NEG_CACHE_H_ - -struct nss_nc_ctx; - -/* init the in memory negative cache */ -int nss_ncache_init(TALLOC_CTX *memctx, struct nss_nc_ctx **_ctx); - -/* check if the user is expired according to the passed in time to live */ -int nss_ncache_check_user(struct nss_nc_ctx *ctx, int ttl, - const char *domain, const char *name); -int nss_ncache_check_group(struct nss_nc_ctx *ctx, int ttl, - const char *domain, const char *name); -int nss_ncache_check_uid(struct nss_nc_ctx *ctx, int ttl, uid_t uid); -int nss_ncache_check_gid(struct nss_nc_ctx *ctx, int ttl, gid_t gid); - -/* add a new neg-cache entry setting the timestamp to "now" unless - * "permanent" is set to true, in which case the timestamps is set to 0 - * and the negative cache never expires (used to permanently filter out - * users and groups) */ -int nss_ncache_set_user(struct nss_nc_ctx *ctx, bool permanent, - const char *domain, const char *name); -int nss_ncache_set_group(struct nss_nc_ctx *ctx, bool permanent, - const char *domain, const char *name); -int nss_ncache_set_uid(struct nss_nc_ctx *ctx, bool permanent, uid_t uid); -int nss_ncache_set_gid(struct nss_nc_ctx *ctx, bool permanent, gid_t gid); - -int nss_ncache_reset_permament(struct nss_nc_ctx *ctx); - -#endif /* _NSS_NEG_CACHE_H_ */ diff --git a/server/responder/pam/pam_LOCAL_domain.c b/server/responder/pam/pam_LOCAL_domain.c deleted file mode 100644 index 34f0c8dd5..000000000 --- a/server/responder/pam/pam_LOCAL_domain.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - SSSD - - PAM e credentials - - Copyright (C) Sumit Bose <sbose@redhat.com> 2009 - - 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 <time.h> -#include <security/pam_modules.h> - -#include "util/util.h" -#include "db/sysdb.h" -#include "util/sha512crypt.h" -#include "providers/data_provider.h" -#include "responder/pam/pamsrv.h" - - -#define NULL_CHECK_OR_JUMP(var, msg, ret, err, label) do { \ - if (var == NULL) { \ - DEBUG(1, (msg)); \ - ret = (err); \ - goto label; \ - } \ -} while(0) - -#define NEQ_CHECK_OR_JUMP(var, val, msg, ret, err, label) do { \ - if (var != (val)) { \ - DEBUG(1, (msg)); \ - ret = (err); \ - goto label; \ - } \ -} while(0) - - -struct LOCAL_request { - struct tevent_context *ev; - struct sysdb_ctx *dbctx; - struct sysdb_attrs *mod_attrs; - struct sysdb_handle *handle; - - struct ldb_result *res; - int error; - - struct pam_auth_req *preq; -}; - -static void prepare_reply(struct LOCAL_request *lreq) -{ - struct pam_data *pd; - - pd = lreq->preq->pd; - - if (lreq->error != EOK && pd->pam_status == PAM_SUCCESS) - pd->pam_status = PAM_SYSTEM_ERR; - - lreq->preq->callback(lreq->preq); -} - -static void set_user_attr_done(struct tevent_req *req) -{ - struct LOCAL_request *lreq; - int ret; - - lreq = tevent_req_callback_data(req, struct LOCAL_request); - - ret = sysdb_transaction_commit_recv(req); - if (ret) { - DEBUG(2, ("set_user_attr failed.\n")); - lreq->error =ret; - } - - prepare_reply(lreq); -} - -static void set_user_attr_req_done(struct tevent_req *subreq); -static void set_user_attr_req(struct tevent_req *req) -{ - struct LOCAL_request *lreq = tevent_req_callback_data(req, - struct LOCAL_request); - struct tevent_req *subreq; - int ret; - - DEBUG(4, ("entering set_user_attr_req\n")); - - ret = sysdb_transaction_recv(req, lreq, &lreq->handle); - if (ret) { - lreq->error = ret; - return prepare_reply(lreq); - } - - subreq = sysdb_set_user_attr_send(lreq, lreq->ev, lreq->handle, - lreq->preq->domain, - lreq->preq->pd->user, - lreq->mod_attrs, SYSDB_MOD_REP); - if (!subreq) { - /* cancel transaction */ - talloc_zfree(lreq->handle); - lreq->error = ret; - return prepare_reply(lreq); - } - tevent_req_set_callback(subreq, set_user_attr_req_done, lreq); -} - -static void set_user_attr_req_done(struct tevent_req *subreq) -{ - struct LOCAL_request *lreq = tevent_req_callback_data(subreq, - struct LOCAL_request); - struct tevent_req *req; - int ret; - - ret = sysdb_set_user_attr_recv(subreq); - talloc_zfree(subreq); - - DEBUG(4, ("set_user_attr_callback, status [%d][%s]\n", ret, strerror(ret))); - - if (ret) { - lreq->error = ret; - goto fail; - } - - req = sysdb_transaction_commit_send(lreq, lreq->ev, lreq->handle); - if (!req) { - lreq->error = ENOMEM; - goto fail; - } - tevent_req_set_callback(req, set_user_attr_done, lreq); - - return; - -fail: - DEBUG(2, ("set_user_attr failed.\n")); - - /* cancel transaction */ - talloc_zfree(lreq->handle); - - prepare_reply(lreq); -} - -static void do_successful_login(struct LOCAL_request *lreq) -{ - struct tevent_req *req; - int ret; - - lreq->mod_attrs = sysdb_new_attrs(lreq); - NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), - lreq->error, ENOMEM, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - SYSDB_LAST_LOGIN, (long)time(NULL)); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, SYSDB_FAILED_LOGIN_ATTEMPTS, 0L); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); - if (!req) { - lreq->error = ENOMEM; - goto done; - } - tevent_req_set_callback(req, set_user_attr_req, lreq); - - return; - -done: - - prepare_reply(lreq); -} - -static void do_failed_login(struct LOCAL_request *lreq) -{ - struct tevent_req *req; - int ret; - int failedLoginAttempts; - struct pam_data *pd; - - pd = lreq->preq->pd; - pd->pam_status = PAM_AUTH_ERR; -/* TODO: maybe add more inteligent delay calculation */ - pd->response_delay = 3; - - lreq->mod_attrs = sysdb_new_attrs(lreq); - NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), - lreq->error, ENOMEM, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - SYSDB_LAST_FAILED_LOGIN, (long)time(NULL)); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - failedLoginAttempts = ldb_msg_find_attr_as_int(lreq->res->msgs[0], - SYSDB_FAILED_LOGIN_ATTEMPTS, - 0); - failedLoginAttempts++; - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - SYSDB_FAILED_LOGIN_ATTEMPTS, - (long)failedLoginAttempts); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); - if (!req) { - lreq->error = ENOMEM; - goto done; - } - tevent_req_set_callback(req, set_user_attr_req, lreq); - - return; - -done: - - prepare_reply(lreq); -} - -static void do_pam_acct_mgmt(struct LOCAL_request *lreq) -{ - const char *disabled; - struct pam_data *pd; - - pd = lreq->preq->pd; - - disabled = ldb_msg_find_attr_as_string(lreq->res->msgs[0], - SYSDB_DISABLED, NULL); - if ((disabled != NULL) && - (strncasecmp(disabled, "false",5) != 0) && - (strncasecmp(disabled, "no",2) != 0) ) { - pd->pam_status = PAM_PERM_DENIED; - } - - prepare_reply(lreq); -} - -static void do_pam_chauthtok(struct LOCAL_request *lreq) -{ - struct tevent_req *req; - int ret; - char *newauthtok; - char *salt; - char *new_hash; - struct pam_data *pd; - - pd = lreq->preq->pd; - - newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { - /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!")); - ret = EINVAL; - goto done; - } - - ret = s3crypt_gen_salt(lreq, &salt); - NEQ_CHECK_OR_JUMP(ret, EOK, ("Salt generation failed.\n"), - lreq->error, ret, done); - DEBUG(4, ("Using salt [%s]\n", salt)); - - ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); - NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), - lreq->error, ret, done); - DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size); - - lreq->mod_attrs = sysdb_new_attrs(lreq); - NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), - lreq->error, ENOMEM, done); - - ret = sysdb_attrs_add_string(lreq->mod_attrs, SYSDB_PWD, new_hash); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_string failed.\n"), - lreq->error, ret, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - "lastPasswordChange", (long)time(NULL)); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); - if (!req) { - lreq->error = ENOMEM; - goto done; - } - tevent_req_set_callback(req, set_user_attr_req, lreq); - - return; -done: - - prepare_reply(lreq); -} - -static void local_handler_callback(void *pvt, int ldb_status, - struct ldb_result *res) -{ - struct LOCAL_request *lreq; - const char *username = NULL; - const char *password = NULL; - char *newauthtok = NULL; - char *new_hash = NULL; - char *authtok = NULL; - struct pam_data *pd; - int ret; - - lreq = talloc_get_type(pvt, struct LOCAL_request); - pd = lreq->preq->pd; - - DEBUG(4, ("pam_handler_callback called with ldb_status [%d].\n", - ldb_status)); - - NEQ_CHECK_OR_JUMP(ldb_status, LDB_SUCCESS, ("ldb search failed.\n"), - lreq->error, sysdb_error_to_errno(ldb_status), done); - - - if (res->count < 1) { - DEBUG(4, ("No user found with filter ["SYSDB_PWNAM_FILTER"]\n", - pd->user)); - pd->pam_status = PAM_USER_UNKNOWN; - goto done; - } else if (res->count > 1) { - DEBUG(4, ("More than one object found with filter ["SYSDB_PWNAM_FILTER"]\n")); - lreq->error = EFAULT; - goto done; - } - - username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); - if (strcmp(username, pd->user) != 0) { - DEBUG(1, ("Expected username [%s] get [%s].\n", pd->user, username)); - lreq->error = EINVAL; - goto done; - } - - lreq->res = res; - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - if ((pd->cmd == SSS_PAM_CHAUTHTOK || - pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && - lreq->preq->cctx->priv == 1) { -/* TODO: maybe this is a candiate for an explicit audit message. */ - DEBUG(4, ("allowing root to reset a password.\n")); - break; - } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); - - password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), - lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); - - ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); - NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), - lreq->error, ret, done); - - DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash)); - - if (strcmp(new_hash, password) != 0) { - DEBUG(1, ("Passwords do not match.\n")); - do_failed_login(lreq); - return; - } - - break; - } - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - do_successful_login(lreq); - return; - break; - case SSS_PAM_CHAUTHTOK: - do_pam_chauthtok(lreq); - return; - break; - case SSS_PAM_ACCT_MGMT: - do_pam_acct_mgmt(lreq); - return; - break; - case SSS_PAM_SETCRED: - break; - case SSS_PAM_OPEN_SESSION: - break; - case SSS_PAM_CLOSE_SESSION: - break; - case SSS_PAM_CHAUTHTOK_PRELIM: - break; - default: - lreq->error = EINVAL; - DEBUG(1, ("Unknown PAM task [%d].\n")); - } - -done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - if (newauthtok != NULL) - memset(newauthtok, 0, pd->newauthtok_size); - - prepare_reply(lreq); -} - -int LOCAL_pam_handler(struct pam_auth_req *preq) -{ - int ret; - struct LOCAL_request *lreq; - - static const char *attrs[] = {SYSDB_NAME, - SYSDB_PWD, - SYSDB_DISABLED, - SYSDB_LAST_LOGIN, - "lastPasswordChange", - "accountExpires", - SYSDB_FAILED_LOGIN_ATTEMPTS, - "passwordHint", - "passwordHistory", - SYSDB_LAST_FAILED_LOGIN, - NULL}; - - DEBUG(4, ("LOCAL pam handler.\n")); - - lreq = talloc_zero(preq, struct LOCAL_request); - if (!lreq) { - return ENOMEM; - } - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &lreq->dbctx); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - talloc_free(lreq); - return ret; - } - lreq->ev = preq->cctx->ev; - lreq->preq = preq; - - preq->pd->pam_status = PAM_SUCCESS; - - ret = sysdb_get_user_attr(lreq, lreq->dbctx, - preq->domain, preq->pd->user, attrs, - local_handler_callback, lreq); - - if (ret != EOK) { - DEBUG(1, ("sysdb_get_user_attr failed.\n")); - talloc_free(lreq); - return ret; - } - - return EOK; -} diff --git a/server/responder/pam/pamsrv.c b/server/responder/pam/pamsrv.c deleted file mode 100644 index 84b13dc45..000000000 --- a/server/responder/pam/pamsrv.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - SSSD - - PAM Responder - - Copyright (C) Simo Sorce <ssorce@redhat.com> 2009 - Copyright (C) Sumit Bose <sbose@redhat.com> 2009 - - 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 "db/sysdb.h" -#include "confdb/confdb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "responder/common/responder_packet.h" -#include "providers/data_provider.h" -#include "monitor/monitor_interfaces.h" -#include "sbus/sbus_client.h" -#include "responder/pam/pamsrv.h" - -#define SSS_PAM_SBUS_SERVICE_VERSION 0x0001 -#define SSS_PAM_SBUS_SERVICE_NAME "pam" - -static int service_reload(DBusMessage *message, struct sbus_connection *conn); - -struct sbus_method monitor_pam_methods[] = { - { MON_CLI_METHOD_PING, monitor_common_pong }, - { MON_CLI_METHOD_RELOAD, service_reload }, - { MON_CLI_METHOD_RES_INIT, monitor_common_res_init }, - { NULL, NULL } -}; - -struct sbus_interface monitor_pam_interface = { - MONITOR_INTERFACE, - MONITOR_PATH, - SBUS_DEFAULT_VTABLE, - monitor_pam_methods, - NULL -}; - -static int service_reload(DBusMessage *message, struct sbus_connection *conn) { - /* 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 monitor_common_pong(message, conn); -} - -static struct sbus_method pam_dp_methods[] = { - { NULL, NULL } -}; - -struct sbus_interface pam_dp_interface = { - DP_INTERFACE, - DP_PATH, - SBUS_DEFAULT_VTABLE, - pam_dp_methods, - NULL -}; - - -static void pam_dp_reconnect_init(struct sbus_connection *conn, int status, void *pvt) -{ - struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn); - int ret; - - /* Did we reconnect successfully? */ - if (status == SBUS_RECONNECT_SUCCESS) { - DEBUG(1, ("Reconnected to the Data Provider.\n")); - - /* Identify ourselves to the data provider */ - ret = dp_common_send_id(be_conn->conn, - DATA_PROVIDER_VERSION, - "PAM", be_conn->domain->name); - /* all fine */ - if (ret == EOK) return; - } - - /* Handle failure */ - DEBUG(0, ("Could not reconnect to %s provider.\n", - be_conn->domain->name)); - - /* FIXME: kill the frontend and let the monitor restart it ? */ - /* pam_shutdown(rctx); */ -} - -static errno_t pam_get_config(struct pam_ctx *pctx, - struct resp_ctx *rctx, - struct confdb_ctx *cdb) -{ - int ret = EOK; - ret = confdb_get_int(cdb, pctx, CONFDB_PAM_CONF_ENTRY, - CONFDB_PAM_CRED_TIMEOUT, 0, - &pctx->cred_expiration); - return ret; -} - -static int pam_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb) -{ - struct sss_cmd_table *pam_cmds; - struct be_conn *iter; - struct pam_ctx *pctx; - int ret, max_retries; - - pctx = talloc_zero(mem_ctx, struct pam_ctx); - if (!pctx) { - return ENOMEM; - } - - pam_cmds = get_pam_cmds(); - ret = sss_process_init(pctx, ev, cdb, - pam_cmds, - SSS_PAM_SOCKET_NAME, - SSS_PAM_PRIV_SOCKET_NAME, - CONFDB_PAM_CONF_ENTRY, - SSS_PAM_SBUS_SERVICE_NAME, - SSS_PAM_SBUS_SERVICE_VERSION, - &monitor_pam_interface, - "PAM", &pam_dp_interface, - &pctx->rctx); - if (ret != EOK) { - return ret; - } - - pctx->rctx->pvt_ctx = pctx; - ret = pam_get_config(pctx, pctx->rctx, pctx->rctx->cdb); - - /* Enable automatic reconnection to the Data Provider */ - - /* FIXME: "retries" is too generic, either get it from a global config - * or specify these retries are about the sbus connections to DP */ - ret = confdb_get_int(pctx->rctx->cdb, pctx->rctx, CONFDB_PAM_CONF_ENTRY, - CONFDB_SERVICE_RECON_RETRIES, 3, &max_retries); - if (ret != EOK) { - DEBUG(0, ("Failed to set up automatic reconnection\n")); - return ret; - } - - for (iter = pctx->rctx->be_conns; iter; iter = iter->next) { - sbus_reconnect_init(iter->conn, max_retries, - pam_dp_reconnect_init, iter); - } - - 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... */ - debug_log_file = "sssd_pam"; - - ret = server_setup("sssd[pam]", 0, CONFDB_PAM_CONF_ENTRY, &main_ctx); - if (ret != EOK) return 2; - - ret = die_if_parent_died(); - if (ret != EOK) { - /* This is not fatal, don't return */ - DEBUG(2, ("Could not set up to exit when parent process does\n")); - } - - ret = pam_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/responder/pam/pamsrv.h b/server/responder/pam/pamsrv.h deleted file mode 100644 index 60f9c66ae..000000000 --- a/server/responder/pam/pamsrv.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Authors: - Simo Sorce <ssorce@redhat.com> - Sumit Bose <sbose@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef __PAMSRV_H__ -#define __PAMSRV_H__ - -#include <security/pam_appl.h> -#include "util/util.h" -#include "sbus/sssd_dbus.h" -#include "responder/common/responder.h" - -struct pam_auth_req; - -typedef void (pam_dp_callback_t)(struct pam_auth_req *preq); - -struct pam_ctx { - int cred_expiration; - struct resp_ctx *rctx; -}; - -struct pam_auth_req { - struct cli_ctx *cctx; - struct sss_domain_info *domain; - - struct pam_data *pd; - - pam_dp_callback_t *callback; - - bool check_provider; - void *data; -}; - -struct sss_cmd_table *get_pam_cmds(void); - -int pam_dp_send_req(struct pam_auth_req *preq, int timeout); - -int LOCAL_pam_handler(struct pam_auth_req *preq); - -#endif /* __PAMSRV_H__ */ diff --git a/server/responder/pam/pamsrv_cmd.c b/server/responder/pam/pamsrv_cmd.c deleted file mode 100644 index 37aad8299..000000000 --- a/server/responder/pam/pamsrv_cmd.c +++ /dev/null @@ -1,1181 +0,0 @@ -/* - SSSD - - PAM Responder - - Copyright (C) Simo Sorce <ssorce@redhat.com> 2009 - Copyright (C) Sumit Bose <sbose@redhat.com> 2009 - - 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 <time.h> -#include "util/util.h" -#include "db/sysdb.h" -#include "confdb/confdb.h" -#include "responder/common/responder_packet.h" -#include "responder/common/responder.h" -#include "providers/data_provider.h" -#include "responder/pam/pamsrv.h" -#include "db/sysdb.h" - -static void pam_reply(struct pam_auth_req *preq); - -static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, uint8_t *body, size_t blen, size_t *c) { - uint32_t data_size; - - if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL; - - memcpy(&data_size, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - if (data_size < sizeof(uint32_t) || (*c)+(data_size) > blen) return EINVAL; - *size = data_size - sizeof(uint32_t); - - memcpy(type, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - - *tok = body+(*c); - - *c += (*size); - - return EOK; -} - -static int extract_string(char **var, uint8_t *body, size_t blen, size_t *c) { - uint32_t size; - uint8_t *str; - - if (blen-(*c) < sizeof(uint32_t)+1) return EINVAL; - - memcpy(&size, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - if (*c+size > blen) return EINVAL; - - str = body+(*c); - - if (str[size-1]!='\0') return EINVAL; - - *c += size; - - *var = (char *) str; - - return EOK; -} - -static int extract_uint32_t(uint32_t *var, uint8_t *body, size_t blen, size_t *c) { - uint32_t size; - - if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL; - - memcpy(&size, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - - memcpy(var, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - - return EOK; -} - -static int pam_parse_in_data_v2(struct sss_names_ctx *snctx, - struct pam_data *pd, - uint8_t *body, size_t blen) -{ - size_t c; - uint32_t type; - uint32_t size; - char *pam_user; - int ret; - uint32_t terminator = SSS_END_OF_PAM_REQUEST; - - if (blen < 4*sizeof(uint32_t)+2 || - ((uint32_t *)body)[0] != SSS_START_OF_PAM_REQUEST || - memcmp(&body[blen - sizeof(uint32_t)], &terminator, sizeof(uint32_t)) != 0) { - DEBUG(1, ("Received data is invalid.\n")); - return EINVAL; - } - - c = sizeof(uint32_t); - do { - memcpy(&type, &body[c], sizeof(uint32_t)); - c += sizeof(uint32_t); - if (c > blen) return EINVAL; - - switch(type) { - case SSS_PAM_ITEM_USER: - ret = extract_string(&pam_user, body, blen, &c); - if (ret != EOK) return ret; - - ret = sss_parse_name(pd, snctx, pam_user, - &pd->domain, &pd->user); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_SERVICE: - ret = extract_string(&pd->service, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_TTY: - ret = extract_string(&pd->tty, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_RUSER: - ret = extract_string(&pd->ruser, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_RHOST: - ret = extract_string(&pd->rhost, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_CLI_PID: - ret = extract_uint32_t(&pd->cli_pid, - body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_END_OF_PAM_REQUEST: - if (c != blen) return EINVAL; - break; - default: - DEBUG(1,("Ignoring unknown data type [%d].\n", type)); - size = ((uint32_t *)&body[c])[0]; - c += size+sizeof(uint32_t); - } - } while(c < blen); - - if (pd->user == NULL || *pd->user == '\0') return EINVAL; - - DEBUG_PAM_DATA(4, pd); - - return EOK; - -} - -static int pam_parse_in_data_v3(struct sss_names_ctx *snctx, - struct pam_data *pd, - uint8_t *body, size_t blen) -{ - int ret; - - ret = pam_parse_in_data_v2(snctx, pd, body, blen); - if (ret != EOK) { - DEBUG(1, ("pam_parse_in_data_v2 failed.\n")); - return ret; - } - - if (pd->cli_pid == 0) { - DEBUG(1, ("Missing client PID.\n")); - return EINVAL; - } - - return EOK; -} - -static int pam_parse_in_data(struct sss_names_ctx *snctx, - struct pam_data *pd, - uint8_t *body, size_t blen) -{ - int start; - int end; - int last; - int ret; - - last = blen - 1; - end = 0; - - /* user name */ - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - - ret = sss_parse_name(pd, snctx, (char *)&body[start], &pd->domain, &pd->user); - if (ret != EOK) return ret; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->service = (char *) &body[start]; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->tty = (char *) &body[start]; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->ruser = (char *) &body[start]; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->rhost = (char *) &body[start]; - - start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } - } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } - } - - DEBUG_PAM_DATA(4, pd); - - return EOK; -} - -/*=Save-Last-Login-State===================================================*/ - -struct set_last_login_state { - struct tevent_context *ev; - struct sysdb_ctx *dbctx; - - struct sss_domain_info *dom; - const char *username; - struct sysdb_attrs *attrs; - - struct sysdb_handle *handle; - - struct ldb_result *res; -}; - -static void set_last_login_trans_done(struct tevent_req *subreq); -static void set_last_login_attrs_done(struct tevent_req *subreq); -static void set_last_login_done(struct tevent_req *subreq); - -static struct tevent_req *set_last_login_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sysdb_ctx *dbctx, - struct sss_domain_info *dom, - const char *username, - struct sysdb_attrs *attrs) -{ - struct tevent_req *req, *subreq; - struct set_last_login_state *state; - - req = tevent_req_create(memctx, &state, struct set_last_login_state); - if (!req) { - return NULL; - } - - state->ev = ev; - state->dbctx = dbctx; - state->dom = dom; - state->username = username; - state->attrs = attrs; - state->handle = NULL; - - subreq = sysdb_transaction_send(state, state->ev, state->dbctx); - if (!subreq) { - talloc_free(req); - return NULL; - } - tevent_req_set_callback(subreq, set_last_login_trans_done, req); - - return req; -} - -static void set_last_login_trans_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct set_last_login_state *state = tevent_req_data(req, - struct set_last_login_state); - int ret; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(1, ("Unable to acquire sysdb transaction lock\n")); - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_set_user_attr_send(state, state->ev, state->handle, - state->dom, state->username, - state->attrs, SYSDB_MOD_REP); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, set_last_login_attrs_done, req); -} - -static void set_last_login_attrs_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct set_last_login_state *state = tevent_req_data(req, - struct set_last_login_state); - int ret; - - ret = sysdb_set_user_attr_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(4, ("set_user_attr_callback, status [%d][%s]\n", - ret, strerror(ret))); - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, set_last_login_done, req); -} - -static void set_last_login_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - int ret; - - ret = sysdb_transaction_commit_recv(subreq); - if (ret != EOK) { - DEBUG(2, ("set_last_login failed.\n")); - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int set_last_login_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -/*=========================================================================*/ - - -static void set_last_login_reply(struct tevent_req *req); - -static errno_t set_last_login(struct pam_auth_req *preq) -{ - struct tevent_req *req; - struct sysdb_ctx *dbctx; - struct sysdb_attrs *attrs; - errno_t ret; - - attrs = sysdb_new_attrs(preq); - if (!attrs) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL)); - if (ret != EOK) { - goto fail; - } - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, preq->domain, - &dbctx); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb context not found for this domain!\n")); - goto fail; - } - - req = set_last_login_send(preq, preq->cctx->ev, dbctx, - preq->domain, preq->pd->user, attrs); - if (!req) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(req, set_last_login_reply, preq); - - return EOK; - -fail: - return ret; -} - -static void set_last_login_reply(struct tevent_req *req) -{ - struct pam_auth_req *preq = tevent_req_callback_data(req, - struct pam_auth_req); - int ret; - - ret = set_last_login_recv(req); - if (ret != EOK) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - } else { - preq->pd->last_auth_saved = true; - } - - preq->callback(preq); -} - -static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct pam_auth_req *preq; - - DEBUG(4, ("pam_reply_delay get called.\n")); - - preq = talloc_get_type(pvt, struct pam_auth_req); - - pam_reply(preq); -} - -static void pam_cache_auth_done(struct tevent_req *req); - -static void pam_reply(struct pam_auth_req *preq) -{ - struct cli_ctx *cctx; - uint8_t *body; - size_t blen; - int ret; - int32_t resp_c; - int32_t resp_size; - struct response_data *resp; - int p; - struct timeval tv; - struct tevent_timer *te; - struct pam_data *pd; - struct tevent_req *req; - struct sysdb_ctx *sysdb; - struct pam_ctx *pctx; - uint32_t user_info_type; - - pd = preq->pd; - cctx = preq->cctx; - - DEBUG(4, ("pam_reply get called.\n")); - - if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) { - switch(pd->cmd) { - case SSS_PAM_AUTHENTICATE: - if ((preq->domain != NULL) && - (preq->domain->cache_credentials == true) && - (pd->offline_auth == false)) { - - /* do auth with offline credentials */ - pd->offline_auth = true; - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } - - pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, - struct pam_ctx); - - req = sysdb_cache_auth_send(preq, preq->cctx->ev, sysdb, - preq->domain, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb); - if (req == NULL) { - DEBUG(1, ("Failed to setup offline auth.\n")); - /* this error is not fatal, continue */ - } else { - tevent_req_set_callback(req, pam_cache_auth_done, preq); - return; - } - } - break; - case SSS_PAM_CHAUTHTOK_PRELIM: - case SSS_PAM_CHAUTHTOK: - DEBUG(5, ("Password change not possible while offline.\n")); - pd->pam_status = PAM_AUTHTOK_ERR; - user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS; - pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), - (const uint8_t *) &user_info_type); - break; -/* TODO: we need the pam session cookie here to make sure that cached - * authentication was successful */ - case SSS_PAM_SETCRED: - case SSS_PAM_ACCT_MGMT: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - DEBUG(2, ("Assuming offline authentication setting status for " - "pam call %d to PAM_SUCCESS.\n", pd->cmd)); - pd->pam_status = PAM_SUCCESS; - break; - default: - DEBUG(1, ("Unknown PAM call [%d].\n", pd->cmd)); - pd->pam_status = PAM_MODULE_UNKNOWN; - } - } - - if (pd->response_delay > 0) { - ret = gettimeofday(&tv, NULL); - if (ret != EOK) { - DEBUG(1, ("gettimeofday failed [%d][%s].\n", - errno, strerror(errno))); - goto done; - } - tv.tv_sec += pd->response_delay; - tv.tv_usec = 0; - pd->response_delay = 0; - - te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq); - if (te == NULL) { - DEBUG(1, ("Failed to add event pam_reply_delay.\n")); - goto done; - } - - return; - } - - /* If this was a successful login, save the lastLogin time */ - if (pd->cmd == SSS_PAM_AUTHENTICATE && - pd->pam_status == PAM_SUCCESS && - preq->domain->cache_credentials && - !pd->offline_auth && - !pd->last_auth_saved && - NEED_CHECK_PROVIDER(preq->domain->provider)) { - ret = set_last_login(preq); - if (ret != EOK) { - goto done; - } - - return; - } - - ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - goto done; - } - - if (pd->domain != NULL) { - pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1, - (uint8_t *) pd->domain); - } - - resp_c = 0; - resp_size = 0; - resp = pd->resp_list; - while(resp != NULL) { - resp_c++; - resp_size += resp->len; - resp = resp->next; - } - - ret = sss_packet_grow(cctx->creq->out, sizeof(int32_t) + - sizeof(int32_t) + - resp_c * 2* sizeof(int32_t) + - resp_size); - if (ret != EOK) { - goto done; - } - - sss_packet_get_body(cctx->creq->out, &body, &blen); - DEBUG(4, ("blen: %d\n", blen)); - p = 0; - - memcpy(&body[p], &pd->pam_status, sizeof(int32_t)); - p += sizeof(int32_t); - - memcpy(&body[p], &resp_c, sizeof(int32_t)); - p += sizeof(int32_t); - - resp = pd->resp_list; - while(resp != NULL) { - memcpy(&body[p], &resp->type, sizeof(int32_t)); - p += sizeof(int32_t); - memcpy(&body[p], &resp->len, sizeof(int32_t)); - p += sizeof(int32_t); - memcpy(&body[p], resp->data, resp->len); - p += resp->len; - - resp = resp->next; - } - -done: - sss_cmd_done(cctx, preq); -} - -static void pam_cache_auth_done(struct tevent_req *req) -{ - int ret; - struct pam_auth_req *preq = tevent_req_callback_data(req, - struct pam_auth_req); - uint32_t resp_type; - size_t resp_len; - uint8_t *resp; - time_t expire_date = 0; - time_t delayed_until = -1; - long long dummy; - - ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until); - talloc_zfree(req); - - switch (ret) { - case EOK: - preq->pd->pam_status = PAM_SUCCESS; - - resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH; - resp_len = sizeof(uint32_t) + sizeof(long long); - resp = talloc_size(preq->pd, resp_len); - if (resp == NULL) { - DEBUG(1, ("talloc_size failed, cannot prepare user info.\n")); - } else { - memcpy(resp, &resp_type, sizeof(uint32_t)); - dummy = (long long) expire_date; - memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long)); - ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len, - (const uint8_t *) resp); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - } - break; - case ENOENT: - preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; - break; - case EINVAL: - preq->pd->pam_status = PAM_AUTH_ERR; - break; - case EACCES: - preq->pd->pam_status = PAM_PERM_DENIED; - if (delayed_until >= 0) { - resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED; - resp_len = sizeof(uint32_t) + sizeof(long long); - resp = talloc_size(preq->pd, resp_len); - if (resp == NULL) { - DEBUG(1, ("talloc_size failed, cannot prepare user info.\n")); - } else { - memcpy(resp, &resp_type, sizeof(uint32_t)); - dummy = (long long) delayed_until; - memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long)); - ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len, - (const uint8_t *) resp); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - } - } - break; - default: - preq->pd->pam_status = PAM_SYSTEM_ERR; - } - - pam_reply(preq); - return; -} - -static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); -static void pam_check_user_callback(void *ptr, int status, - struct ldb_result *res); -static void pam_dom_forwarder(struct pam_auth_req *preq); - -/* TODO: we should probably return some sort of cookie that is set in the - * PAM_ENVIRONMENT, so that we can save performing some calls and cache - * data. */ - -static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) -{ - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct pam_auth_req *preq; - struct pam_data *pd; - uint8_t *body; - size_t blen; - int timeout; - int ret; - uint32_t terminator = SSS_END_OF_PAM_REQUEST; - preq = talloc_zero(cctx, struct pam_auth_req); - if (!preq) { - return ENOMEM; - } - preq->cctx = cctx; - - preq->pd = talloc_zero(preq, struct pam_data); - if (!preq->pd) { - talloc_free(preq); - return ENOMEM; - } - pd = preq->pd; - - sss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen >= sizeof(uint32_t) && - memcmp(&body[blen - sizeof(uint32_t)], &terminator, sizeof(uint32_t)) != 0) { - DEBUG(1, ("Received data not terminated.\n")); - ret = EINVAL; - goto done; - } - - pd->cmd = pam_cmd; - pd->priv = cctx->priv; - - switch (cctx->cli_protocol_version->version) { - case 1: - ret = pam_parse_in_data(cctx->rctx->names, pd, body, blen); - break; - case 2: - ret = pam_parse_in_data_v2(cctx->rctx->names, pd, body, blen); - break; - case 3: - ret = pam_parse_in_data_v3(cctx->rctx->names, pd, body, blen); - break; - default: - DEBUG(1, ("Illegal protocol version [%d].\n", - cctx->cli_protocol_version->version)); - ret = EINVAL; - } - if (ret != EOK) { - ret = EINVAL; - goto done; - } - - /* now check user is valid */ - if (pd->domain) { - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, pd->domain) == 0) break; - } - if (!dom) { - ret = ENOENT; - goto done; - } - preq->domain = dom; - } - else { - for (dom = preq->cctx->rctx->domains; dom; dom = dom->next) { - if (dom->fqnames) continue; - -/* FIXME: need to support negative cache */ -#if HAVE_NEG_CACHE - ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; -#endif - break; - } - if (!dom) { - ret = ENOENT; - goto done; - } - preq->domain = dom; - } - - if (preq->domain->provider == NULL) { - DEBUG(1, ("Domain [%s] has no auth provider.\n", preq->domain->name)); - ret = EINVAL; - goto done; - } - - /* When auth is requested always search the provider first, - * do not rely on cached data unless the provider is completely - * offline */ - if (NEED_CHECK_PROVIDER(preq->domain->provider) && - (pam_cmd == SSS_PAM_AUTHENTICATE || pam_cmd == SSS_PAM_SETCRED)) { - - /* no need to re-check later on */ - preq->check_provider = false; - timeout = SSS_CLI_SOCKET_TIMEOUT/2; - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, preq, - timeout, preq->domain->name, - false, SSS_DP_INITGROUPS, - preq->pd->user, 0); - } - else { - preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - goto done; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); - } - -done: - if (ret != EOK) { - switch (ret) { - case ENOENT: - pd->pam_status = PAM_USER_UNKNOWN; - default: - pd->pam_status = PAM_SYSTEM_ERR; - } - pam_reply(preq); - } - return EOK; -} - -static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req); - struct sysdb_ctx *sysdb; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - /* always try to see if we have the user in cache even if the provider - * returned an error */ - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - goto done; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); - -done: - if (ret != EOK) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } -} - -static void pam_check_user_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req); - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - uint64_t cacheExpire; - bool call_provider = false; - time_t timeout; - int ret; - - if (status != LDB_SUCCESS) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } - - timeout = SSS_CLI_SOCKET_TIMEOUT/2; - - if (preq->check_provider) { - switch (res->count) { - case 0: - call_provider = true; - break; - - case 1: - cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_CACHE_EXPIRE, 0); - if (cacheExpire < time(NULL)) { - call_provider = true; - } - break; - - default: - DEBUG(1, ("check user call returned more than one result !?!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } - } - - if (call_provider) { - - /* dont loop forever :-) */ - preq->check_provider = false; - - /* keep around current data in case backend is offline */ - if (res->count) { - preq->data = talloc_steal(preq, res); - } - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, preq, - timeout, preq->domain->name, - false, SSS_DP_USER, - preq->pd->user, 0); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } - return; - } - - switch (res->count) { - case 0: - if (!preq->pd->domain) { - /* search next as the domain was unknown */ - - ret = EOK; - - /* skip domains that require FQnames or have negative caches */ - for (dom = preq->domain->next; dom; dom = dom->next) { - - if (dom->fqnames) continue; - -#if HAVE_NEG_CACHE - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; -#endif - break; - } -#if HAVE_NEG_CACHE - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", - cmdctx->name)); - ret = ENOENT; - } -#endif - if (dom == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", - preq->pd->user)); - ret = ENOENT; - } - - if (ret == EOK) { - preq->domain = dom; - preq->data = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - preq->pd->user, preq->domain->name)); - - /* When auth is requested always search the provider first, - * do not rely on cached data unless the provider is - * completely offline */ - if (NEED_CHECK_PROVIDER(preq->domain->provider) && - (preq->pd->cmd == SSS_PAM_AUTHENTICATE || - preq->pd->cmd == SSS_PAM_SETCRED)) { - - /* no need to re-check later on */ - preq->check_provider = false; - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, - preq, timeout, - preq->domain->name, - false, SSS_DP_USER, - preq->pd->user, 0); - } - else { - preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider); - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); - } - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } - - /* we made another call, end here */ - if (ret == EOK) return; - } - else { - ret = ENOENT; - } - - DEBUG(2, ("No results for check user call\n")); - -#if HAVE_NEG_CACHE - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_user(nctx->ncache, false, - dctx->domain->name, cmdctx->name); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } -#endif - - if (ret != EOK) { - if (ret == ENOENT) { - preq->pd->pam_status = PAM_USER_UNKNOWN; - } else { - preq->pd->pam_status = PAM_SYSTEM_ERR; - } - pam_reply(preq); - return; - } - break; - - case 1: - - /* BINGO */ - preq->pd->pw_uid = - ldb_msg_find_attr_as_int(res->msgs[0], SYSDB_UIDNUM, -1); - if (preq->pd->pw_uid == -1) { - DEBUG(1, ("Failed to find uid for user [%s] in domain [%s].\n", - preq->pd->user, preq->pd->domain)); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } - - preq->pd->gr_gid = - ldb_msg_find_attr_as_int(res->msgs[0], SYSDB_GIDNUM, -1); - if (preq->pd->gr_gid == -1) { - DEBUG(1, ("Failed to find gid for user [%s] in domain [%s].\n", - preq->pd->user, preq->pd->domain)); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } - - pam_dom_forwarder(preq); - return; - - default: - DEBUG(1, ("check user call returned more than one result !?!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } -} - -static void pam_dom_forwarder(struct pam_auth_req *preq) -{ - int ret; - - if (!preq->pd->domain) { - preq->pd->domain = preq->domain->name; - } - - if (!NEED_CHECK_PROVIDER(preq->domain->provider)) { - preq->callback = pam_reply; - ret = LOCAL_pam_handler(preq); - } - else { - preq->callback = pam_reply; - ret = pam_dp_send_req(preq, SSS_CLI_SOCKET_TIMEOUT/2); - DEBUG(4, ("pam_dp_send_req returned %d\n", ret)); - } - - if (ret != EOK) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } -} - -static int pam_cmd_authenticate(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_authenticate\n")); - return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE); -} - -static int pam_cmd_setcred(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_setcred\n")); - return pam_forwarder(cctx, SSS_PAM_SETCRED); -} - -static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_acct_mgmt\n")); - return pam_forwarder(cctx, SSS_PAM_ACCT_MGMT); -} - -static int pam_cmd_open_session(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_open_session\n")); - return pam_forwarder(cctx, SSS_PAM_OPEN_SESSION); -} - -static int pam_cmd_close_session(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_close_session\n")); - return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION); -} - -static int pam_cmd_chauthtok(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_chauthtok\n")); - return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK); -} - -static int pam_cmd_chauthtok_prelim(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_chauthtok_prelim\n")); - return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK_PRELIM); -} - -struct cli_protocol_version *register_cli_protocol_version(void) -{ - static struct cli_protocol_version pam_cli_protocol_version[] = { - {3, "2009-09-14", "make cli_pid mandatory"}, - {2, "2009-05-12", "new format <type><size><data>"}, - {1, "2008-09-05", "initial version, \\0 terminated strings"}, - {0, NULL, NULL} - }; - - return pam_cli_protocol_version; -} - -struct sss_cmd_table *get_pam_cmds(void) -{ - static struct sss_cmd_table sss_cmds[] = { - {SSS_GET_VERSION, sss_cmd_get_version}, - {SSS_PAM_AUTHENTICATE, pam_cmd_authenticate}, - {SSS_PAM_SETCRED, pam_cmd_setcred}, - {SSS_PAM_ACCT_MGMT, pam_cmd_acct_mgmt}, - {SSS_PAM_OPEN_SESSION, pam_cmd_open_session}, - {SSS_PAM_CLOSE_SESSION, pam_cmd_close_session}, - {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok}, - {SSS_PAM_CHAUTHTOK_PRELIM, pam_cmd_chauthtok_prelim}, - {SSS_CLI_NULL, NULL} - }; - - return sss_cmds; -} diff --git a/server/responder/pam/pamsrv_dp.c b/server/responder/pam/pamsrv_dp.c deleted file mode 100644 index 071d09b8e..000000000 --- a/server/responder/pam/pamsrv_dp.c +++ /dev/null @@ -1,142 +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 <talloc.h> -#include <security/pam_modules.h> - -#include "util/util.h" -#include "responder/common/responder_packet.h" -#include "providers/data_provider.h" -#include "sbus/sbus_client.h" -#include "responder/pam/pamsrv.h" - -static void pam_dp_process_reply(DBusPendingCall *pending, void *ptr) -{ - DBusError dbus_error; - DBusMessage* msg; - int ret; - int type; - struct pam_auth_req *preq; - - preq = talloc_get_type(ptr, struct pam_auth_req); - - dbus_error_init(&dbus_error); - - dbus_pending_call_block(pending); - msg = dbus_pending_call_steal_reply(pending); - if (msg == NULL) { - DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - - - type = dbus_message_get_type(msg); - switch (type) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - ret = dp_unpack_pam_response(msg, preq->pd, &dbus_error); - if (!ret) { - DEBUG(0, ("Failed to parse reply.\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - DEBUG(4, ("received: [%d][%s]\n", preq->pd->pam_status, preq->pd->domain)); - break; - case DBUS_MESSAGE_TYPE_ERROR: - DEBUG(0, ("Reply error.\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - break; - default: - DEBUG(0, ("Default... what now?.\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - } - - -done: - dbus_pending_call_unref(pending); - dbus_message_unref(msg); - preq->callback(preq); -} - -int pam_dp_send_req(struct pam_auth_req *preq, int timeout) -{ - struct pam_data *pd = preq->pd; - struct be_conn *be_conn; - DBusMessage *msg; - DBusPendingCall *pending_reply; - DBusConnection *dbus_conn; - dbus_bool_t ret; - int res; - - /* double check dp_ctx has actually been initialized. - * in some pathological cases it may happen that nss starts up before - * dp connection code is actually able to establish a connection. - */ - res = sss_dp_get_domain_conn(preq->cctx->rctx, - preq->domain->name, &be_conn); - if (res != EOK) { - DEBUG(1, ("The Data Provider connection for %s is not available!" - " This maybe a bug, it shouldn't happen!\n", preq->domain)); - return EIO; - } - dbus_conn = sbus_get_connection(be_conn->conn); - - msg = dbus_message_new_method_call(NULL, - DP_PATH, - DP_INTERFACE, - DP_METHOD_PAMHANDLER); - if (msg == NULL) { - DEBUG(0,("Out of memory?!\n")); - return ENOMEM; - } - - - DEBUG(4, ("Sending request with the following data:\n")); - DEBUG_PAM_DATA(4, pd); - - ret = dp_pack_pam_request(msg, pd); - if (!ret) { - DEBUG(1,("Failed to build message\n")); - return EIO; - } - - ret = dbus_connection_send_with_reply(dbus_conn, msg, &pending_reply, timeout); - if (!ret || pending_reply == NULL) { - /* - * 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; - } - - dbus_pending_call_set_notify(pending_reply, - pam_dp_process_reply, preq, NULL); - dbus_message_unref(msg); - - return EOK; -} - |