summaryrefslogtreecommitdiffstats
path: root/src/responder/ifp/ifpsrv_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/responder/ifp/ifpsrv_util.c')
-rw-r--r--src/responder/ifp/ifpsrv_util.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
new file mode 100644
index 0000000..c21ceef
--- /dev/null
+++ b/src/responder/ifp/ifpsrv_util.c
@@ -0,0 +1,455 @@
+/*
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+ Stephen Gallagher <sgallagh@redhat.com>
+
+ Copyright (C) 2013 Red Hat
+
+ InfoPipe responder: Utility functions
+
+ 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 <sys/param.h>
+
+#include "db/sysdb.h"
+#include "responder/ifp/ifp_private.h"
+
+#define IFP_USER_DEFAULT_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \
+ SYSDB_GIDNUM, SYSDB_GECOS, \
+ SYSDB_HOMEDIR, SYSDB_SHELL, \
+ "groups", "domain", "domainname", \
+ "extraAttributes", NULL}
+
+errno_t ifp_add_value_to_dict(DBusMessageIter *iter_dict,
+ const char *key,
+ const char *value)
+{
+ DBusMessageIter iter_dict_entry;
+ DBusMessageIter iter_dict_val;
+ DBusMessageIter iter_array;
+ dbus_bool_t dbret;
+
+ if (value == NULL || key == NULL) {
+ return EINVAL;
+ }
+
+ dbret = dbus_message_iter_open_container(iter_dict,
+ DBUS_TYPE_DICT_ENTRY, NULL,
+ &iter_dict_entry);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ /* Start by appending the key */
+ dbret = dbus_message_iter_append_basic(&iter_dict_entry,
+ DBUS_TYPE_STRING, &key);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_open_container(&iter_dict_entry,
+ DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING,
+ &iter_dict_val);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ /* Open container for values */
+ dbret = dbus_message_iter_open_container(&iter_dict_val,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING,
+ &iter_array);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_STRING,
+ &value);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_close_container(&iter_dict_val,
+ &iter_array);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_close_container(&iter_dict_entry,
+ &iter_dict_val);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_close_container(iter_dict,
+ &iter_dict_entry);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict,
+ struct ldb_message_element *el)
+{
+ DBusMessageIter iter_dict_entry;
+ DBusMessageIter iter_dict_val;
+ DBusMessageIter iter_array;
+ dbus_bool_t dbret;
+ unsigned int i;
+
+ if (el == NULL) {
+ return EINVAL;
+ }
+
+ dbret = dbus_message_iter_open_container(iter_dict,
+ DBUS_TYPE_DICT_ENTRY, NULL,
+ &iter_dict_entry);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ /* Start by appending the key */
+ dbret = dbus_message_iter_append_basic(&iter_dict_entry,
+ DBUS_TYPE_STRING, &(el->name));
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_open_container(&iter_dict_entry,
+ DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING,
+ &iter_dict_val);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ /* Open container for values */
+ dbret = dbus_message_iter_open_container(&iter_dict_val,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING,
+ &iter_array);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ /* Now add all the values */
+ for (i = 0; i < el->num_values; i++) {
+ DEBUG(SSSDBG_TRACE_FUNC, "element [%s] has value [%s]\n",
+ el->name, (const char *) el->values[i].data);
+
+ dbret = dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_STRING,
+ &(el->values[i].data));
+ if (!dbret) {
+ return ENOMEM;
+ }
+ }
+
+ dbret = dbus_message_iter_close_container(&iter_dict_val,
+ &iter_array);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_close_container(&iter_dict_entry,
+ &iter_dict_val);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ dbret = dbus_message_iter_close_container(iter_dict,
+ &iter_dict_entry);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+
+bool
+ifp_attr_allowed(const char *whitelist[], const char *attr)
+{
+ size_t i;
+
+ if (whitelist == NULL) {
+ return false;
+ }
+
+ for (i = 0; whitelist[i]; i++) {
+ if (strcasecmp(whitelist[i], attr) == 0) {
+ break;
+ }
+ }
+
+ return (whitelist[i]) ? true : false;
+}
+
+const char **
+ifp_parse_user_attr_list(TALLOC_CTX *mem_ctx, const char *csv)
+{
+ static const char *defaults[] = IFP_USER_DEFAULT_ATTRS;
+
+ return parse_attr_list_ex(mem_ctx, csv, defaults);
+}
+
+const char **
+ifp_get_user_extra_attributes(TALLOC_CTX *mem_ctx, struct ifp_ctx *ifp_ctx)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ const char *std[] = IFP_USER_DEFAULT_ATTRS;
+ const char **whitelist = ifp_ctx->user_whitelist;
+ const char **extra;
+ bool found;
+ int extra_num;
+ int i, j;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return NULL;
+ }
+
+ for (i = 0; whitelist[i] != NULL; i++) {
+ /* Just count number of attributes in whitelist. */
+ }
+
+ extra = talloc_zero_array(tmp_ctx, const char *, i + 1);
+ if (extra == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
+ goto fail;
+ }
+
+ extra_num = 0;
+ for (i = 0; whitelist[i] != NULL; i++) {
+ found = false;
+ for (j = 0; std[j] != NULL; j++) {
+ if (strcmp(whitelist[i], std[j]) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ extra[extra_num] = talloc_strdup(extra, whitelist[i]);
+ if (extra[extra_num] == NULL) {
+ goto fail;
+ }
+
+ extra_num++;
+ }
+ }
+
+ extra = talloc_realloc(tmp_ctx, extra, const char *, extra_num + 1);
+ if (extra == NULL) {
+ goto fail;
+ }
+
+ talloc_steal(mem_ctx, extra);
+ talloc_free(tmp_ctx);
+ return extra;
+
+fail:
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+bool
+ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr)
+{
+ return ifp_attr_allowed(ifp_ctx->user_whitelist, attr);
+}
+
+static uint32_t ifp_list_limit(struct ifp_ctx *ctx, uint32_t limit)
+{
+ if (limit == 0) {
+ return ctx->wildcard_limit;
+ } else if (ctx->wildcard_limit) {
+ return MIN(ctx->wildcard_limit, limit);
+ } else {
+ return limit;
+ }
+}
+
+struct ifp_list_ctx *ifp_list_ctx_new(TALLOC_CTX *mem_ctx,
+ struct ifp_ctx *ctx,
+ const char *attr,
+ const char *filter,
+ uint32_t limit)
+{
+ struct ifp_list_ctx *list_ctx;
+
+ list_ctx = talloc_zero(mem_ctx, struct ifp_list_ctx);
+ if (list_ctx == NULL) {
+ return NULL;
+ }
+
+ list_ctx->limit = ifp_list_limit(ctx, limit);
+ list_ctx->ctx = ctx;
+ list_ctx->dom = ctx->rctx->domains;
+ list_ctx->attr = attr;
+ list_ctx->filter = filter;
+ list_ctx->paths_max = 1;
+ list_ctx->paths = talloc_zero_array(list_ctx, const char *,
+ list_ctx->paths_max + 1);
+ if (list_ctx->paths == NULL) {
+ talloc_free(list_ctx);
+ return NULL;
+ }
+
+ return list_ctx;
+}
+
+errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
+ size_t entries,
+ size_t *_capacity)
+{
+ size_t capacity = list_ctx->limit - list_ctx->path_count;
+ errno_t ret;
+ size_t c;
+
+ if (list_ctx->limit == 0) {
+ capacity = entries;
+ goto immediately;
+ }
+
+ if (capacity < entries) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "IFP list request has limit of %"PRIu32" entries but back end "
+ "returned %zu entries\n", list_ctx->limit,
+ list_ctx->path_count + entries);
+ } else {
+ capacity = entries;
+ }
+
+immediately:
+ list_ctx->paths_max = list_ctx->path_count + capacity;
+ list_ctx->paths = talloc_realloc(list_ctx, list_ctx->paths, const char *,
+ list_ctx->paths_max + 1);
+ if (list_ctx->paths == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc() failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ for (c = list_ctx->path_count; c <= list_ctx->paths_max; c++) {
+ list_ctx->paths[c] = NULL;
+ }
+
+ *_capacity = capacity;
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+errno_t ifp_ldb_el_output_name(struct resp_ctx *rctx,
+ struct ldb_message *msg,
+ const char *el_name,
+ struct sss_domain_info *dom)
+{
+ struct ldb_message_element *el;
+ char *in_name;
+ char *out_name;
+ errno_t ret;
+ char *name;
+ TALLOC_CTX *tmp_ctx;
+
+ el = ldb_msg_find_element(msg, el_name);
+ if (el == NULL) {
+ return EOK;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ for (size_t c = 0; c < el->num_values; c++) {
+ in_name = (char *) el->values[c].data;
+ ret = sss_parse_internal_fqname(tmp_ctx, in_name, &name, NULL);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ out_name = sss_output_name(tmp_ctx, in_name, dom->case_preserve,
+ rctx->override_space);
+ if (out_name == NULL) {
+ ret = EIO;
+ goto done;
+ }
+
+ if (dom->fqnames) {
+ out_name = sss_tc_fqname(tmp_ctx, dom->names, dom, out_name);
+ if (out_name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_tc_fqname failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ talloc_free(el->values[c].data);
+ el->values[c].data = (uint8_t *) talloc_steal(el->values, out_name);
+ el->values[c].length = strlen(out_name);
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+char *ifp_format_name_attr(TALLOC_CTX *mem_ctx, struct ifp_ctx *ifp_ctx,
+ const char *in_name, struct sss_domain_info *dom)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *out_name;
+ char *ret_name = NULL;
+ char *shortname;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ ret = sss_parse_internal_fqname(tmp_ctx, in_name, &shortname, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unparseable name %s\n", in_name);
+ goto done;
+ }
+
+ out_name = sss_output_name(tmp_ctx, in_name, dom->case_preserve,
+ ifp_ctx->rctx->override_space);
+ if (out_name == NULL) {
+ goto done;
+ }
+
+ if (dom->fqnames) {
+ out_name = sss_tc_fqname(tmp_ctx, dom->names, dom, out_name);
+ if (out_name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_tc_fqname failed\n");
+ goto done;
+ }
+ }
+
+ ret_name = talloc_steal(mem_ctx, out_name);
+done:
+ talloc_free(tmp_ctx);
+ return ret_name;
+}