summaryrefslogtreecommitdiffstats
path: root/src/auth/auth-fields.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/auth/auth-fields.c')
-rw-r--r--src/auth/auth-fields.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/auth/auth-fields.c b/src/auth/auth-fields.c
new file mode 100644
index 0000000..0771390
--- /dev/null
+++ b/src/auth/auth-fields.c
@@ -0,0 +1,226 @@
+/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
+
+#include "auth-common.h"
+#include "array.h"
+#include "str.h"
+#include "strescape.h"
+#include "ostream.h"
+#include "auth-request.h"
+#include "auth-fields.h"
+
+struct auth_fields {
+ pool_t pool;
+ ARRAY_TYPE(auth_field) fields, snapshot_fields;
+ unsigned int snapshot_idx;
+ bool snapshotted;
+};
+
+struct auth_fields *auth_fields_init(pool_t pool)
+{
+ struct auth_fields *fields;
+
+ fields = p_new(pool, struct auth_fields, 1);
+ fields->pool = pool;
+ return fields;
+}
+
+static void auth_fields_snapshot_preserve(struct auth_fields *fields)
+{
+ if (!fields->snapshotted || array_is_created(&fields->snapshot_fields))
+ return;
+
+ p_array_init(&fields->snapshot_fields, fields->pool,
+ array_count(&fields->fields));
+ array_append_array(&fields->snapshot_fields, &fields->fields);
+}
+
+static bool
+auth_fields_find_idx(struct auth_fields *fields, const char *key,
+ unsigned int *idx_r)
+{
+ const struct auth_field *f;
+ unsigned int i, count;
+
+ if (!array_is_created(&fields->fields))
+ return FALSE;
+
+ f = array_get(&fields->fields, &count);
+ for (i = 0; i < count; i++) {
+ if (strcmp(f[i].key, key) == 0) {
+ *idx_r = i;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void auth_fields_add(struct auth_fields *fields,
+ const char *key, const char *value,
+ enum auth_field_flags flags)
+{
+ struct auth_field *field;
+ unsigned int idx;
+
+ i_assert(*key != '\0');
+ i_assert(strchr(key, '\t') == NULL &&
+ strchr(key, '\n') == NULL);
+
+ if (!auth_fields_find_idx(fields, key, &idx)) {
+ if (!array_is_created(&fields->fields))
+ p_array_init(&fields->fields, fields->pool, 16);
+
+ field = array_append_space(&fields->fields);
+ field->key = p_strdup(fields->pool, key);
+ } else {
+ auth_fields_snapshot_preserve(fields);
+ field = array_idx_modifiable(&fields->fields, idx);
+ }
+ field->value = p_strdup_empty(fields->pool, value);
+ field->flags = flags | AUTH_FIELD_FLAG_CHANGED;
+}
+
+void auth_fields_remove(struct auth_fields *fields, const char *key)
+{
+ unsigned int idx;
+
+ if (auth_fields_find_idx(fields, key, &idx)) {
+ auth_fields_snapshot_preserve(fields);
+ array_delete(&fields->fields, idx, 1);
+ }
+}
+
+const char *auth_fields_find(struct auth_fields *fields, const char *key)
+{
+ const struct auth_field *field;
+ unsigned int idx;
+
+ if (!auth_fields_find_idx(fields, key, &idx))
+ return NULL;
+
+ field = array_idx(&fields->fields, idx);
+ return field->value == NULL ? "" : field->value;
+}
+
+bool auth_fields_exists(struct auth_fields *fields, const char *key)
+{
+ return auth_fields_find(fields, key) != NULL;
+}
+
+void auth_fields_reset(struct auth_fields *fields)
+{
+ if (array_is_created(&fields->fields)) {
+ auth_fields_snapshot_preserve(fields);
+ array_clear(&fields->fields);
+ }
+}
+
+void auth_fields_import_prefixed(struct auth_fields *fields, const char *prefix,
+ const char *str, enum auth_field_flags flags)
+{
+ T_BEGIN {
+ const char *const *arg = t_strsplit_tabescaped(str);
+ const char *key, *value;
+
+ for (; *arg != NULL; arg++) {
+ value = strchr(*arg, '=');
+ if (value == NULL) {
+ key = *arg;
+ value = NULL;
+ } else {
+ key = t_strdup_until(*arg, value++);
+ if (*prefix != '\0')
+ key = t_strconcat(prefix, key, NULL);
+ }
+ auth_fields_add(fields, key, value, flags);
+ }
+ } T_END;
+}
+
+void auth_fields_import(struct auth_fields *fields, const char *str,
+ enum auth_field_flags flags)
+{
+ auth_fields_import_prefixed(fields, "", str, flags);
+}
+
+const ARRAY_TYPE(auth_field) *auth_fields_export(struct auth_fields *fields)
+{
+ if (!array_is_created(&fields->fields))
+ p_array_init(&fields->fields, fields->pool, 1);
+ return &fields->fields;
+}
+
+void auth_fields_append(struct auth_fields *fields, string_t *dest,
+ enum auth_field_flags flags_mask,
+ enum auth_field_flags flags_result)
+{
+ const struct auth_field *f;
+ unsigned int i, count;
+ bool first = TRUE;
+
+ if (!array_is_created(&fields->fields))
+ return;
+
+ f = array_get(&fields->fields, &count);
+ for (i = 0; i < count; i++) {
+ if ((f[i].flags & flags_mask) != flags_result)
+ continue;
+
+ if (first)
+ first = FALSE;
+ else
+ str_append_c(dest, '\t');
+ str_append(dest, f[i].key);
+ if (f[i].value != NULL) {
+ str_append_c(dest, '=');
+ str_append_tabescaped(dest, f[i].value);
+ }
+ }
+}
+
+bool auth_fields_is_empty(struct auth_fields *fields)
+{
+ return fields == NULL || !array_is_created(&fields->fields) ||
+ array_count(&fields->fields) == 0;
+}
+
+void auth_fields_booleanize(struct auth_fields *fields, const char *key)
+{
+ struct auth_field *field;
+ unsigned int idx;
+
+ if (auth_fields_find_idx(fields, key, &idx)) {
+ field = array_idx_modifiable(&fields->fields, idx);
+ field->value = NULL;
+ }
+}
+
+void auth_fields_snapshot(struct auth_fields *fields)
+{
+ struct auth_field *field;
+
+ fields->snapshotted = TRUE;
+ if (!array_is_created(&fields->fields))
+ return;
+
+ if (!array_is_created(&fields->snapshot_fields)) {
+ /* try to avoid creating this array */
+ fields->snapshot_idx = array_count(&fields->fields);
+ } else {
+ array_clear(&fields->snapshot_fields);
+ array_append_array(&fields->snapshot_fields, &fields->fields);
+ }
+ array_foreach_modifiable(&fields->fields, field)
+ field->flags &= ENUM_NEGATE(AUTH_FIELD_FLAG_CHANGED);
+}
+
+void auth_fields_rollback(struct auth_fields *fields)
+{
+ if (array_is_created(&fields->snapshot_fields)) {
+ array_clear(&fields->fields);
+ array_append_array(&fields->fields, &fields->snapshot_fields);
+ } else if (array_is_created(&fields->fields)) {
+ array_delete(&fields->fields, fields->snapshot_idx,
+ array_count(&fields->fields) -
+ fields->snapshot_idx);
+ }
+}