summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/Makefile.in13
-rw-r--r--server/infopipe/infopipe.c256
-rw-r--r--server/infopipe/infopipe.h3
-rw-r--r--server/infopipe/infopipe_private.h64
-rw-r--r--server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml2
-rw-r--r--server/infopipe/org.freeipa.sssd.infopipe.conf1
-rw-r--r--server/server.mk7
-rw-r--r--server/tests/infopipe-tests.c320
-rw-r--r--server/util/usertools.c35
-rw-r--r--server/util/util.h3
10 files changed, 696 insertions, 8 deletions
diff --git a/server/Makefile.in b/server/Makefile.in
index f281ba41f..1cde271ef 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -96,7 +96,9 @@ ifneq (x$(HAVE_POLICYKIT), x)
LIBEXECBINS += sbin/sssd_pk
endif
BINS = sbin/sssd $(LIBEXECBINS)
-TESTS = tests/sysdb-tests
+
+TESTS = tests/sysdb-tests tests/infopipe-tests
+TESTS_DATA = tests/tests.ldb tests/tests_conf.ldb tests/introspect.ref
SOLIBS = lib/$(MEMBEROF_SOLIB) lib/$(PROXY_BE_SOLIB)
SONAMELIBS = lib/$(PROXY_BE_SONAME) lib/$(MEMBEROF_SONAME)
@@ -109,15 +111,15 @@ all: showflags dirs $(OBJS) $(BINS) $(SOBASELIBS)
shared-build: all
tests: all $(TESTS)
+ cp $(INFP_INTROSPECT_XML) tests/introspect.ref
dirs:
@mkdir -p $(DIRS)
-clean::
+clean:: testclean
rm -f $(OBJS) $(BINS) $(MODULES)
rm -f *.o */*.o */*/*.o
- rm -f $(BINS) $(TESTS)
- rm -f $(BINS) $(TESTS)
+ rm -f $(BINS)
rm -f $(SOBASELIBS) $(SONAMELIBS) $(SOLIBS)
distclean:: clean
@@ -128,6 +130,9 @@ distclean:: clean
realdistclean:: distclean
rm -f configure config.h.in
+testclean::
+ rm -f $(TESTS) $(TESTS_DATA)
+
install:: all installdirs installheaders installlibs installbin installsupport
${INSTALLCMD} -d $(DESTDIR)$(sbindir)
${INSTALLCMD} -m 755 sbin/sssd $(DESTDIR)$(sbindir)
diff --git a/server/infopipe/infopipe.c b/server/infopipe/infopipe.c
index 9c129d26e..80b1bef0a 100644
--- a/server/infopipe/infopipe.c
+++ b/server/infopipe/infopipe.c
@@ -29,7 +29,8 @@
#include "monitor/monitor_sbus.h"
#include "monitor/monitor_interfaces.h"
#include "infopipe/sysbus.h"
-#include "infopipe.h"
+#include "infopipe/infopipe.h"
+#include "infopipe/infopipe_private.h"
struct infp_ctx {
struct event_context *ev;
@@ -127,12 +128,13 @@ static int infp_monitor_init(struct infp_ctx *infp_ctx)
}
struct sbus_method infp_methods[] = {
+ INFP_PERMISSION_METHODS
INFP_USER_METHODS
INFP_GROUP_METHODS
{ NULL, NULL }
};
-#define INTROSPECT_CHUNK_SIZE 128
+#define INTROSPECT_CHUNK_SIZE 4096 /* Read in one memory page at a time */
int infp_introspect(DBusMessage *message, struct sbus_message_ctx *reply)
{
@@ -250,9 +252,257 @@ static int infp_process_init(TALLOC_CTX *mem_ctx,
return ret;
}
+int 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 get_action_type(const char *action)
+{
+ int action_type = INFP_ACTION_TYPE_INVALID;
+
+ 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 get_attribute_type(const char *attribute)
+{
+ int attribute_type = 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 *username,
+ const char *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(username, "root") == 0)
+ return true;
+ return false;
+}
+
+/* CheckPermissions(STRING domain, STRING object, STRING instance
+ * ARRAY(STRING action_type, STRING attribute) actions)
+ */
int infp_check_permissions(DBusMessage *message, struct sbus_message_ctx *reply)
{
- reply->reply_message = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, "Not yet implemented");
+ TALLOC_CTX *tmp_ctx;
+ int current_type;
+ DBusConnection *conn;
+ const char *conn_name;
+ uid_t uid;
+ char *username;
+ DBusMessageIter iter;
+ DBusMessageIter action_array_iter;
+ DBusMessageIter action_struct_iter;
+ DBusError error;
+ int object_type;
+ const char *einval_msg;
+ const char *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(reply);
+ if(tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ /* Get the connection UID */
+ conn = sbus_get_connection(reply->mh_ctx->conn_ctx);
+ conn_name = dbus_message_get_sender(message);
+ if (conn_name == NULL) {
+ DEBUG(0, ("Critical error: D-BUS client has no unique name\n"));
+ return EIO;
+ }
+ dbus_error_init(&error);
+ uid = dbus_bus_get_unix_user(conn, conn_name, &error);
+ if (uid == -1) {
+ DEBUG(0, ("Could not identify unix user. Error message was '%s:%s'\n", error.name, error.message));
+ dbus_error_free(&error);
+ return EIO;
+ }
+ username = get_username_from_uid(tmp_ctx, uid);
+ if (username == NULL) {
+ DEBUG(0, ("No username matched the connected UID\n"));
+ 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);
+ DEBUG(9, ("Domain: %s\n", domain));
+
+ /* 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 = 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;
+ 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 = 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 = 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(username, domain,
+ object_type, instance,
+ action_type, attribute_type);
+
+ dbus_message_iter_next(&action_array_iter);
+ }
+
+ /* Create response message */
+ reply->reply_message = dbus_message_new_method_return(message);
+ if (reply->reply_message == NULL) return ENOMEM;
+
+ talloc_steal(reply, permissions);
+ dbus_message_append_args(reply->reply_message,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &permissions, count,
+ DBUS_TYPE_INVALID);
+
+ talloc_free(tmp_ctx);
+ return EOK;
+
+einval:
+ talloc_steal(reply, einval_msg);
+ reply->reply_message = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, einval_msg);
+ talloc_free(tmp_ctx);
return EOK;
}
diff --git a/server/infopipe/infopipe.h b/server/infopipe/infopipe.h
index 83a3d8d42..9db5c0d16 100644
--- a/server/infopipe/infopipe.h
+++ b/server/infopipe/infopipe.h
@@ -55,6 +55,9 @@ int infp_introspect(DBusMessage *message, struct sbus_message_ctx *reply);
#define INFP_CHECK_PERMISSIONS "CheckPermissions1"
int infp_check_permissions(DBusMessage *message, struct sbus_message_ctx *reply);
+#define INFP_PERMISSION_METHODS \
+ {INFP_CHECK_PERMISSIONS,infp_check_permissions},
+
/**********************************************************
* User Methods (from infopipe_users.c) *
**********************************************************/
diff --git a/server/infopipe/infopipe_private.h b/server/infopipe/infopipe_private.h
new file mode 100644
index 000000000..afac334b6
--- /dev/null
+++ b/server/infopipe/infopipe_private.h
@@ -0,0 +1,64 @@
+/*
+ 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/>.
+*/
+
+#ifndef INFOPIPE_PRIVATE_H_
+#define INFOPIPE_PRIVATE_H_
+
+enum object_types {
+ INFP_OBJ_TYPE_INVALID = 0,
+ INFP_OBJ_TYPE_USER,
+ INFP_OBJ_TYPE_GROUP
+};
+int get_object_type(const char *obj);
+
+enum action_types {
+ INFP_ACTION_TYPE_INVALID = 0,
+ INFP_ACTION_TYPE_CREATE,
+ INFP_ACTION_TYPE_DELETE,
+ INFP_ACTION_TYPE_MODIFY,
+ INFP_ACTION_TYPE_ADDMEMBER,
+ INFP_ACTION_TYPE_REMOVEMEMBER
+};
+int get_action_type(const char *action);
+
+enum attribute_types {
+ INFP_ATTR_TYPE_INVALID = 0,
+ INFP_ATTR_TYPE_DEFAULTGROUP,
+ INFP_ATTR_TYPE_GECOS,
+ INFP_ATTR_TYPE_HOMEDIR,
+ INFP_ATTR_TYPE_SHELL,
+ INFP_ATTR_TYPE_FULLNAME,
+ INFP_ATTR_TYPE_LOCALE,
+ INFP_ATTR_TYPE_KEYBOARD,
+ INFP_ATTR_TYPE_SESSION,
+ INFP_ATTR_TYPE_LAST_LOGIN,
+ INFP_ATTR_TYPE_USERPIC
+};
+int get_attribute_type(const char *attribute);
+
+bool infp_get_permissions(const char *username,
+ const char *domain,
+ int object_type,
+ const char *instance,
+ int action_type,
+ int action_attribute);
+
+#endif /* INFOPIPE_PRIVATE_H_ */
diff --git a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
index 5c50cfe8c..412206068 100644
--- a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
+++ b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
@@ -123,7 +123,7 @@
defaultgroup(STRING)
gecos(STRING)
homedir(STRING)
- shell(STRSING)
+ shell(STRING)
fullname(STRING)
locale(STRING)
keyboard(STRING)
diff --git a/server/infopipe/org.freeipa.sssd.infopipe.conf b/server/infopipe/org.freeipa.sssd.infopipe.conf
index b9ca55884..2ed3cf1b5 100644
--- a/server/infopipe/org.freeipa.sssd.infopipe.conf
+++ b/server/infopipe/org.freeipa.sssd.infopipe.conf
@@ -16,6 +16,7 @@
<!-- Right now, this will be handled by a limited ACL
within the InfoPipe Daemon. -->
<policy context="default">
+ <allow own="org.freeipa.sssd.infopipe1.test"/>
<allow send_interface="org.freeipa.sssd.infopipe1"/>
</policy>
diff --git a/server/server.mk b/server/server.mk
index b37be9fae..744dc243d 100644
--- a/server/server.mk
+++ b/server/server.mk
@@ -4,6 +4,7 @@ UTIL_OBJ = \
util/server.o \
util/memory.o \
util/btreemap.o \
+ util/usertools.o \
monitor/monitor_sbus.o \
providers/dp_sbus.o \
sbus/sssd_dbus_common.o \
@@ -47,6 +48,9 @@ MEMBEROF_OBJ = \
SYSDB_TEST_OBJ = \
tests/sysdb-tests.o
+INFP_TEST_OBJ = \
+ tests/infopipe-tests.o
+
sbin/sssd: $(SERVER_OBJ) $(UTIL_OBJ)
$(CC) -o sbin/sssd $(SERVER_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS)
@@ -76,3 +80,6 @@ lib/$(MEMBEROF_SOBASE): $(MEMBEROF_OBJ)
#Tests
tests/sysdb-tests: $(SYSDB_TEST_OBJ) $(UTIL_OBJ)
$(CC) -o tests/sysdb-tests $(SYSDB_TEST_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS) $(CHECK_LIBS)
+
+tests/infopipe-tests: $(INFP_TEST_OBJ) $(UTIL_OBJ)
+ $(CC) -o tests/infopipe-tests $(INFP_TEST_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS) $(CHECK_LIBS)
diff --git a/server/tests/infopipe-tests.c b/server/tests/infopipe-tests.c
new file mode 100644
index 000000000..2aaa653a6
--- /dev/null
+++ b/server/tests/infopipe-tests.c
@@ -0,0 +1,320 @@
+/*
+ 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/>.
+*/
+
+#include <stdlib.h>
+#include <check.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <popt.h>
+#include <dbus/dbus.h>
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "sbus/sssd_dbus.h"
+#include "infopipe/infopipe.h"
+
+#define INFP_TEST_DBUS_NAME "org.freeipa.sssd.infopipe1.test"
+#define TEST_TIMEOUT 30000 /* 30 seconds */
+
+static int setup_infp_tests(DBusConnection **bus)
+{
+ DBusError error;
+ int ret;
+
+ /* Connect to the system bus */
+ dbus_error_init(&error);
+ *bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (*bus == NULL) {
+ fail("Could not connect to the system bus. %s:%s", error.name, error.message);
+ dbus_error_free(&error);
+ return EIO;
+ }
+
+ /* Abort the tests if disconnect occurs */
+ dbus_connection_set_exit_on_disconnect(*bus, TRUE);
+
+ ret = dbus_bus_request_name(*bus,
+ INFP_TEST_DBUS_NAME,
+ /* We want exclusive access */
+ DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ &error);
+ if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ /* We were unable to register on the system bus */
+ fail("Unable to request name on the system bus. Error: %s:%s\n", error.name, error.message);
+ dbus_error_free(&error);
+ return EIO;
+ }
+ return EOK;
+}
+
+static int teardown_infp_tests(DBusConnection *bus)
+{
+ dbus_connection_unref(bus);
+ return EOK;
+}
+
+#define INTROSPECT_CHUNK_SIZE 4096
+START_TEST(test_infp_introspect)
+{
+ TALLOC_CTX *tmp_ctx;
+ DBusConnection *bus;
+ DBusError error;
+ DBusMessage *introspect_req;
+ DBusMessage *reply;
+ FILE *xml_stream;
+ char *chunk;
+ char *introspect_xml;
+ char *returned_xml;
+ unsigned long xml_size;
+ size_t chunk_size;
+ int type;
+
+ if (setup_infp_tests(&bus) != EOK) {
+ fail("Could not set up the tests");
+ return;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ fail("Could not create temporary talloc context");
+ goto done;
+ }
+
+ /* Create introspection method call */
+ introspect_req = dbus_message_new_method_call(INFOPIPE_DBUS_NAME,
+ INFOPIPE_PATH,
+ DBUS_INTROSPECT_INTERFACE,
+ DBUS_INTROSPECT_METHOD);
+ if(!introspect_req) {
+ fail("Could not create new method call message");
+ goto done;
+ }
+
+ /* Send the message */
+ dbus_error_init(&error);
+ reply = dbus_connection_send_with_reply_and_block(bus,
+ introspect_req,
+ TEST_TIMEOUT,
+ &error);
+ if(!reply) {
+ fail("Could not send message. Error: %s:%s", error.name, error.message);
+ dbus_error_free(&error);
+ goto done;
+ }
+
+ type = dbus_message_get_type(reply);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ /* Read in the reference Introspection XML */
+ xml_stream = fopen("introspect.ref", "r");
+ if(xml_stream == NULL) {
+ DEBUG(0, ("Could not open the introspection XML for reading: [%d].\n", errno));
+ return;
+ }
+
+ chunk = talloc_size(tmp_ctx, INTROSPECT_CHUNK_SIZE);
+ if (chunk == NULL) goto done;
+
+ xml_size = 0;
+ introspect_xml = NULL;
+ do {
+ chunk_size = fread(chunk, 1, INTROSPECT_CHUNK_SIZE, xml_stream);
+ introspect_xml = talloc_realloc_size(tmp_ctx, introspect_xml, xml_size+chunk_size+1);
+ if (introspect_xml == NULL) goto done;
+
+ memcpy(introspect_xml+xml_size, chunk, chunk_size);
+ xml_size += chunk_size;
+ } while(chunk_size == INTROSPECT_CHUNK_SIZE);
+ introspect_xml[xml_size] = '\0';
+ talloc_free(chunk);
+
+ /* Get the XML from the message */
+ dbus_message_get_args(reply, &error,
+ DBUS_TYPE_STRING, &returned_xml,
+ DBUS_TYPE_INVALID);
+
+ /* Verify that the reply matches the reference file */
+ if (strcmp(introspect_xml, returned_xml) != 0) {
+ fail("Verify Introspection XML: FAILED");
+ }
+ break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ fail("Error: %s\n", dbus_message_get_error_name(reply));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ teardown_infp_tests(bus);
+}
+END_TEST
+
+START_TEST(test_infp_check_permissions)
+{
+ TALLOC_CTX *tmp_ctx;
+ DBusConnection *bus;
+ DBusError error;
+ DBusMessage *permission_req;
+ DBusMessage *reply;
+ DBusMessageIter msg_iter;
+ DBusMessageIter array_iter;
+ DBusMessageIter struct_iter;
+ dbus_bool_t *permission_array;
+ int permission_count;
+ char *domain;
+ char *object;
+ char *instance;
+ char *action;
+ char *attribute;
+ int type, i;
+
+ if (setup_infp_tests(&bus) != EOK) {
+ fail("Could not set up the tests");
+ return;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ fail("Could not create temporary talloc context");
+ goto done;
+ }
+
+ /* Create permission request message */
+ permission_req = dbus_message_new_method_call(INFOPIPE_DBUS_NAME,
+ INFOPIPE_PATH,
+ INFOPIPE_INTERFACE,
+ INFP_CHECK_PERMISSIONS);
+ if(!permission_req) {
+ fail("Could not create new method call message");
+ goto done;
+ }
+
+ /* Add arguments */
+ domain = talloc_strdup(tmp_ctx, "LOCAL");
+ object = talloc_strdup(tmp_ctx, "user");
+ instance = talloc_strdup(tmp_ctx, "testuser1");
+ action = talloc_strdup(tmp_ctx, "modify");
+ attribute = talloc_strdup(tmp_ctx, "userpic");
+
+ dbus_message_append_args(permission_req,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_STRING, &object,
+ DBUS_TYPE_STRING, &instance,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_iter_init_append(permission_req, &msg_iter);
+ dbus_message_iter_open_container(&msg_iter,
+ DBUS_TYPE_ARRAY, "(ss)", /* Array of structs */
+ &array_iter);
+ dbus_message_iter_open_container(&array_iter,
+ DBUS_TYPE_STRUCT, NULL,
+ &struct_iter);
+ dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &action);
+ dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &attribute);
+ dbus_message_iter_close_container(&array_iter, &struct_iter);
+ dbus_message_iter_close_container(&msg_iter, &array_iter);
+
+
+ /* Send the message */
+ dbus_error_init(&error);
+ reply = dbus_connection_send_with_reply_and_block(bus,
+ permission_req,
+ TEST_TIMEOUT,
+ &error);
+ if(!reply) {
+ fail("Could not send message. Error: %s:%s", error.name, error.message);
+ dbus_error_free(&error);
+ goto done;
+ }
+
+ type = dbus_message_get_type(reply);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_ERROR:
+ fail("Error: %s\n", dbus_message_get_error_name(reply));
+ goto done;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ dbus_message_get_args(reply, &error,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &permission_array, &permission_count,
+ DBUS_TYPE_INVALID);
+ }
+
+ i = 0;
+ while(i < permission_count) {
+ if (permission_array[i] == true) {
+ fail("User was granted permission unexpectedly");
+ goto done;
+ }
+ i++;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ teardown_infp_tests(bus);
+}
+END_TEST
+
+Suite *create_infopipe_suite(void)
+{
+ Suite *s = suite_create("infopipe");
+
+ TCase *tc_infp = tcase_create("InfoPipe Tests");
+
+ /* Test the Introspection XML */
+ tcase_add_test(tc_infp, test_infp_introspect);
+ tcase_add_test(tc_infp, test_infp_check_permissions);
+
+/* Add all test cases to the test suite */
+ suite_add_tcase(s, tc_infp);
+
+ return s;
+}
+
+int main(int argc, const char *argv[]) {
+ int opt;
+ poptContext pc;
+ int failure_count;
+ Suite *infopipe_suite;
+ SRunner *sr;
+
+ 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);
+
+ infopipe_suite = create_infopipe_suite();
+ sr = srunner_create(infopipe_suite);
+ srunner_run_all(sr, CK_VERBOSE);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (failure_count==0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/server/util/usertools.c b/server/util/usertools.c
new file mode 100644
index 000000000..079306134
--- /dev/null
+++ b/server/util/usertools.c
@@ -0,0 +1,35 @@
+/*
+ SSSD
+
+ User tools
+
+ 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/>.
+*/
+
+#include <pwd.h>
+#include <talloc.h>
+
+char *get_username_from_uid(TALLOC_CTX *mem_ctx, uid_t uid)
+{
+ char *username;
+ struct passwd *pwd;
+
+ pwd = getpwuid(uid);
+ if (!pwd) return NULL;
+
+ username = talloc_strdup(mem_ctx, pwd->pw_name);
+ return username;
+}
diff --git a/server/util/util.h b/server/util/util.h
index 1c3fa2e77..7388febd6 100644
--- a/server/util/util.h
+++ b/server/util/util.h
@@ -65,4 +65,7 @@ TALLOC_CTX *sssd_mem_takeover(TALLOC_CTX *mem_ctx,
void *ptr,
int (*destructor)(void **));
+/* from usertools.c */
+char *get_username_from_uid(TALLOC_CTX *mem_ctx, uid_t uid);
+
#endif /* __SSSD_UTIL_H__ */