From 1c48b5a62f73234ed26bb20f0ab345ab61cda0ab Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Thu, 18 Feb 2010 07:49:04 -0500 Subject: Rename server/ directory to src/ Also update BUILD.txt --- src/responder/common/responder.h | 152 ++++++++ src/responder/common/responder_cmd.c | 103 ++++++ src/responder/common/responder_common.c | 589 +++++++++++++++++++++++++++++++ src/responder/common/responder_dp.c | 590 ++++++++++++++++++++++++++++++++ src/responder/common/responder_packet.c | 253 ++++++++++++++ src/responder/common/responder_packet.h | 43 +++ 6 files changed, 1730 insertions(+) create mode 100644 src/responder/common/responder.h create mode 100644 src/responder/common/responder_cmd.c create mode 100644 src/responder/common/responder_common.c create mode 100644 src/responder/common/responder_dp.c create mode 100644 src/responder/common/responder_packet.c create mode 100644 src/responder/common/responder_packet.h (limited to 'src/responder/common') diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h new file mode 100644 index 000000000..ea6ba5831 --- /dev/null +++ b/src/responder/common/responder.h @@ -0,0 +1,152 @@ +/* + SSSD + + SSS Client Responder, header file + + Copyright (C) Simo Sorce 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __SSS_RESPONDER_H__ +#define __SSS_RESPONDER_H__ + +#include +#include +#include +#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/src/responder/common/responder_cmd.c b/src/responder/common/responder_cmd.c new file mode 100644 index 000000000..cd9890305 --- /dev/null +++ b/src/responder/common/responder_cmd.c @@ -0,0 +1,103 @@ +/* + SSSD + + SSS Client Responder, command parser + + Copyright (C) Simo Sorce 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include "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/src/responder/common/responder_common.c b/src/responder/common/responder_common.c new file mode 100644 index 000000000..37bbcb30f --- /dev/null +++ b/src/responder/common/responder_common.c @@ -0,0 +1,589 @@ +/* + SSSD + + Common Responder methods + + Copyright (C) Simo Sorce 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "popt.h" +#include "util/util.h" +#include "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/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c new file mode 100644 index 000000000..782befb17 --- /dev/null +++ b/src/responder/common/responder_dp.c @@ -0,0 +1,590 @@ +/* + Authors: + Simo Sorce + Stephen Gallagher + + 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 . +*/ + + +#include +#include +#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/src/responder/common/responder_packet.c b/src/responder/common/responder_packet.c new file mode 100644 index 000000000..6e581a3c9 --- /dev/null +++ b/src/responder/common/responder_packet.c @@ -0,0 +1,253 @@ +/* + SSSD + + SSS Client Responder, command parser + + Copyright (C) Simo Sorce 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include "talloc.h" +#include "util/util.h" +#include "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/src/responder/common/responder_packet.h b/src/responder/common/responder_packet.h new file mode 100644 index 000000000..2bfdc8a32 --- /dev/null +++ b/src/responder/common/responder_packet.h @@ -0,0 +1,43 @@ +/* + SSSD + + SSS Client Responder, header file + + Copyright (C) Simo Sorce 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __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__ */ -- cgit