[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [Freeipa-devel] [PATCH][SSSD] Implement GetUserAttributes in the InfoPipe



Replies inline.

Simo Sorce wrote:
> Stephen,
> I think there is some work to do on the patch, as it is it will not work
> as, for example, the latest patches removed check_provider.
> (It's always true except for LOCAL, so I removed it in favor of checking
> explicitly for the domain name != LOCAL)

I like it the way I have it for now. When the infp_getattr_req is
created, I do the strcasecmp("LOCAL") and assign that to
infp_getattr_req, then I can just check the boolean value wherever I
need to. Much faster than doing another string compare. (And since
GetAttributes may call into the sysdb any number of times, depending on
how many users they are requesting, this is a definite optimization).

Also, for what it's worth, you are doing the same in nsssrv.c.

> 
> See some minor comments inline, but the general approach looks ok.
> 
> On Sun, 2009-03-01 at 15:19 -0500, Stephen Gallagher wrote:
>> This patch adds support for requesting user data in the sysdb via the
>> InfoPipe. It currently has support for reading defined entries of
>> integral, floating-point or string types.
> 
> Some comments:
> 
> - When you use btreemap_get_value() like in infp_get_domain_obj() you
> should probably use talloc_get_type() instead of doing a cast yourself,
> so that if something wrong comes out of it you get a null pointer and do
> not act on random data.

Fixed. I'm not sure why I did that. I usually use talloc_get_type().

> 
> - why in create_getattr_result_map() do you fetch uint64_t data but
> variant->data is cast to int ?

That was a mistake. I was tinkering with smaller integral types to
ensure that casting to other (and signed) types was working as expected.
I thought I had switched everything back to uint64_t. Fixed.

> 
> - In infp_get_all_attributes() why do you copy all these static strings?
> As far as I can see they are not manipulated in any way, but just used
> as is.

Only talloc pointers can be added to btreemaps because they steal the
reference (to make sure the data they hold doesn't disappear during the
tree's life). Passing a static string == a segfault (this was an
annoying bug to track down).

> 
> - I see that you added confdb/confbd.h to sysdb.h, but you also keep
> including them both explicitly in infopipe, any reason for this ?
> 
>> Tasks remaining:
>>     1) Implement call to the provider when cache is out of date
>>     2) Support byte arrays for userpic and similar
>>
>> I modified init_src_context in sysdb_search.c to accept an array of
>> attributes to pass into the LDB search.
> 
> I would rather not make attrs a parameter of init_src_context() but just
> assign it when necessary like we do for expression, given most of the
> time we would pass in NULL otherwise.

You're right, that makes more sense. Fixed.

> 
>> I also made one additional related fix: the btreemap now sorts in the
>> correct order. Previously I had accidentally transposed the two values
>> for sorting, so the map would always have been in exact reverse order.
> 
> Thanks for this.
> 
> 
> Simo.
> 

Please see new attached patch.

-- 
Stephen Gallagher
RHCE 804006346421761

Looking to carve out IT costs?
www.redhat.com/carveoutcosts/
From aa6cfb69159b81c544c12d432edf2a388ed6609e Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh redhat com>
Date: Sun, 1 Mar 2009 15:12:38 -0500
Subject: [PATCH] Implement GetUserAttributes in the InfoPipe

This patch adds support for requesting user data in the sysdb via
the InfoPipe. It currently has support for reading defined entries
of integral, floating-point or string types.

Tasks remaining:
1) Implement call to the provider when cache is out of date
2) Support byte arrays for userpic and similar

I modified sysdb_search_ctx in sysdb_search.c to accept an array of
attributes to pass into the LDB search.

I also made one additional related fix: the btreemap now sorts in the
correct order. Previously I had accidentally transposed the two
values for sorting, so the map would always have been in exact
reverse order.
---
 .gitignore                                         |    1 +
 server/confdb/confdb.c                             |    4 +-
 server/db/sysdb.h                                  |   30 +
 server/db/sysdb_search.c                           |   61 ++
 server/infopipe/infopipe.c                         |  100 ++--
 server/infopipe/infopipe_private.h                 |   30 +-
 server/infopipe/infopipe_users.c                   |  666 +++++++++++++++++++-
 .../org.freeipa.sssd.infopipe.Introspect.xml       |    5 +-
 server/infopipe/sysbus.c                           |   29 +
 server/infopipe/sysbus.h                           |    2 +
 server/sbus/sssd_dbus.h                            |    2 +
 server/sbus/sssd_dbus_common.c                     |   29 +
 server/tests/infopipe-tests.c                      |    6 +-
 server/util/btreemap.c                             |    4 +-
 14 files changed, 911 insertions(+), 58 deletions(-)

diff --git a/.gitignore b/.gitignore
index 2e6dd43..3b784ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ config.log
 config.status
 config.h
 config.h.in
+config.rpath
 Makefile
 cscope.out
 *.so
diff --git a/server/confdb/confdb.c b/server/confdb/confdb.c
index e93a4f4..4c895d5 100644
--- a/server/confdb/confdb.c
+++ b/server/confdb/confdb.c
@@ -612,8 +612,8 @@ static int _domain_comparator(const void *key1, const void *key2)
     ret = strcasecmp((const char *)key1, (const char *)key2);
     if (ret) {
         /* special case LOCAL to be always the first domain */
-        if (strcmp(key1, "LOCAL") == 0) return 1;
-        if (strcmp(key2, "LOCAL") == 0) return -1;
+        if (strcmp(key1, "LOCAL") == 0) return -1;
+        if (strcmp(key2, "LOCAL") == 0) return 1;
     }
     return ret;
 }
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index c0ef361..df673ad 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -23,6 +23,7 @@
 #define __SYS_DB_H__
 
 #include "ldb.h"
+#include "confdb/confdb.h"
 
 #define SYSDB_CONF_SECTION "config/sysdb"
 #define SYSDB_FILE "sssd.ldb"
@@ -59,6 +60,17 @@
 #define SYSDB_GR_MEMBER "member"
 #define SYSDB_LEGACY_MEMBER "memberUid"
 
