summaryrefslogtreecommitdiff
path: root/server/infopipe
diff options
context:
space:
mode:
Diffstat (limited to 'server/infopipe')
-rw-r--r--server/infopipe/infopipe.c100
-rw-r--r--server/infopipe/infopipe_private.h30
-rw-r--r--server/infopipe/infopipe_users.c666
-rw-r--r--server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml5
-rw-r--r--server/infopipe/sysbus.c29
-rw-r--r--server/infopipe/sysbus.h2
6 files changed, 779 insertions, 53 deletions
diff --git a/server/infopipe/infopipe.c b/server/infopipe/infopipe.c
index 4b1eb920..035bd4b4 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 8ea2586b..f1d6694a 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 2c107bc4..82889fa8 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 41220606..02fda967 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 6ba1bb72..a90f92d5 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 2bed23a4..cb45fa7e 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_ */