summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2009-02-24 12:02:05 -0500
committerSimo Sorce <idra@samba.org>2009-02-24 13:47:47 -0500
commitc14486feb47672a3562989ddb00653f58357e368 (patch)
tree92fe193ae916c95ae95654a55a7bdce45587aeac /server
parent795e12d8315c4f7f0d4b2abb77fb49e0417e362a (diff)
downloadsssd-c14486feb47672a3562989ddb00653f58357e368.tar.gz
sssd-c14486feb47672a3562989ddb00653f58357e368.tar.xz
sssd-c14486feb47672a3562989ddb00653f58357e368.zip
Adding support for CheckPermissions to InfoPipe.
CheckPermissions will currently return unrestricted access to the root user, and no access to any other user. Once we decide on an ACL mechanism, this will be easy to change. I have also added very basic tests for the Introspect and CheckPermissions methods.
Diffstat (limited to 'server')
-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__ */