+#define SYSDB_USER_ATTR_DEFAULTGROUP "defaultGroup"
+#define SYSDB_USER_ATTR_GECOS "gecos"
+#define SYSDB_USER_ATTR_HOMEDIR "homeDirectory"
+#define SYSDB_USER_ATTR_SHELL "shell"
+#define SYSDB_USER_ATTR_FULLNAME "fullName"
+#define SYSDB_USER_ATTR_LOCALE "locale"
+#define SYSDB_USER_ATTR_KEYBOARD "keyboard"
+#define SYSDB_USER_ATTR_SESSION "session"
+#define SYSDB_USER_ATTR_LAST_LOGIN "lastLogin"
+#define SYSDB_USER_ATTR_USERPIC "userPicture"
+
 #define SYSDB_LAST_UPDATE "lastUpdate"
 
 #define SYSDB_PW_ATTRS {SYSDB_PW_NAME, SYSDB_PW_UIDNUM, \
@@ -66,6 +78,18 @@
                         SYSDB_PW_HOMEDIR, SYSDB_PW_SHELL, \
                         SYSDB_LAST_UPDATE, \
                         NULL}
+#define SYSDB_USER_ATTRS {SYSDB_USER_ATTR_DEFAULTGROUP, \
+                          SYSDB_USER_ATTR_GECOS, \
+                          SYSDB_USER_ATTR_HOMEDIR, \
+                          SYSDB_USER_ATTR_SHELL, \
+                          SYSDB_USER_ATTR_FULLNAME, \
+                          SYSDB_USER_ATTR_LOCALE, \
+                          SYSDB_USER_ATTR_KEYBOARD, \
+                          SYSDB_USER_ATTR_SESSION, \
+                          SYSDB_USER_ATTR_LAST_LOGIN, \
+                          SYSDB_USER_ATTR_USERPIC, \
+                          SYSDB_LAST_UPDATE, \
+                          NULL}
 #define SYSDB_GRNAM_ATTRS {SYSDB_GR_NAME, SYSDB_GR_GIDNUM, \
                            SYSDB_LAST_UPDATE, SYSDB_LEGACY_MEMBER, \
                            NULL}
@@ -134,6 +158,12 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx,
                      bool legacy,
                      sysdb_callback_t fn, void *ptr);
 
+int sysdb_get_user_attr(TALLOC_CTX *mem_ctx,
+                        struct sysdb_ctx *ctx,
+                        struct sss_domain_info *domain,
+                        const char *name,
+                        const char **attributes,
+                        sysdb_callback_t fn, void *ptr);
 
 /* the following are all SYNCHRONOUS calls
  * TODO: make these asynchronous */
diff --git a/server/db/sysdb_search.c b/server/db/sysdb_search.c
index 5a355a0..f3c029c 100644
--- a/server/db/sysdb_search.c
+++ b/server/db/sysdb_search.c
@@ -44,6 +44,8 @@ struct sysdb_search_ctx {
     struct get_mem_ctx *gmctx;
 
     struct ldb_result *res;
+
+    const char **attrs;
 };
 
 static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx,
@@ -204,6 +206,37 @@ static void pwd_search(struct sysdb_req *sysreq, void *ptr)
     }
 }
 
+static void user_search(struct sysdb_req *sysreq, void *ptr)
+{
+    struct sysdb_search_ctx *sctx;
+    struct ldb_request *req;
+    struct ldb_dn *base_dn;
+    int ret;
+
+    sctx = talloc_get_type(ptr, struct sysdb_search_ctx);
+    sctx->req = sysreq;
+
+    base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb,
+                             SYSDB_TMPL_USER_BASE, sctx->domain);
+    if (!base_dn) {
+        return request_error(sctx, ENOMEM);
+    }
+
+    ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx,
+                               base_dn, LDB_SCOPE_SUBTREE,
+                               sctx->expression, sctx->attrs, NULL,
+                               sctx, get_gen_callback,
+                               NULL);
+    if (ret != LDB_SUCCESS) {
+        return request_ldberror(sctx, ret);
+    }
+
+    ret = ldb_request(sctx->ctx->ldb, req);
+    if (ret != LDB_SUCCESS) {
+        return request_ldberror(sctx, ret);
+    }
+}
+
 int sysdb_getpwnam(TALLOC_CTX *mem_ctx,
                    struct sysdb_ctx *ctx,
                    const char *domain,
@@ -729,3 +762,31 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx,
     return sysdb_operation(mem_ctx, ctx, initgr_search, sctx);
 }
 
+int sysdb_get_user_attr(TALLOC_CTX *mem_ctx,
+                        struct sysdb_ctx *ctx,
+                        struct sss_domain_info *domain,
+                        const char *name,
+                        const char **attributes,
+                        sysdb_callback_t fn, void *ptr)
+{
+    struct sysdb_search_ctx *sctx;
+
+    if (!domain) {
+        return EINVAL;
+    }
+
+    sctx = init_src_ctx(mem_ctx, domain->name, domain->legacy, ctx, fn, ptr);
+    if (!sctx) {
+        return ENOMEM;
+    }
+
+    sctx->expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name);
+    if (!sctx->expression) {
+        talloc_free(sctx);
+        return ENOMEM;
+    }
+
+    sctx->attrs = attributes;
+
+    return sysdb_operation(mem_ctx, ctx, user_search, sctx);
+}
diff --git a/server/infopipe/infopipe.c b/server/infopipe/infopipe.c
index 4b1eb92..035bd4b 100644
--- a/server/infopipe/infopipe.c
+++ b/server/infopipe/infopipe.c
@@ -26,6 +26,8 @@
 #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"
