diff options
Diffstat (limited to 'server/infopipe/infopipe.c')
-rw-r--r-- | server/infopipe/infopipe.c | 748 |
1 files changed, 0 insertions, 748 deletions
diff --git a/server/infopipe/infopipe.c b/server/infopipe/infopipe.c deleted file mode 100644 index 72998301..00000000 --- a/server/infopipe/infopipe.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - SSSD - - InfoPipe - - Copyright (C) Stephen Gallagher <sgallagh@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/>. -*/ -#define _GNU_SOURCE -#include <stdlib.h> -#include <stdio.h> -#include "popt.h" -#include "util/util.h" -#include "util/btreemap.h" -#include "sbus/sssd_dbus.h" -#include "sbus/sbus_client.h" -#include "db/sysdb.h" -#include "confdb/confdb.h" -#include "monitor/monitor_sbus.h" -#include "monitor/monitor_interfaces.h" -#include "infopipe/sysbus.h" -#include "infopipe/infopipe.h" -#include "infopipe/infopipe_private.h" - -#define INFP_CONF_ENTRY "config/services/info" - -static int service_identity(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - dbus_uint16_t version = INFOPIPE_VERSION; - const char *name = INFOPIPE_SERVICE_NAME; - DBusMessage *reply; - dbus_bool_t ret; - - DEBUG(4, ("Sending identity data [%s,%d]\n", name, version)); - - reply = dbus_message_new_method_return(message); - if (!reply) return ENOMEM; - - ret = dbus_message_append_args(reply, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT16, &version, - DBUS_TYPE_INVALID); - if (!ret) { - dbus_message_unref(reply); - return EIO; - } - - /* send reply back */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - return EOK; -} - -static int service_pong(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply; - dbus_bool_t ret; - - reply = dbus_message_new_method_return(message); - if (!reply) return ENOMEM; - - ret = dbus_message_append_args(reply, DBUS_TYPE_INVALID); - if (!ret) { - dbus_message_unref(reply); - return EIO; - } - - /* send reply back */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - return EOK; -} - -static int service_reload(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - /* Monitor calls this function when we need to reload - * our configuration information. Perform whatever steps - * are needed to update the configuration objects. - */ - - /* Send an empty reply to acknowledge receipt */ - return service_pong(message, sconn); -} - -struct sbus_method mon_sbus_methods[] = { - { SERVICE_METHOD_IDENTITY, service_identity }, - { SERVICE_METHOD_PING, service_pong }, - { SERVICE_METHOD_RELOAD, service_reload }, - { NULL, NULL } -}; - -static int infp_monitor_init(struct infp_ctx *infp_ctx) -{ - int ret; - char *sbus_address; - struct service_sbus_ctx *ss_ctx; - struct sbus_method_ctx *sm_ctx; - - /* Set up SBUS connection to the monitor */ - ret = monitor_get_sbus_address(infp_ctx, infp_ctx->cdb, &sbus_address); - if (ret != EOK) { - DEBUG(0, ("Could not locate monitor address.\n")); - return ret; - } - - ret = monitor_init_sbus_methods(infp_ctx, mon_sbus_methods, &sm_ctx); - if (ret != EOK) { - DEBUG(0, ("Could not initialize SBUS methods.\n")); - return ret; - } - - ret = sbus_client_init(infp_ctx, infp_ctx->ev, - sbus_address, sm_ctx, - NULL /* Private Data */, - NULL /* Destructor */, - &ss_ctx); - if (ret != EOK) { - DEBUG(0, ("Failed to connect to monitor services.\n")); - return ret; - } - - /* Set up InfoPipe-specific listeners */ - /* None currently used */ - - infp_ctx->ss_ctx = ss_ctx; - - return EOK; -} - -/* Helper function to return an immediate error message in the event - * of internal error in the InfoPipe to avoid forcing the clients to - * time out waiting for a reply. - * This function will make a best effort to send a reply, but if it - * fails, clients will simply have to handle the timeout. - */ -void infp_return_failure(struct infp_req_ctx *infp_req, const char *message) -{ - DBusMessage *reply; - - if(infp_req == NULL) return; - - reply = dbus_message_new_error(infp_req->req_message, - DBUS_ERROR_FAILED, - message); - /* If the reply was NULL, we ran out of memory, so we won't - * bother trying to queue the message to send. In this case, - * our safest move is to allow the client to time out waiting - * for a reply. - */ - if(reply) { - sbus_conn_send_reply(infp_req->sconn, reply); - dbus_message_unref(reply); - } -} - -/* Helper function to return an ack to the caller to indicate - * that the internal process completed succesfully. An ack in - * InfoPipe is simply an empty D-BUS method return (as opposed - * to a D-BUS error or signal) - */ -void infp_return_success(struct infp_req_ctx *infp_req) -{ - DBusMessage *reply; - - if (infp_req == NULL) return; - - reply = dbus_message_new_method_return(infp_req->req_message); - /* If the reply was NULL, we ran out of memory, so we won't - * bother trying to queue the message to send. In this case, - * our safest move is to allow the client to time out waiting - * for a reply. - */ - if(reply) { - sbus_conn_send_reply(infp_req->sconn, reply); - dbus_message_unref(reply); - } -} - -struct sbus_method infp_methods[] = { - INFP_PERMISSION_METHODS - INFP_USER_METHODS - INFP_GROUP_METHODS - { NULL, NULL } -}; - -int infp_introspect(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply; - FILE *xml_stream = NULL; - struct infp_ctx *infp; - long xml_size, read_size; - int ret; - dbus_bool_t dbret; - - infp = talloc_get_type(sbus_conn_get_private_data(sconn), struct infp_ctx); - - if (infp->introspect_xml == NULL) { - - /* Read in the Introspection XML the first time */ - xml_stream = fopen(SSSD_INTROSPECT_PATH"/"INFP_INTROSPECT_XML, "r"); - if(xml_stream == NULL) { - ret = errno; - DEBUG(0, ("Could not open [%s] for reading. [%d:%s]\n", - SSSD_INTROSPECT_PATH"/"INFP_INTROSPECT_XML, - ret, strerror(ret))); - return ret; - } - - if (fseek(xml_stream, 0L, SEEK_END) != 0) { - ret = errno; - DEBUG(0, ("Could not seek into [%s]. [%d:%s]\n", - SSSD_INTROSPECT_PATH"/"INFP_INTROSPECT_XML, - ret, strerror(ret))); - goto done; - } - - errno = 0; - xml_size = ftell(xml_stream); - if (xml_size <= 0) { - ret = errno; - DEBUG(0, ("Could not get [%s] length (or file is empty). [%d:%s]\n", - SSSD_INTROSPECT_PATH"/"INFP_INTROSPECT_XML, - ret, strerror(ret))); - goto done; - } - - if (fseek(xml_stream, 0L, SEEK_SET) != 0) { - ret = errno; - DEBUG(0, ("Could not seek into [%s]. [%d:%s]\n", - SSSD_INTROSPECT_PATH"/"INFP_INTROSPECT_XML, - ret, strerror(ret))); - goto done; - } - - infp->introspect_xml = talloc_size(infp, xml_size+1); - if (!(infp->introspect_xml)) { - ret = ENOMEM; - goto done; - } - - read_size = fread(infp->introspect_xml, 1, xml_size, xml_stream); - if (read_size < xml_size) { - if (!feof(xml_stream)) { - ret = ferror(xml_stream); - DEBUG(0, ("Error occurred while reading [%s]. [%d:%s]\n", - SSSD_INTROSPECT_PATH"/"INFP_INTROSPECT_XML, - ret, strerror(ret))); - - talloc_free(infp->introspect_xml); - infp->introspect_xml = NULL; - goto done; - } - } - - /* Copy the introspection XML to the infp_ctx */ - infp->introspect_xml[xml_size+1] = '\0'; - } - - /* Return the Introspection XML */ - reply = dbus_message_new_method_return(message); - if (reply == NULL) { - ret = ENOMEM; - goto done; - } - dbret = dbus_message_append_args(reply, - DBUS_TYPE_STRING, &infp->introspect_xml, - DBUS_TYPE_INVALID); - if (!dbret) { - ret = ENOMEM; - goto done; - } - - /* send reply back */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - DEBUG(9, ("%s\n", infp->introspect_xml)); - ret = EOK; - -done: - if (xml_stream) fclose(xml_stream); - return ret; -} - -struct infp_req_ctx *infp_req_init(TALLOC_CTX *mem_ctx, DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - struct infp_req_ctx *infp_req; - - /* Create an infp_req_ctx */ - infp_req = talloc_zero(mem_ctx, struct infp_req_ctx); - if (infp_req == NULL) { - return NULL; - } - - infp_req->infp = talloc_get_type(sbus_conn_get_private_data(sconn), struct infp_ctx); - infp_req->sconn = sconn; - infp_req->req_message = message; - infp_req->caller = sysbus_get_caller(infp_req, - infp_req->req_message, - infp_req->sconn); - if (infp_req->caller == NULL) { - talloc_free(infp_req); - return NULL; - } - - return infp_req; -} - -static int infp_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb) -{ - struct infp_ctx *infp_ctx; - int ret; - - infp_ctx = talloc_zero(mem_ctx, struct infp_ctx); - if (infp_ctx == NULL) { - DEBUG(0, ("Fatal error initializing infp_ctx\n")); - return ENOMEM; - } - infp_ctx->ev = ev; - infp_ctx->cdb = cdb; - - /* Connect to the monitor */ - ret = infp_monitor_init(infp_ctx); - if (ret != EOK) { - DEBUG(0, ("Fatal error setting up monitor bus\n")); - talloc_free(infp_ctx); - return EIO; - } - - /* Connect to the D-BUS system bus and set up methods */ - ret = sysbus_init(infp_ctx, &infp_ctx->sysbus, - infp_ctx->ev, INFOPIPE_DBUS_NAME, - INFOPIPE_INTERFACE, INFOPIPE_PATH, - infp_methods, infp_introspect); - if (ret != EOK) { - DEBUG(0, ("Failed to connect to the system message bus\n")); - talloc_free(infp_ctx); - return EIO; - } - - /* Connect to the sysdb */ - ret = sysdb_init(infp_ctx, infp_ctx->ev, infp_ctx->cdb, - NULL, &infp_ctx->sysdb); - if (ret != EOK) { - DEBUG(0, ("Failed to connect to the cache database\n")); - talloc_free(infp_ctx); - return EIO; - } - - /* Read in the domain map */ - ret = confdb_get_domains(cdb, infp_ctx, &infp_ctx->domains); - if (ret != EOK) { - DEBUG(0, ("Failed to populate the domain map\n")); - talloc_free(infp_ctx); - return EIO; - } - - infp_ctx->cache_timeout = 600; /* FIXME: read from confdb */ - - /* Add the infp_ctx to the sbus_conn_ctx private data - * so we can pass it into message handler functions - */ - sbus_conn_set_private_data(sysbus_get_sbus_conn(infp_ctx->sysbus), infp_ctx); - - return EOK; -} - -int infp_get_object_type(const char *obj) -{ - int object_type = INFP_OBJ_TYPE_INVALID; - - if (strcasecmp(obj, "user") == 0) - object_type = INFP_OBJ_TYPE_USER; - else if (strcasecmp(obj, "group") == 0) - object_type = INFP_OBJ_TYPE_GROUP; - - return object_type; -} - -int infp_get_action_type(const char *action) -{ - int action_type = INFP_ACTION_TYPE_INVALID; - - if (strcasecmp(action, "read") == 0) - action_type = INFP_ACTION_TYPE_READ; - else if (strcasecmp(action, "create") == 0) - action_type = INFP_ACTION_TYPE_CREATE; - else if ((strcasecmp(action, "delete") == 0)) - action_type = INFP_ACTION_TYPE_DELETE; - else if ((strcasecmp(action, "modify") == 0)) - action_type = INFP_ACTION_TYPE_MODIFY; - else if ((strcasecmp(action, "addmember") == 0)) - action_type = INFP_ACTION_TYPE_ADDMEMBER; - else if ((strcasecmp(action, "removemember") == 0)) - action_type = INFP_ACTION_TYPE_REMOVEMEMBER; - - return action_type; -} - -int infp_get_attribute_type(const char *attribute) -{ - int attribute_type = INFP_ATTR_TYPE_INVALID; - - if(attribute == NULL) - return INFP_ATTR_TYPE_INVALID; - - if(strcasecmp(attribute, "defaultgroup") == 0) - attribute_type = INFP_ATTR_TYPE_DEFAULTGROUP; - else if (strcasecmp(attribute, "gecos") == 0) { - attribute_type = INFP_ATTR_TYPE_GECOS; - } - else if (strcasecmp(attribute, "homedir") == 0) { - attribute_type = INFP_ATTR_TYPE_HOMEDIR; - } - else if (strcasecmp(attribute, "shell") == 0) { - attribute_type = INFP_ATTR_TYPE_SHELL; - } - else if (strcasecmp(attribute, "fullname") == 0) { - attribute_type = INFP_ATTR_TYPE_FULLNAME; - } - else if (strcasecmp(attribute, "locale") == 0) { - attribute_type = INFP_ATTR_TYPE_LOCALE; - } - else if (strcasecmp(attribute, "keyboard") == 0) { - attribute_type = INFP_ATTR_TYPE_KEYBOARD; - } - else if (strcasecmp(attribute, "session") == 0) { - attribute_type = INFP_ATTR_TYPE_SESSION; - } - else if (strcasecmp(attribute, "last_login") == 0) { - attribute_type = INFP_ATTR_TYPE_LAST_LOGIN; - } - else if (strcasecmp(attribute, "userpic") == 0) { - attribute_type = INFP_ATTR_TYPE_USERPIC; - } - - return attribute_type; -} - -bool infp_get_permissions(const char *caller, - struct sss_domain_info *domain, - int object_type, - const char *instance, - int action_type, - int action_attribute) -{ - /* TODO: have a real ACL mechanism. - * For right now, root is God and no one else can do anything. - * Note: this is buggy. It will return true for ALL requests, - * even the nonsensical ones. - */ - if (strcmp(caller, "root") == 0) - return true; - return false; -} - -struct sss_domain_info *infp_get_domain_obj(struct infp_ctx *infp, - const char *domain_name) -{ - struct sss_domain_info *dom; - - for (dom = infp->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, domain_name) == 0) break; - } - return dom; -} - -/* CheckPermissions(STRING domain, STRING object, STRING instance - * ARRAY(STRING action_type, STRING attribute) actions) - */ -int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply; - TALLOC_CTX *tmp_ctx; - struct infp_ctx *infp; - int current_type; - char *caller; - DBusMessageIter iter; - DBusMessageIter action_array_iter; - DBusMessageIter action_struct_iter; - int object_type; - const char *einval_msg; - const char *domain_name; - struct sss_domain_info *domain; - const char *object; - const char *instance; - const char *action; - const char *attribute; - int action_type, attribute_type; - dbus_bool_t *permissions; - size_t count; - - tmp_ctx = talloc_new(NULL); - if(tmp_ctx == NULL) { - return ENOMEM; - } - - infp = talloc_get_type(sbus_conn_get_private_data(sconn), struct infp_ctx); - - /* Get the caller */ - caller = sysbus_get_caller(tmp_ctx, message, sconn); - if (caller == NULL) { - return EIO; - } - - if (!dbus_message_iter_init(message, &iter)) { - einval_msg = talloc_strdup(tmp_ctx, "No arguments received."); - goto einval; - } - - /* domain */ - current_type = dbus_message_iter_get_arg_type (&iter); - if (current_type != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(tmp_ctx, "Expected domain"); - goto einval; - } - dbus_message_iter_get_basic(&iter, &domain_name); - DEBUG(9, ("Domain: %s\n", domain_name)); - domain = infp_get_domain_obj(infp, domain_name); - - /* Object */ - dbus_message_iter_next(&iter); - current_type = dbus_message_iter_get_arg_type (&iter); - if (current_type != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(tmp_ctx, "Expected object"); - goto einval; - } - dbus_message_iter_get_basic(&iter, &object); - DEBUG(9, ("Object: %s\n", object)); - object_type = infp_get_object_type(object); - if (object_type == INFP_OBJ_TYPE_INVALID) { - einval_msg = talloc_strdup(tmp_ctx, "Invalid object type"); - goto einval; - } - - /* Instance */ - dbus_message_iter_next(&iter); - current_type = dbus_message_iter_get_arg_type (&iter); - if (current_type != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(tmp_ctx, "Expected instance"); - goto einval; - } - dbus_message_iter_get_basic(&iter, &instance); - DEBUG(9, ("Instance: %s\n", instance)); - if(strcmp(instance,"")==0) { - instance = NULL; - } - - /* Actions */ - dbus_message_iter_next(&iter); - current_type = dbus_message_iter_get_arg_type (&iter); - if (current_type != DBUS_TYPE_ARRAY) { - einval_msg = talloc_strdup(tmp_ctx, "Expected array of actions"); - goto einval; - } - - dbus_message_iter_recurse(&iter, &action_array_iter); - count = 0; - permissions = NULL; - while((current_type=dbus_message_iter_get_arg_type(&action_array_iter)) != DBUS_TYPE_INVALID) { - if (current_type != DBUS_TYPE_STRUCT) { - einval_msg = talloc_strdup(tmp_ctx, "Action array entry was not a struct"); - goto einval; - } - dbus_message_iter_recurse(&action_array_iter, &action_struct_iter); - /* action_type */ - if (dbus_message_iter_get_arg_type(&action_struct_iter) != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(tmp_ctx, "Missing action_type"); - goto einval; - } - dbus_message_iter_get_basic(&action_struct_iter, &action); - DEBUG(9, ("Action type: %s\n", action)); - action_type = infp_get_action_type(action); - if(action_type == INFP_ACTION_TYPE_INVALID) { - einval_msg = talloc_asprintf(tmp_ctx, "Action type [%s] is not valid", action); - goto einval; - } - - /* attribute */ - dbus_message_iter_next(&action_struct_iter); - if (dbus_message_iter_get_arg_type(&action_struct_iter) != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(tmp_ctx, "Missing attribute"); - goto einval; - } - dbus_message_iter_get_basic(&action_struct_iter, &attribute); - DEBUG(9, ("Action attribute: %s\n", attribute)); - attribute_type = infp_get_attribute_type(attribute); - if(attribute_type == INFP_ATTR_TYPE_INVALID) { - einval_msg = talloc_asprintf(tmp_ctx, "Attribute [%s] is not valid", attribute); - goto einval; - } - - if (dbus_message_iter_has_next(&action_struct_iter)) { - einval_msg = talloc_strdup(tmp_ctx, "Unexpected value in action struct"); - goto einval; - } - - /* Process the actions */ - count++; - permissions=talloc_realloc(tmp_ctx, permissions, dbus_bool_t, count); - permissions[count-1] = infp_get_permissions(caller, domain, - object_type, instance, - action_type, attribute_type); - - dbus_message_iter_next(&action_array_iter); - } - - /* Create response message */ - reply = dbus_message_new_method_return(message); - if (reply == NULL) { - talloc_free(tmp_ctx); - return ENOMEM; - } - - dbus_message_append_args(reply, - DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &permissions, count, - DBUS_TYPE_INVALID); - - /* send reply back */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - talloc_free(tmp_ctx); - return EOK; - -einval: - reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, einval_msg); - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - talloc_free(tmp_ctx); - return EOK; -} - -int infp_get_ldb_val_from_dbus(TALLOC_CTX *mem_ctx, DBusMessageIter *iter, struct ldb_val **value, int dbus_type, int subtype) -{ - struct ldb_val *val = NULL; - void *tmp; - size_t element_size; - int num_elements; - int ret; - - val = talloc_zero(mem_ctx, struct ldb_val); - if (val == NULL) { - ret = ENOMEM; - goto done; - } - - /* Fixed-size types */ - if (sbus_is_dbus_fixed_type(dbus_type)) { - dbus_message_iter_get_basic(iter, &tmp); - val->length = sbus_get_dbus_type_size(dbus_type); - } - - else if (sbus_is_dbus_string_type(dbus_type)) { - dbus_message_iter_get_basic(iter, &tmp); - val->length = strlen((const char *)tmp); - } - - else if (dbus_type == DBUS_TYPE_ARRAY) { - if (!sbus_is_dbus_fixed_type(subtype)) { - ret = EINVAL; - goto done; - } - - element_size = sbus_get_dbus_type_size(subtype); - dbus_message_iter_get_fixed_array(iter, &tmp, &num_elements); - val->length = num_elements * element_size; - } - else { - /* Unsupported type */ - ret = EINVAL; - goto done; - } - - val->data = talloc_memdup(val, tmp, val->length); - if (val->data == NULL) { - ret = ENOMEM; - goto done; - } - - *value = val; - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(val); - *value = NULL; - } - return ret; -} - -int main(int argc, const char *argv[]) -{ - int opt; - poptContext pc; - struct main_context *main_ctx; - int ret; - - struct poptOption long_options[] = { - POPT_AUTOHELP - SSSD_MAIN_OPTS - { NULL } - }; - - pc = poptGetContext(argv[0], argc, argv, long_options, 0); - while((opt = poptGetNextOpt(pc)) != -1) { - switch(opt) { - default: - fprintf(stderr, "\nInvalid option %s: %s\n\n", - poptBadOption(pc, 0), poptStrerror(opt)); - poptPrintUsage(pc, stderr, 0); - return 1; - } - } - - poptFreeContext(pc); - - /* set up things like debug , signals, daemonization, etc... */ - ret = server_setup("sssd[info]", 0, INFP_CONF_ENTRY, &main_ctx); - if (ret != EOK) return 2; - - ret = infp_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; -} |