diff options
Diffstat (limited to 'src/auth/auth-fields.c')
-rw-r--r-- | src/auth/auth-fields.c | 226 |
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); + } +} |