@@ -264,6 +266,7 @@ static int infp_process_init(TALLOC_CTX *mem_ctx,
     ret = infp_monitor_init(infp_ctx);
     if (ret != EOK) {
         DEBUG(0, ("Fatal error setting up monitor bus\n"));
+        talloc_free(infp_ctx);
         return EIO;
     }
 
@@ -274,18 +277,48 @@ static int infp_process_init(TALLOC_CTX *mem_ctx,
                       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->domain_map);
+    if (ret != EOK) {
+        DEBUG(0, ("Failed to populate the domain map\n"));
+        talloc_free(infp_ctx);
+        return EIO;
+    }
+
+    if (infp_ctx->domain_map == NULL) {
+        /* No domains configured!
+         * Note: this should never happen, since LOCAL
+         * should always be configured
+         */
+        DEBUG(0, ("No domains configured on this client!\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 ret;
+    return EOK;
 }
 
-int get_object_type(const char *obj)
+int infp_get_object_type(const char *obj)
 {
     int object_type = INFP_OBJ_TYPE_INVALID;
 
@@ -297,11 +330,13 @@ int get_object_type(const char *obj)
     return object_type;
 }
 
-int get_action_type(const char *action)
+int infp_get_action_type(const char *action)
 {
     int action_type = INFP_ACTION_TYPE_INVALID;
 
-    if (strcasecmp(action, "create") == 0)
+    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;
@@ -315,7 +350,7 @@ int get_action_type(const char *action)
     return action_type;
 }
 
-int get_attribute_type(const char *attribute)
+int infp_get_attribute_type(const char *attribute)
 {
     int attribute_type = INFP_ATTR_TYPE_INVALID;
 
@@ -353,7 +388,7 @@ int get_attribute_type(const char *attribute)
 }
 
 bool infp_get_permissions(const char *username,
-                          const char *domain,
+                          struct sss_domain_info *domain,
                           int object_type,
                           const char *instance,
                           int action_type,
@@ -369,6 +404,11 @@ bool infp_get_permissions(const char *username,
     return false;
 }
 
+struct sss_domain_info *infp_get_domain_obj(struct infp_ctx *infp, const char *domain_name)
+{
+    return talloc_get_type(btreemap_get_value(infp->domain_map, (const void *) domain_name), struct sss_domain_info);
+}
+
 /* CheckPermissions(STRING domain, STRING object, STRING instance
  *                  ARRAY(STRING action_type, STRING attribute) actions)
  */
@@ -376,18 +416,16 @@ int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn)
 {
     DBusMessage *reply;
     TALLOC_CTX *tmp_ctx;
+    struct infp_ctx *infp;
     int current_type;
-    DBusConnection *conn;
-    const char *conn_name;
-    uid_t uid;
-    char *username;
+    char *caller;
     DBusMessageIter iter;
     DBusMessageIter action_array_iter;
     DBusMessageIter action_struct_iter;
-    DBusError error;
     int object_type;
     const char *einval_msg;
-    const char *domain;
+    const char *domain_name;
+    struct sss_domain_info *domain;
     const char *object;
     const char *instance;
     const char *action;
@@ -401,26 +439,11 @@ int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn)
         return ENOMEM;
     }
 
-    /* Get the connection UID */
-    conn = sbus_get_connection(sconn);
-    conn_name = dbus_message_get_sender(message);
-    if (conn_name == NULL) {
-        DEBUG(0, ("Critical error: D-BUS client has no unique name\n"));
-        talloc_free(tmp_ctx);
-        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);
-        talloc_free(tmp_ctx);
-        return EIO;
-    }
-    username = get_username_from_uid(tmp_ctx, uid);
-    if (username == NULL) {
-        DEBUG(0, ("No username matched the connected UID\n"));
-        talloc_free(tmp_ctx);
+    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;
     }
 
@@ -435,8 +458,9 @@ int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn)
         einval_msg = talloc_strdup(tmp_ctx, "Expected domain");
         goto einval;
     }
-    dbus_message_iter_get_basic(&iter, &domain);
-    DEBUG(9, ("Domain: %s\n", domain));
+    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);
@@ -447,7 +471,7 @@ int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn)
     }
     dbus_message_iter_get_basic(&iter, &object);
     DEBUG(9, ("Object: %s\n", object));
-    object_type = get_object_type(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;
@@ -490,7 +514,7 @@ int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn)
         }
         dbus_message_iter_get_basic(&action_struct_iter, &action);
         DEBUG(9, ("Action type: %s\n", action));
-        action_type = get_action_type(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;
@@ -504,7 +528,7 @@ int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn)
         }
         dbus_message_iter_get_basic(&action_struct_iter, &attribute);
         DEBUG(9, ("Action attribute: %s\n", attribute));
-        attribute_type = get_attribute_type(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;
@@ -518,7 +542,7 @@ int infp_check_permissions(DBusMessage *message, struct sbus_conn_ctx *sconn)
         /* Process the actions */
         count++;
         permissions=talloc_realloc(tmp_ctx, permissions, dbus_bool_t, count);
-        permissions[count-1] = infp_get_permissions(username, domain,
+        permissions[count-1] = infp_get_permissions(caller, domain,
                                                     object_type, instance,
                                                     action_type, attribute_type);
 
diff --git a/server/infopipe/infopipe_private.h b/server/infopipe/infopipe_private.h
index 8ea2586..f1d6694 100644
--- a/server/infopipe/infopipe_private.h
+++ b/server/infopipe/infopipe_private.h
@@ -27,27 +27,39 @@ struct infp_ctx {
     struct confdb_ctx *cdb;
     struct service_sbus_ctx *ss_ctx;
     struct sysbus_ctx *sysbus;
+    struct sysdb_ctx *sysdb;
+    struct btreemap *domain_map;
     char *introspect_xml;
+
+    int cache_timeout;
+};
+
+struct infp_req_ctx {
+    struct infp_ctx *infp;
+    struct sbus_conn_ctx *sconn;
+    DBusMessage *req_message;
+    bool check_provider;
 };
 
-enum object_types {
+enum infp_object_types {
     INFP_OBJ_TYPE_INVALID = 0,
     INFP_OBJ_TYPE_USER,
     INFP_OBJ_TYPE_GROUP
 };
-int get_object_type(const char *obj);
+int infp_get_object_type(const char *obj);
 
-enum action_types {
+enum infp_action_types {
     INFP_ACTION_TYPE_INVALID = 0,
+    INFP_ACTION_TYPE_READ,
     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);
+int infp_get_action_type(const char *action);
 
-enum attribute_types {
+enum infp_attribute_types {
     INFP_ATTR_TYPE_INVALID = 0,
     INFP_ATTR_TYPE_DEFAULTGROUP,
     INFP_ATTR_TYPE_GECOS,
@@ -60,13 +72,17 @@ enum attribute_types {
     INFP_ATTR_TYPE_LAST_LOGIN,
     INFP_ATTR_TYPE_USERPIC
 };
-int get_attribute_type(const char *attribute);
+int infp_get_attribute_type(const char *attribute);
+
+int infp_get_user_attr_dbus_type(int attr_type, int *subtype);
 
 bool infp_get_permissions(const char *username,
-                          const char *domain,
+                          struct sss_domain_info *domain,
                           int object_type,
                           const char *instance,
                           int action_type,
                           int action_attribute);
 
+struct sss_domain_info *infp_get_domain_obj(struct infp_ctx *infp, const char *domain_name);
+
 #endif /* INFOPIPE_PRIVATE_H_ */
diff --git a/server/infopipe/infopipe_users.c b/server/infopipe/infopipe_users.c
index 2c107bc..82889fa 100644
--- a/server/infopipe/infopipe_users.c
+++ b/server/infopipe/infopipe_users.c
@@ -19,8 +19,17 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include <dbus/dbus.h>
+#include <ldb.h>
+#include <time.h>
 #include "util/util.h"
-#include "infopipe.h"
+#include "util/btreemap.h"
+#include "confdb/confdb.h"
+#include "infopipe/infopipe.h"
+#include "infopipe/infopipe_private.h"
+#include "infopipe/sysbus.h"
+#include "db/sysdb.h"
+
+static int attr_comparator(const void *key1, const void *key2);
 
 int infp_users_get_cached(DBusMessage *message, struct sbus_conn_ctx *sconn)
 {
@@ -61,19 +70,664 @@ int infp_users_delete(DBusMessage *message, struct sbus_conn_ctx *sconn)
     return EOK;
 }
 
-int infp_users_get_attr(DBusMessage *message, struct sbus_conn_ctx *sconn)
+struct infp_getattr_ctx {
+    char *caller;
+    struct sss_domain_info *domain;
+    struct infp_req_ctx *infp_req;
+    char **usernames;
+    uint32_t username_count;
+    char **attributes;
+    uint32_t attr_count;
+    uint32_t index;
+    bool check_provider;
+
+    /* The results array must have username_count elements */
+    struct btreemap **results;
+};
+
+static int infp_get_attr_lookup(struct infp_getattr_ctx *infp_getattr_req);
+
+struct infp_attr_variant {
+    int dbus_type;
+    int subtype;
+    int count;
+    void *data;
+};
+
+/* We are restricting variants to three basic types:
+ * Fixed (Numeric) types
+ * Strings
+ * Arrays of fixed (numeric) types
+ */
+static int infp_user_getattr_append_dict(TALLOC_CTX *mem_ctx,
+                                         DBusMessageIter *iter,
+                                         struct btreemap *map)
+{
+    int ret, i;
+    char **attrs;
+    struct infp_attr_variant *value;
+    char *vartype;
+    char *subtype;
+    int attr_count;
+    DBusMessageIter array_iter;
+    DBusMessageIter dict_iter;
+    DBusMessageIter variant_iter;
+    dbus_bool_t dbret;
+
+    ret = btreemap_get_keys(mem_ctx, map, (const void ***)&attrs, &attr_count);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* DICTs are an array of dict pairs */
+    dbret = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &array_iter);
+    if (!dbret) {
+        ret = ENOMEM;
+        goto error;
+    }
+
+    i = 0;
+    while (i < attr_count) {
+        if (strcasecmp(attrs[i], SYSDB_LAST_UPDATE) == 0) {
+            /* Skip lastUpdate. We shouldn't be returning this */
+            i++;
+            continue;
+        }
+
+        /* Create the variant value */
+        value = talloc_get_type(btreemap_get_value(map, attrs[i]), struct infp_attr_variant);
+        if (value == NULL) {
+            /* Skip any entries that returned an empty value */
+            i++;
+            continue;
+        }
+
+        /* Open a dict container for this pair */
+        dbret = dbus_message_iter_open_container(&array_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter);
+        if (!dbret) {
+            ret = ENOMEM;
+            goto error;
+        }
+        /* Write the dict key */
+        dbret = dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &attrs[i]);
+        if (!dbret) {
+            ret = ENOMEM;
+            goto error;
+        }
+
+        vartype = NULL;
+        subtype = NULL;
+        if (sbus_is_dbus_string_type(value->dbus_type)) {
+            /* String types are strings, object paths and signatures */
+            vartype = talloc_asprintf(mem_ctx, "%c", value->dbus_type);
+            if (vartype == NULL) {
+                ret = ENOMEM;
+                goto error;
+            }
+            dbret = dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, vartype, &variant_iter);
+            if (!dbret) {
+                ret = ENOMEM;
+                goto error;
+            }
+            dbret = dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &value->data);
+            if (!dbret) {
+                ret = ENOMEM;
+                goto error;
+            }
+            talloc_free(vartype);
+            vartype = NULL;
+        }
+
+        else if (sbus_is_dbus_fixed_type(value->dbus_type)) {
+            /* Fixed types are booleans, bytes, the integral types and the floating-point types */
+            vartype = talloc_asprintf(mem_ctx, "%c", value->dbus_type);
+            if (vartype == NULL) {
+                ret = ENOMEM;
+                goto error;
+            }
+            dbret = dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, vartype, &variant_iter);
+            if (!dbret) {
+                ret = ENOMEM;
+                goto error;
+            }
+            dbret = dbus_message_iter_append_basic(&variant_iter, value->dbus_type, value->data);
+            if (!dbret) {
+                ret = ENOMEM;
+                goto error;
+            }
+            talloc_free(vartype);
+            vartype = NULL;
+        }
+        /* FIXME: Need to support byte arrays for userpic and similar */
+
+        else {
+            /* Value type not yet supported */
+            DEBUG(0, ("Attempted to create DICT value for something not a basic type or fixed array [%d]\n", value->dbus_type));
+            ret = EINVAL;
+            goto error;
+        }
+
+        /* Close the variant */
+        dbret = dbus_message_iter_close_container(&dict_iter, &variant_iter);
+        if(!dbret) {
+            ret = ENOMEM;
+            goto error;
+        }
+
+        /* Close the dict */
+        dbret = dbus_message_iter_close_container(&array_iter, &dict_iter);
+        if(!dbret) {
+            ret = ENOMEM;
+            goto error;
+        }
+        i++;
+    }
+
+    /* Close the dict array */
+    dbret = dbus_message_iter_close_container(iter, &array_iter);
+    if(!dbret) {
+        ret = ENOMEM;
+        goto error;
+    }
+
+    return EOK;
+
+error:
+    talloc_free(attrs);
+    talloc_free(vartype);
+    talloc_free(subtype);
+    return ret;
+}
+
+static int create_getattr_result_map(TALLOC_CTX *mem_ctx, struct infp_getattr_ctx *infp_getattr_req,
+                                     struct ldb_result *res, struct btreemap **results)
+{
+    int i, ret;
+    int attr_type, subtype;
+    struct infp_attr_variant *variant;
+    const char *tmp_string;
+
+    /* Iterate through the requested attributes */
+    for (i=0; i < infp_getattr_req->attr_count; i++) {
+        /* Ignore any attributes we don't care about */
+        attr_type = infp_get_attribute_type(infp_getattr_req->attributes[i]);
+        if (attr_type != INFP_ATTR_TYPE_INVALID) {
+            variant = talloc_zero(mem_ctx, struct infp_attr_variant);
+            if (variant == NULL) {
+                ret = ENOMEM;
+                goto end;
+            }
+            variant->dbus_type = infp_get_user_attr_dbus_type(attr_type, &subtype);
+            switch (variant->dbus_type) {
+            case DBUS_TYPE_STRING:
+                tmp_string = ldb_msg_find_attr_as_string(res->msgs[0], infp_getattr_req->attributes[i], NULL);
+                if (tmp_string == NULL) {
+                    /* Attribute was not found in the result list */
+                    talloc_free(variant);
+                    continue;
+                }
+                variant->data = (void *)talloc_strdup(variant, tmp_string);
+                if (variant->data == NULL) {
+                    talloc_free(variant);
+                    continue;
+                }
+                break;
+
+            case DBUS_TYPE_BOOLEAN:
+            case DBUS_TYPE_BYTE:
+            case DBUS_TYPE_INT16:
+            case DBUS_TYPE_UINT16:
+            case DBUS_TYPE_INT32:
+            case DBUS_TYPE_UINT32:
+            case DBUS_TYPE_INT64:
+            case DBUS_TYPE_UINT64:
+                /* We'll treat all integral types as UINT64 internally
+                 * These will be correctly converted to their true types
+                 * when being marshalled on the wire.
+                 */
+                variant->data = (void *)talloc(variant, uint64_t);
+                if (variant->data == NULL) {
+                    talloc_free(variant);
+                    continue;
+                }
+
+                *(uint64_t *)variant->data = ldb_msg_find_attr_as_uint64(res->msgs[0], infp_getattr_req->attributes[i], 0);
+                break;
+
+            default:
+                talloc_free(variant);
+                continue;
+            }
+
+            /* Add the variant to the map */
+            ret = btreemap_set_value(mem_ctx, results, (const void *)infp_getattr_req->attributes[i], variant, attr_comparator);
+            if (ret != EOK) {
+                talloc_free(variant);
+                continue;
+            }
+        }
+    }
+
+    ret = EOK;
+
+end:
+    return ret;
+}
+
+static void infp_get_attr_lookup_callback(void *ptr, int ldb_status, struct ldb_result *res)
 {
+    int ret;
+    int i;
+    bool call_provider = false;
+    int timeout;
+    uint64_t lastUpdate;
     DBusMessage *reply;
+    DBusMessageIter iter;
+    DBusMessageIter array_iter;
+    struct infp_getattr_ctx *infp_getattr_req = talloc_get_type(ptr, struct infp_getattr_ctx);
 
-    reply = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, "Not yet implemented");
+    DEBUG(9, ("Processing results for user [%s]\n", infp_getattr_req->usernames[infp_getattr_req->index]));
 
-    /* send reply */
-    sbus_conn_send_reply(sconn, reply);
+    /* Process the current results */
+    if (ldb_status != LDB_SUCCESS) {
+        DEBUG(0, ("Critical error reading from sysdb.\n"));
+        goto done;
+    }
+
+    if(infp_getattr_req->check_provider) {
+        switch(res->count) {
+        case 0:
+            call_provider = true;
+            break;
+
+        case 1:
+            timeout = infp_getattr_req->infp_req->infp->cache_timeout;
+            lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
+                                                     SYSDB_LAST_UPDATE, 0);
+            if (lastUpdate + timeout < time(NULL)) {
+                call_provider = true;
+            }
+            break;
+
+        default:
+            DEBUG(0, ("GetUser call returned more than one result. This probably means the sysdb is corrupt!\n"));
+            goto done;
+        }
+    }
+
+    if (call_provider) {
+        /* FIXME call the provider */
+    }
+
+    switch (res->count) {
+    case 0:
+        DEBUG(2, ("No results for GetUser"));
+        infp_getattr_req->results[infp_getattr_req->index] = NULL;
+        break;
+
+    case 1:
+        /* Create the result map */
+        ret = create_getattr_result_map(infp_getattr_req, infp_getattr_req, res,
+                                        &infp_getattr_req->results[infp_getattr_req->index]);
+        if (ret != EOK) {
+            DEBUG(0, ("Unable to create result map!\n"));
+            goto done;
+        }
+        break;
+    default:
+        /* We received more than one result. This is bad */
+        DEBUG(0, ("GetUser call returned more than one result. This probably means the sysdb is corrupt!\n"));
+        goto done;
+    }
+
+    /* If there are more usernames remaining in the list, re-enter the loop */
+    infp_getattr_req->index++;
+    if (infp_getattr_req->index < infp_getattr_req->username_count) {
+        ret = infp_get_attr_lookup(infp_getattr_req);
+        if (ret != EOK) {
+            DEBUG(0, ("Could not read from cache database\n"));
+            goto done;
+        }
+        return;
+    }
+
+    /* No more names remain, return the result DICTs */
+    reply = dbus_message_new_method_return(infp_getattr_req->infp_req->req_message);
+    if (reply == NULL) {
+        goto done;
+    }
+
+    dbus_message_iter_init_append(reply, &iter);
+
+    dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "a{sv}", &array_iter);
+    i = 0;
+    while (i < infp_getattr_req->username_count) {
+        ret = infp_user_getattr_append_dict(infp_getattr_req, &array_iter, infp_getattr_req->results[i]);
+        if (ret != EOK) {
+            DEBUG(0, ("Unable to append response DICT\n"));
+            goto done;
+        }
+        i++;
+    }
+    dbus_message_iter_close_container(&iter, &array_iter);
+
+    sbus_conn_send_reply(infp_getattr_req->infp_req->sconn, reply);
+
+done:
+    talloc_free(infp_getattr_req);
+}
+
+int infp_get_user_attr_dbus_type(int attr_type, int *subtype)
+{
+    int dbus_type;
+
+    switch(attr_type) {
+    case INFP_ATTR_TYPE_DEFAULTGROUP:
+    case INFP_ATTR_TYPE_GECOS:
+    case INFP_ATTR_TYPE_HOMEDIR:
+    case INFP_ATTR_TYPE_SHELL:
+    case INFP_ATTR_TYPE_FULLNAME:
+    case INFP_ATTR_TYPE_LOCALE:
+    case INFP_ATTR_TYPE_KEYBOARD:
+    case INFP_ATTR_TYPE_SESSION:
+        dbus_type = DBUS_TYPE_STRING;
+        break;
+    case INFP_ATTR_TYPE_LAST_LOGIN:
+        dbus_type = DBUS_TYPE_UINT64;
+        break;
+    case INFP_ATTR_TYPE_USERPIC:
+        dbus_type = DBUS_TYPE_ARRAY;
+        *subtype = DBUS_TYPE_BYTE;
+        break;
+    default:
+        dbus_type = DBUS_TYPE_INVALID;
+    }
+    return dbus_type;
+}
+
+static int attr_comparator(const void *key1, const void *key2)
+{
+    return strcmp((const char *)key1, (const char *)key2);
+}
+
+static int infp_get_attr_lookup(struct infp_getattr_ctx *infp_getattr_req)
+{
+    uint32_t i;
+    int ret;
+    char **attributes;
+    const char *last_update;
+    int attr_count;
+
+    DEBUG(9, ("Processing lookup for user [%s]\n", infp_getattr_req->usernames[infp_getattr_req->index]));
+
+    if (infp_getattr_req->index >= infp_getattr_req->username_count) {
+        /* Avoid index bound issues */
+        return EINVAL;
+    }
+
+    /* Check permissions */
+    i=0;
+    infp_getattr_req->results[infp_getattr_req->index] = NULL;
+    while(i < infp_getattr_req->attr_count) {
+        if(infp_get_permissions(infp_getattr_req->caller,
+                                infp_getattr_req->domain,
+                                INFP_OBJ_TYPE_USER,
+                                infp_getattr_req->usernames[infp_getattr_req->index],
+                                INFP_ACTION_TYPE_READ,
+                                infp_get_attribute_type(infp_getattr_req->attributes[i]))
+        ) {
+            /* Add this attribute as a key to the result map
+             * This will guarantee that we are requesting only unique attributes
+             * that we have permission to read
+             */
+            ret = btreemap_set_value(infp_getattr_req, &infp_getattr_req->results[infp_getattr_req->index],
+                                     infp_getattr_req->attributes[i], NULL, attr_comparator);
+            if (ret != EOK) {
+                return ret;
+            }
+        }
+        i++;
+    }
+
+    /* Always add SYSDB_LAST_UPDATE to the list, we won't return it */
+    last_update = talloc_strdup(infp_getattr_req, SYSDB_LAST_UPDATE);
+    ret = btreemap_set_value(infp_getattr_req, &infp_getattr_req->results[infp_getattr_req->index],
+                             last_update, NULL, attr_comparator);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* Prepare the list of attributes to request from the sysdb */
+    attr_count = 0;
+    ret = btreemap_get_keys(infp_getattr_req,
+                            infp_getattr_req->results[infp_getattr_req->index],
+                            (const void ***)&attributes, &attr_count);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    if (attr_count == 1) {
+        /* There were zero authorized attributes in the list
+         * No need to call sysdb, just move to the next username
+         * The single attribute was SYSDB_LAST_UPDATE which we
+         * added manually.
+         */
+        infp_getattr_req->index++;
+        return infp_get_attr_lookup(infp_getattr_req);
+    }
+
+    /* Add a trailing NULL entry (required for sysdb) */
+    attributes = talloc_realloc(infp_getattr_req, attributes, char *, attr_count+1);
+    if (attributes == NULL) {
+        return ENOMEM;
+    }
+    attributes[attr_count] = NULL;
+
+    /* Call into the sysdb for the requested attributes */
+    ret = sysdb_get_user_attr(infp_getattr_req,
+                              infp_getattr_req->infp_req->infp->sysdb,
+                              infp_getattr_req->domain,
+                              infp_getattr_req->usernames[infp_getattr_req->index],
+                              (const char **)attributes,
+                              infp_get_attr_lookup_callback, infp_getattr_req);
 
-    dbus_message_unref(reply);
     return EOK;
 }
 
+static char **infp_get_all_attributes(TALLOC_CTX *mem_ctx, uint32_t *attr_count)
+{
+    char **attributes;
+    int offset = 0;
+
+    *attr_count = 10;
+    attributes = talloc_array(mem_ctx, char *, *attr_count);
+    if (attributes == NULL) {
+        return NULL;
+    }
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_DEFAULTGROUP);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_GECOS);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_HOMEDIR);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_SHELL);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_FULLNAME);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_LOCALE);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_KEYBOARD);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_SESSION);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_LAST_LOGIN);
+    if(!attributes[offset]) goto error;
+
+    attributes[offset++] = talloc_strdup(attributes, SYSDB_USER_ATTR_USERPIC);
+    if(!attributes[offset]) goto error;
+
+    return attributes;
+
+error:
+    talloc_free(attributes);
+    *attr_count = 0;
+    return NULL;
+}
+
+/* GetUserAttributes(ARRAY(STRING) usernames,
+ *                   STRING domain,
+ *                   ARRAY(STRING) filter)
+ */
+int infp_users_get_attr(DBusMessage *message, struct sbus_conn_ctx *sconn)
+{
+    int ret, i;
+    DBusMessage *reply;
+    DBusError error;
+    dbus_bool_t dbret;
+    char **usernames;
+    uint32_t username_count;
+    char *domain;
+    char **attributes;
+    uint32_t attr_count;
+    struct infp_getattr_ctx *infp_getattr_req;
+
+    usernames = NULL;
+    attributes = NULL;
+    /* Get the arguments to GetAttributes */
+    dbus_error_init(&error);
+    dbret = dbus_message_get_args(message, &error,
+                                  DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &usernames, &username_count,
+                                  DBUS_TYPE_STRING, &domain,
+                                  DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &attributes, &attr_count,
+                                  DBUS_TYPE_INVALID);
+    if(!dbret) {
+        DEBUG(0, ("Parsing arguments failed: %s:%s\n", error.name, error.message));
+        dbus_free_string_array(usernames);
+        dbus_free_string_array(attributes);
+
+        reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, error.message);
+        sbus_conn_send_reply(sconn, reply);
+
+        dbus_message_unref(reply);
+        dbus_error_free(&error);
+
+        return EOK;
+    }
+
+    if (username_count < 1) {
+        /* No usernames received. Return an error */
+        reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "No usernames specified.");
+        sbus_conn_send_reply(sconn, reply);
+
+        dbus_free_string_array(usernames);
+        dbus_free_string_array(attributes);
+        dbus_message_unref(reply);
+        ret = EOK;
+    }
+
+    /* Create a infp_getattr_ctx */
+    infp_getattr_req = talloc_zero(NULL, struct infp_getattr_ctx);
+    if (infp_getattr_req == NULL) {
+        ret = ENOMEM;
+        goto end;
+    }
+
+    /* Create an infp_req_ctx */
+    infp_getattr_req->infp_req = talloc_zero(infp_getattr_req, struct infp_req_ctx);
+    if (infp_getattr_req == NULL) {
+        ret = ENOMEM;
+        goto end;
+    }
+    infp_getattr_req->infp_req->infp = talloc_get_type(sbus_conn_get_private_data(sconn), struct infp_ctx);
+    infp_getattr_req->infp_req->sconn = sconn;
+    infp_getattr_req->infp_req->req_message = message;
+    infp_getattr_req->domain = btreemap_get_value(infp_getattr_req->infp_req->infp->domain_map, (const void *)domain);
+    infp_getattr_req->check_provider = strcasecmp(domain, "LOCAL");
+
+    /* Copy the username list */
+    infp_getattr_req->usernames = talloc_array(infp_getattr_req, char *, username_count);
+    if (infp_getattr_req->usernames == NULL) {
+        ret = ENOMEM;
+        goto end;
+    }
+
+    i = 0;
+    while (i < username_count) {
+        DEBUG(9, ("Request for user [%s]\n", usernames[i]));
+        infp_getattr_req->usernames[i] = talloc_strdup(infp_getattr_req->usernames, usernames[i]);
+        if (infp_getattr_req == NULL) {
+            ret = ENOMEM;
+            goto end;
+        }
+        i++;
+    }
+    infp_getattr_req->username_count = username_count;
+
+    /* Copy the attribute list */
+    if (attr_count > 0) {
+        infp_getattr_req->attributes = talloc_array(infp_getattr_req, char *, attr_count);
+        if (infp_getattr_req->attributes == NULL) {
+            ret = ENOMEM;
+            goto end;
+        }
+        i = 0;
+        while (i < attr_count) {
+            infp_getattr_req->attributes[i] = talloc_strdup(infp_getattr_req, attributes[i]);
+            if (infp_getattr_req == NULL) {
+                ret = ENOMEM;
+                goto end;
+            }
+            i++;
+        }
+        infp_getattr_req->attr_count = attr_count;
+    } else {
+        /* No attributes specified in the call means retrieve all possible */
+        infp_getattr_req->attributes = infp_get_all_attributes(infp_getattr_req, &infp_getattr_req->attr_count);
+        if (infp_getattr_req->attributes == NULL) {
+            ret = ENOMEM;
+            goto end;
+        }
+    }
+
+    infp_getattr_req->index = 0;
+
+    infp_getattr_req->caller = sysbus_get_caller(infp_getattr_req, message, sconn);
+    if (infp_getattr_req->caller == NULL) {
+        ret = EIO;
+        goto end;
+    }
+
+    /* Prepare the result list */
+    infp_getattr_req->results = talloc_array(infp_getattr_req, struct btreemap *, attr_count);
+    if (infp_getattr_req->results == NULL) {
+        ret = ENOMEM;
+        goto end;
+    }
+
+    /* Look up the first username and start the async loop */
+    ret = infp_get_attr_lookup(infp_getattr_req);
+    if (ret != EOK) {
+        DEBUG(0, ("Could not read from cache database\n"));
+    }
+
+end:
+    dbus_free_string_array(usernames);
+    dbus_free_string_array(attributes);
+    if (ret != EOK) {
+        talloc_free(infp_getattr_req);
+    }
+    return ret;
+}
+
 int infp_users_set_attr(DBusMessage *message, struct sbus_conn_ctx *sconn)
 {
     DBusMessage *reply;
diff --git a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
index 4122060..02fda96 100644
--- a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
+++ b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
@@ -28,6 +28,7 @@
                        @param instance A particular instance of an object (a username or group name). An empty string will be interpreted as all instances.
                        @param actions A list of actions to check the permissions of. Each action is described as a pair of (action_type, attribute). If attribute is left as an empty string, the query is for a global value (such as create or delete user) If the attribute value does not make sense for a particular object/instance/action, it will be ignored. Action types not applicable to an object/instance will return false (such as addmember on users).
                            Available action types:
+                            read
                             create
                             delete
                             modify
@@ -136,9 +137,9 @@
                        @note The attribute userpic may contain very large binary data. It is advisable to request this data separately from other attributes to avoid D-BUS message size limits."
             />
             <arg name="usernames" type="as" direction="in" />
-            <arg name="domain" type="as" direction="in" />
+            <arg name="domain" type="s" direction="in" />
             <arg name="filter" type="as" direction="in" />
-            <arg name="attributes" type="a{sv}" direction="out" />
+            <arg name="attributes" type="aa{sv}" direction="out" />
         </method>
 
         <method name="SetUserAttributes1">
diff --git a/server/infopipe/sysbus.c b/server/infopipe/sysbus.c
index 6ba1bb7..a90f92d 100644
--- a/server/infopipe/sysbus.c
+++ b/server/infopipe/sysbus.c
@@ -165,3 +165,32 @@ struct sbus_conn_ctx *sysbus_get_sbus_conn(struct sysbus_ctx *sysbus)
 {
     return sysbus->sconn;
 }
+
+char *sysbus_get_caller(TALLOC_CTX *mem_ctx, DBusMessage *message, struct sbus_conn_ctx *sconn)
+{
+    char *caller;
+    const char *conn_name;
+    DBusError error;
+    uid_t uid;
+
+    /* Get the connection UID */
+    conn_name = dbus_message_get_sender(message);
+    if (conn_name == NULL) {
+        DEBUG(0, ("Critical error: D-BUS client has no unique name\n"));
+        return NULL;
+    }
+    dbus_error_init(&error);
+    uid = dbus_bus_get_unix_user(sbus_get_connection(sconn), 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 NULL;
+    }
+    caller = get_username_from_uid(mem_ctx, uid);
+    if (caller == NULL) {
+        DEBUG(0, ("No username matched the connected UID\n"));
+        return NULL;
+    }
+
+    return caller;
+}
diff --git a/server/infopipe/sysbus.h b/server/infopipe/sysbus.h
index 2bed23a..cb45fa7 100644
--- a/server/infopipe/sysbus.h
+++ b/server/infopipe/sysbus.h
@@ -32,4 +32,6 @@ int sysbus_init(TALLOC_CTX *mem_ctx, struct sysbus_ctx **sysbus,
 
 struct sbus_conn_ctx *sysbus_get_sbus_conn(struct sysbus_ctx *sysbus);
 
+char *sysbus_get_caller(TALLOC_CTX *mem_ctx, DBusMessage *message, struct sbus_conn_ctx *sconn);
+
 #endif /* SYSBUS_H_ */
diff --git a/server/sbus/sssd_dbus.h b/server/sbus/sssd_dbus.h
index 43519b3..8dd0d3e 100644
--- a/server/sbus/sssd_dbus.h
+++ b/server/sbus/sssd_dbus.h
@@ -126,4 +126,6 @@ DBusHandlerResult sbus_message_handler(DBusConnection *conn,
 void sbus_conn_send_reply(struct sbus_conn_ctx *conn_ctx,
                           DBusMessage *reply);
 
+int sbus_is_dbus_fixed_type(int dbus_type);
+int sbus_is_dbus_string_type(int dbus_type);
 #endif /* _SSSD_DBUS_H_*/
diff --git a/server/sbus/sssd_dbus_common.c b/server/sbus/sssd_dbus_common.c
index a9e0d81..e5011aa 100644
--- a/server/sbus/sssd_dbus_common.c
+++ b/server/sbus/sssd_dbus_common.c
@@ -2,6 +2,7 @@
 #include "tevent.h"
 #include "dbus/dbus.h"
 #include "util/util.h"
+#include "util/btreemap.h"
 
 struct timeval _dbus_timeout_get_interval_tv(int interval) {
     struct timeval tv;
@@ -43,3 +44,31 @@ void sbus_remove_timeout(DBusTimeout *timeout, void *data) {
     talloc_free(te);
     dbus_timeout_set_data(timeout, NULL, NULL);
 }
+
+int sbus_is_dbus_fixed_type(int dbus_type)
+{
+    switch (dbus_type) {
+    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_BOOLEAN:
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64:
+    case DBUS_TYPE_DOUBLE:
+        return true;
+    }
+    return false;
+}
+
+int sbus_is_dbus_string_type(int dbus_type)
+{
+    switch(dbus_type) {
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+    case DBUS_TYPE_SIGNATURE:
+        return true;
+    }
+    return false;
+}
diff --git a/server/tests/infopipe-tests.c b/server/tests/infopipe-tests.c
index 2aaa653..0424fcb 100644
--- a/server/tests/infopipe-tests.c
+++ b/server/tests/infopipe-tests.c
@@ -151,8 +151,10 @@ START_TEST(test_infp_introspect)
                               DBUS_TYPE_INVALID);
 
         /* Verify that the reply matches the reference file */
-        if (strcmp(introspect_xml, returned_xml) != 0) {
-            fail("Verify Introspection XML: FAILED");
+        int c;
+        if ((c = strcmp(introspect_xml, returned_xml)) != 0) {
+            DEBUG(0, ("Verify Introspection XML: FAILED %d\nstrlen: %d, %d\n", c, strlen(introspect_xml), strlen(returned_xml)));
+            fail("");//"Verify Introspection XML: FAILED %d\n %s\nstrlen: %d", c, returned_xml, strlen(returned_xml));
         }
         break;
     case DBUS_MESSAGE_TYPE_ERROR:
diff --git a/server/util/btreemap.c b/server/util/btreemap.c
index 2d9b176..9bfc985 100644
--- a/server/util/btreemap.c
+++ b/server/util/btreemap.c
@@ -65,7 +65,7 @@ int btreemap_search_key(struct btreemap *map, const void *key, struct btreemap *
 
     tempnode = map;
     while (found == BTREEMAP_EMPTY) {
-        result = tempnode->comparator(tempnode->key, key);
+        result = tempnode->comparator(key, tempnode->key);
         if (result > 0)
         {
             if (tempnode->right)
@@ -150,6 +150,8 @@ int btreemap_set_value(TALLOC_CTX *mem_ctx,
     new_node->key = talloc_steal(new_node, key);
     new_node->value = talloc_steal(new_node, value);
     new_node->comparator = comparator;
+    new_node->left = NULL;
+    new_node->right = NULL;
 
 
     if (found == BTREEMAP_EMPTY)
-- 
1.6.0.6

Attachment: signature.asc
Description: OpenPGP digital signature


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]