1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3 #include "auth-common.h"
4
5 #include "array.h"
6 #include "istream.h"
7 #include "str.h"
8 #include "json-parser.h"
9 #include "settings.h"
10 #include "dict.h"
11 #include "auth-request.h"
12 #include "auth-worker-client.h"
13 #include "db-dict.h"
14
15 #include <stddef.h>
16
17 enum dict_settings_section {
18 DICT_SETTINGS_SECTION_ROOT = 0,
19 DICT_SETTINGS_SECTION_KEY,
20 DICT_SETTINGS_SECTION_PASSDB,
21 DICT_SETTINGS_SECTION_USERDB
22 };
23
24 struct dict_settings_parser_ctx {
25 struct dict_connection *conn;
26 enum dict_settings_section section;
27 struct db_dict_key *cur_key;
28 };
29
30 struct db_dict_iter_key {
31 const struct db_dict_key *key;
32 bool used;
33 const char *value;
34 };
35
36 struct db_dict_value_iter {
37 pool_t pool;
38 struct auth_request *auth_request;
39 struct dict_connection *conn;
40 const struct var_expand_table *var_expand_table;
41 ARRAY(struct db_dict_iter_key) keys;
42
43 const ARRAY_TYPE(db_dict_field) *fields;
44 const ARRAY_TYPE(db_dict_key_p) *objects;
45 unsigned int field_idx;
46 unsigned int object_idx;
47
48 struct json_parser *json_parser;
49 string_t *tmpstr;
50 const char *error;
51 };
52
53 #define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_settings)
54 #define DEF_BOOL(name) DEF_STRUCT_BOOL(name, db_dict_settings)
55 static struct setting_def setting_defs[] = {
56 DEF_STR(uri),
57 DEF_STR(default_pass_scheme),
58 DEF_STR(iterate_prefix),
59 DEF_BOOL(iterate_disable),
60
61 DEF_STR(passdb_objects),
62 DEF_STR(userdb_objects),
63 { 0, NULL, 0 }
64 };
65
66 static struct db_dict_settings default_dict_settings = {
67 .uri = NULL,
68 .default_pass_scheme = "MD5",
69 .iterate_prefix = "",
70 .iterate_disable = FALSE,
71 .passdb_objects = "",
72 .userdb_objects = ""
73 };
74
75 #undef DEF_STR
76 #define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_key)
77 static struct setting_def key_setting_defs[] = {
78 DEF_STR(name),
79 DEF_STR(key),
80 DEF_STR(format),
81 DEF_STR(default_value),
82
83 { 0, NULL, 0 }
84 };
85
86 static struct db_dict_key default_key_settings = {
87 .name = NULL,
88 .key = "",
89 .format = "value",
90 .default_value = NULL
91 };
92
93 static struct dict_connection *connections = NULL;
94
dict_conn_find(const char * config_path)95 static struct dict_connection *dict_conn_find(const char *config_path)
96 {
97 struct dict_connection *conn;
98
99 for (conn = connections; conn != NULL; conn = conn->next) {
100 if (strcmp(conn->config_path, config_path) == 0)
101 return conn;
102 }
103
104 return NULL;
105 }
106
107 static bool
parse_obsolete_setting(const char * key,const char * value,struct dict_settings_parser_ctx * ctx,const char ** error_r)108 parse_obsolete_setting(const char *key, const char *value,
109 struct dict_settings_parser_ctx *ctx,
110 const char **error_r)
111 {
112 const struct db_dict_key *dbkey;
113
114 if (strcmp(key, "password_key") == 0) {
115 /* key passdb { key=<value> format=json }
116 passdb_objects = passdb */
117 ctx->cur_key = array_append_space(&ctx->conn->set.keys);
118 *ctx->cur_key = default_key_settings;
119 ctx->cur_key->name = "passdb";
120 ctx->cur_key->format = "json";
121 ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON;
122 ctx->cur_key->key = p_strdup(ctx->conn->pool, value);
123
124 dbkey = ctx->cur_key;
125 array_push_back(&ctx->conn->set.parsed_passdb_objects, &dbkey);
126 return TRUE;
127 }
128 if (strcmp(key, "user_key") == 0) {
129 /* key userdb { key=<value> format=json }
130 userdb_objects = userdb */
131 ctx->cur_key = array_append_space(&ctx->conn->set.keys);
132 *ctx->cur_key = default_key_settings;
133 ctx->cur_key->name = "userdb";
134 ctx->cur_key->format = "json";
135 ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON;
136 ctx->cur_key->key = p_strdup(ctx->conn->pool, value);
137
138 dbkey = ctx->cur_key;
139 array_push_back(&ctx->conn->set.parsed_userdb_objects, &dbkey);
140 return TRUE;
141 }
142 if (strcmp(key, "value_format") == 0) {
143 if (strcmp(value, "json") == 0)
144 return TRUE;
145 *error_r = "Deprecated value_format must be 'json'";
146 return FALSE;
147 }
148 return FALSE;
149 }
150
parse_setting(const char * key,const char * value,struct dict_settings_parser_ctx * ctx)151 static const char *parse_setting(const char *key, const char *value,
152 struct dict_settings_parser_ctx *ctx)
153 {
154 struct db_dict_field *field;
155 const char *error = NULL;
156
157 switch (ctx->section) {
158 case DICT_SETTINGS_SECTION_ROOT:
159 if (parse_obsolete_setting(key, value, ctx, &error))
160 return NULL;
161 if (error != NULL)
162 return error;
163 return parse_setting_from_defs(ctx->conn->pool, setting_defs,
164 &ctx->conn->set, key, value);
165 case DICT_SETTINGS_SECTION_KEY:
166 return parse_setting_from_defs(ctx->conn->pool, key_setting_defs,
167 ctx->cur_key, key, value);
168 case DICT_SETTINGS_SECTION_PASSDB:
169 field = array_append_space(&ctx->conn->set.passdb_fields);
170 field->name = p_strdup(ctx->conn->pool, key);
171 field->value = p_strdup(ctx->conn->pool, value);
172 return NULL;
173 case DICT_SETTINGS_SECTION_USERDB:
174 field = array_append_space(&ctx->conn->set.userdb_fields);
175 field->name = p_strdup(ctx->conn->pool, key);
176 field->value = p_strdup(ctx->conn->pool, value);
177 return NULL;
178 }
179 i_unreached();
180 }
181
parse_section(const char * type,const char * name,struct dict_settings_parser_ctx * ctx,const char ** errormsg)182 static bool parse_section(const char *type, const char *name,
183 struct dict_settings_parser_ctx *ctx,
184 const char **errormsg)
185 {
186 if (type == NULL) {
187 ctx->section = DICT_SETTINGS_SECTION_ROOT;
188 if (ctx->cur_key != NULL) {
189 if (strcmp(ctx->cur_key->format, "value") == 0) {
190 ctx->cur_key->parsed_format =
191 DB_DICT_VALUE_FORMAT_VALUE;
192 } else if (strcmp(ctx->cur_key->format, "json") == 0) {
193 ctx->cur_key->parsed_format =
194 DB_DICT_VALUE_FORMAT_JSON;
195 } else {
196 *errormsg = t_strconcat("Unknown key format: ",
197 ctx->cur_key->format, NULL);
198 return FALSE;
199 }
200 }
201 ctx->cur_key = NULL;
202 return TRUE;
203 }
204 if (ctx->section != DICT_SETTINGS_SECTION_ROOT) {
205 *errormsg = "Nested sections not supported";
206 return FALSE;
207 }
208 if (strcmp(type, "key") == 0) {
209 if (name == NULL) {
210 *errormsg = "Key section is missing name";
211 return FALSE;
212 }
213 if (strchr(name, '.') != NULL) {
214 *errormsg = "Key section names must not contain '.'";
215 return FALSE;
216 }
217 ctx->section = DICT_SETTINGS_SECTION_KEY;
218 ctx->cur_key = array_append_space(&ctx->conn->set.keys);
219 *ctx->cur_key = default_key_settings;
220 ctx->cur_key->name = p_strdup(ctx->conn->pool, name);
221 return TRUE;
222 }
223 if (strcmp(type, "passdb_fields") == 0) {
224 ctx->section = DICT_SETTINGS_SECTION_PASSDB;
225 return TRUE;
226 }
227 if (strcmp(type, "userdb_fields") == 0) {
228 ctx->section = DICT_SETTINGS_SECTION_USERDB;
229 return TRUE;
230 }
231 *errormsg = "Unknown section";
232 return FALSE;
233 }
234
235 static void
db_dict_settings_parse(struct db_dict_settings * set)236 db_dict_settings_parse(struct db_dict_settings *set)
237 {
238 const struct db_dict_key *key;
239 const char *const *tmp;
240
241 tmp = t_strsplit_spaces(set->passdb_objects, " ");
242 for (; *tmp != NULL; tmp++) {
243 key = db_dict_set_key_find(&set->keys, *tmp);
244 if (key == NULL) {
245 i_fatal("dict: passdb_objects refers to key %s, "
246 "which doesn't exist", *tmp);
247 }
248 if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
249 i_fatal("dict: passdb_objects refers to key %s, "
250 "but it's in value-only format", *tmp);
251 }
252 array_push_back(&set->parsed_passdb_objects, &key);
253 }
254
255 tmp = t_strsplit_spaces(set->userdb_objects, " ");
256 for (; *tmp != NULL; tmp++) {
257 key = db_dict_set_key_find(&set->keys, *tmp);
258 if (key == NULL) {
259 i_fatal("dict: userdb_objects refers to key %s, "
260 "which doesn't exist", *tmp);
261 }
262 if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
263 i_fatal("dict: userdb_objects refers to key %s, "
264 "but it's in value-only format", *tmp);
265 }
266 array_push_back(&set->parsed_userdb_objects, &key);
267 }
268 }
269
db_dict_init(const char * config_path)270 struct dict_connection *db_dict_init(const char *config_path)
271 {
272 struct dict_settings dict_set;
273 struct dict_settings_parser_ctx ctx;
274 struct dict_connection *conn;
275 const char *error;
276 pool_t pool;
277
278 conn = dict_conn_find(config_path);
279 if (conn != NULL) {
280 conn->refcount++;
281 return conn;
282 }
283
284 if (*config_path == '\0')
285 i_fatal("dict: Configuration file path not given");
286
287 pool = pool_alloconly_create("dict_connection", 1024);
288 conn = p_new(pool, struct dict_connection, 1);
289 conn->pool = pool;
290
291 conn->refcount = 1;
292
293 conn->config_path = p_strdup(pool, config_path);
294 conn->set = default_dict_settings;
295 p_array_init(&conn->set.keys, pool, 8);
296 p_array_init(&conn->set.passdb_fields, pool, 8);
297 p_array_init(&conn->set.userdb_fields, pool, 8);
298 p_array_init(&conn->set.parsed_passdb_objects, pool, 2);
299 p_array_init(&conn->set.parsed_userdb_objects, pool, 2);
300
301 i_zero(&ctx);
302 ctx.conn = conn;
303 if (!settings_read(config_path, NULL, parse_setting,
304 parse_section, &ctx, &error))
305 i_fatal("dict %s: %s", config_path, error);
306 db_dict_settings_parse(&conn->set);
307
308 if (conn->set.uri == NULL)
309 i_fatal("dict %s: Empty uri setting", config_path);
310
311 i_zero(&dict_set);
312 dict_set.base_dir = global_auth_settings->base_dir;
313 dict_set.event_parent = auth_event;
314 if (dict_init(conn->set.uri, &dict_set, &conn->dict, &error) < 0)
315 i_fatal("dict %s: Failed to init dict: %s", config_path, error);
316
317 conn->next = connections;
318 connections = conn;
319 return conn;
320 }
321
db_dict_unref(struct dict_connection ** _conn)322 void db_dict_unref(struct dict_connection **_conn)
323 {
324 struct dict_connection *conn = *_conn;
325
326 *_conn = NULL;
327 if (--conn->refcount > 0)
328 return;
329
330 dict_deinit(&conn->dict);
331 pool_unref(&conn->pool);
332 }
333
334 static struct db_dict_iter_key *
db_dict_iter_find_key(struct db_dict_value_iter * iter,const char * name)335 db_dict_iter_find_key(struct db_dict_value_iter *iter, const char *name)
336 {
337 struct db_dict_iter_key *key;
338
339 array_foreach_modifiable(&iter->keys, key) {
340 if (strcmp(key->key->name, name) == 0)
341 return key;
342 }
343 return NULL;
344 }
345
db_dict_iter_find_used_keys(struct db_dict_value_iter * iter)346 static void db_dict_iter_find_used_keys(struct db_dict_value_iter *iter)
347 {
348 const struct db_dict_field *field;
349 struct db_dict_iter_key *key;
350 const char *p, *name;
351 unsigned int idx, size;
352
353 array_foreach(iter->fields, field) {
354 for (p = field->value; *p != '\0'; ) {
355 if (*p != '%') {
356 p++;
357 continue;
358 }
359
360 var_get_key_range(++p, &idx, &size);
361 if (size == 0) {
362 /* broken %variable ending too early */
363 break;
364 }
365 p += idx;
366 if (size > 5 && memcmp(p, "dict:", 5) == 0) {
367 name = t_strcut(t_strndup(p+5, size-5), ':');
368 key = db_dict_iter_find_key(iter, name);
369 if (key != NULL)
370 key->used = TRUE;
371 }
372 p += size;
373 }
374 }
375 }
376
db_dict_iter_find_used_objects(struct db_dict_value_iter * iter)377 static void db_dict_iter_find_used_objects(struct db_dict_value_iter *iter)
378 {
379 const struct db_dict_key *dict_key;
380 struct db_dict_iter_key *key;
381
382 array_foreach_elem(iter->objects, dict_key) {
383 key = db_dict_iter_find_key(iter, dict_key->name);
384 i_assert(key != NULL); /* checked at init */
385 i_assert(key->key->parsed_format != DB_DICT_VALUE_FORMAT_VALUE);
386 key->used = TRUE;
387 }
388 }
389
390 static int
db_dict_iter_key_cmp(const struct db_dict_iter_key * k1,const struct db_dict_iter_key * k2)391 db_dict_iter_key_cmp(const struct db_dict_iter_key *k1,
392 const struct db_dict_iter_key *k2)
393 {
394 return null_strcmp(k1->key->default_value, k2->key->default_value);
395 }
396
db_dict_iter_lookup_key_values(struct db_dict_value_iter * iter)397 static int db_dict_iter_lookup_key_values(struct db_dict_value_iter *iter)
398 {
399 struct db_dict_iter_key *key;
400 string_t *path;
401 const char *error;
402 int ret;
403
404 /* sort the keys so that we'll first lookup the keys without
405 default value. if their lookup fails, the user doesn't exist. */
406 array_sort(&iter->keys, db_dict_iter_key_cmp);
407
408 path = t_str_new(128);
409 str_append(path, DICT_PATH_SHARED);
410
411 struct dict_op_settings set = {
412 .username = iter->auth_request->fields.user,
413 };
414
415 array_foreach_modifiable(&iter->keys, key) {
416 if (!key->used)
417 continue;
418
419 str_truncate(path, strlen(DICT_PATH_SHARED));
420 str_append(path, key->key->key);
421 ret = dict_lookup(iter->conn->dict, &set, iter->pool,
422 str_c(path), &key->value, &error);
423 if (ret > 0) {
424 e_debug(authdb_event(iter->auth_request),
425 "Lookup: %s = %s", str_c(path),
426 key->value);
427 } else if (ret < 0) {
428 e_error(authdb_event(iter->auth_request),
429 "Failed to lookup key %s: %s", str_c(path), error);
430 return -1;
431 } else if (key->key->default_value != NULL) {
432 e_debug(authdb_event(iter->auth_request),
433 "Lookup: %s not found, using default value %s",
434 str_c(path), key->key->default_value);
435 key->value = key->key->default_value;
436 } else {
437 return 0;
438 }
439 }
440 return 1;
441 }
442
db_dict_value_iter_init(struct dict_connection * conn,struct auth_request * auth_request,const ARRAY_TYPE (db_dict_field)* fields,const ARRAY_TYPE (db_dict_key_p)* objects,struct db_dict_value_iter ** iter_r)443 int db_dict_value_iter_init(struct dict_connection *conn,
444 struct auth_request *auth_request,
445 const ARRAY_TYPE(db_dict_field) *fields,
446 const ARRAY_TYPE(db_dict_key_p) *objects,
447 struct db_dict_value_iter **iter_r)
448 {
449 struct db_dict_value_iter *iter;
450 struct db_dict_iter_key *iterkey;
451 const struct db_dict_key *key;
452 pool_t pool;
453 int ret;
454
455 pool = pool_alloconly_create(MEMPOOL_GROWING"auth dict lookup", 1024);
456 iter = p_new(pool, struct db_dict_value_iter, 1);
457 iter->pool = pool;
458 iter->conn = conn;
459 iter->fields = fields;
460 iter->objects = objects;
461 iter->tmpstr = str_new(pool, 128);
462 iter->auth_request = auth_request;
463 iter->var_expand_table = auth_request_get_var_expand_table(auth_request, NULL);
464
465 /* figure out what keys we need to lookup, and lookup them */
466 p_array_init(&iter->keys, pool, array_count(&conn->set.keys));
467 array_foreach(&conn->set.keys, key) {
468 iterkey = array_append_space(&iter->keys);
469 struct db_dict_key *new_key = p_new(iter->pool, struct db_dict_key, 1);
470 memcpy(new_key, key, sizeof(struct db_dict_key));
471 string_t *expanded_key = str_new(iter->pool, strlen(key->key));
472 const char *error;
473 if (auth_request_var_expand_with_table(expanded_key, key->key, auth_request,
474 iter->var_expand_table,
475 NULL, &error) <= 0) {
476 e_error(authdb_event(iter->auth_request),
477 "Failed to expand key %s: %s", key->key, error);
478 pool_unref(&pool);
479 return -1;
480 }
481 new_key->key = str_c(expanded_key);
482 iterkey->key = new_key;
483 }
484 T_BEGIN {
485 db_dict_iter_find_used_keys(iter);
486 db_dict_iter_find_used_objects(iter);
487 ret = db_dict_iter_lookup_key_values(iter);
488 } T_END;
489 if (ret <= 0) {
490 pool_unref(&pool);
491 return ret;
492 }
493 *iter_r = iter;
494 return 1;
495 }
496
497 static bool
db_dict_value_iter_json_next(struct db_dict_value_iter * iter,string_t * tmpstr,const char ** key_r,const char ** value_r)498 db_dict_value_iter_json_next(struct db_dict_value_iter *iter,
499 string_t *tmpstr,
500 const char **key_r, const char **value_r)
501 {
502 enum json_type type;
503 const char *value;
504
505 if (json_parse_next(iter->json_parser, &type, &value) < 0)
506 return FALSE;
507 if (type != JSON_TYPE_OBJECT_KEY) {
508 iter->error = "Object expected";
509 return FALSE;
510 }
511 if (*value == '\0') {
512 iter->error = "Empty object key";
513 return FALSE;
514 }
515 str_truncate(tmpstr, 0);
516 str_append(tmpstr, value);
517
518 if (json_parse_next(iter->json_parser, &type, &value) < 0) {
519 iter->error = "Missing value";
520 return FALSE;
521 }
522 if (type == JSON_TYPE_OBJECT) {
523 iter->error = "Nested objects not supported";
524 return FALSE;
525 }
526 *key_r = str_c(tmpstr);
527 *value_r = value;
528 return TRUE;
529 }
530
531 static void
db_dict_value_iter_json_init(struct db_dict_value_iter * iter,const char * data)532 db_dict_value_iter_json_init(struct db_dict_value_iter *iter, const char *data)
533 {
534 struct istream *input;
535
536 i_assert(iter->json_parser == NULL);
537
538 input = i_stream_create_from_data(data, strlen(data));
539 iter->json_parser = json_parser_init(input);
540 i_stream_unref(&input);
541 }
542
543 static bool
db_dict_value_iter_object_next(struct db_dict_value_iter * iter,const char ** key_r,const char ** value_r)544 db_dict_value_iter_object_next(struct db_dict_value_iter *iter,
545 const char **key_r, const char **value_r)
546 {
547 const struct db_dict_key *dict_key;
548 struct db_dict_iter_key *key;
549
550 if (iter->json_parser != NULL)
551 return db_dict_value_iter_json_next(iter, iter->tmpstr, key_r, value_r);
552 if (iter->object_idx == array_count(iter->objects))
553 return FALSE;
554
555 dict_key = array_idx_elem(iter->objects, iter->object_idx);
556 key = db_dict_iter_find_key(iter, dict_key->name);
557 i_assert(key != NULL); /* checked at init */
558
559 switch (key->key->parsed_format) {
560 case DB_DICT_VALUE_FORMAT_VALUE:
561 i_unreached();
562 case DB_DICT_VALUE_FORMAT_JSON:
563 db_dict_value_iter_json_init(iter, key->value);
564 return db_dict_value_iter_json_next(iter, iter->tmpstr, key_r, value_r);
565 }
566 i_unreached();
567 }
568
569 static int
db_dict_field_find(const char * data,void * context,const char ** value_r,const char ** error_r ATTR_UNUSED)570 db_dict_field_find(const char *data, void *context,
571 const char **value_r,
572 const char **error_r ATTR_UNUSED)
573 {
574 struct db_dict_value_iter *iter = context;
575 struct db_dict_iter_key *key;
576 const char *name, *value, *dotname = strchr(data, '.');
577 string_t *tmpstr;
578
579 *value_r = NULL;
580
581 if (dotname != NULL)
582 data = t_strdup_until(data, dotname++);
583 key = db_dict_iter_find_key(iter, data);
584 if (key == NULL)
585 return 1;
586
587 switch (key->key->parsed_format) {
588 case DB_DICT_VALUE_FORMAT_VALUE:
589 *value_r = dotname != NULL ? NULL :
590 (key->value == NULL ? "" : key->value);
591 return 1;
592 case DB_DICT_VALUE_FORMAT_JSON:
593 if (dotname == NULL)
594 return 1;
595 db_dict_value_iter_json_init(iter, key->value);
596 *value_r = "";
597 tmpstr = t_str_new(64);
598 while (db_dict_value_iter_json_next(iter, tmpstr, &name, &value)) {
599 if (strcmp(name, dotname) == 0) {
600 *value_r = t_strdup(value);
601 break;
602 }
603 }
604 (void)json_parser_deinit(&iter->json_parser, &iter->error);
605 return 1;
606 }
607 i_unreached();
608 }
609
db_dict_value_iter_next(struct db_dict_value_iter * iter,const char ** key_r,const char ** value_r)610 bool db_dict_value_iter_next(struct db_dict_value_iter *iter,
611 const char **key_r, const char **value_r)
612 {
613 static struct var_expand_func_table var_funcs_table[] = {
614 { "dict", db_dict_field_find },
615 { NULL, NULL }
616 };
617 const struct db_dict_field *field;
618 const char *error;
619
620 if (iter->field_idx == array_count(iter->fields))
621 return db_dict_value_iter_object_next(iter, key_r, value_r);
622 field = array_idx(iter->fields, iter->field_idx++);
623
624 str_truncate(iter->tmpstr, 0);
625 if (var_expand_with_funcs(iter->tmpstr, field->value,
626 iter->var_expand_table, var_funcs_table,
627 iter, &error) <= 0) {
628 iter->error = p_strdup_printf(iter->pool,
629 "Failed to expand %s=%s: %s",
630 field->name, field->value, error);
631 return FALSE;
632 }
633 *key_r = field->name;
634 *value_r = str_c(iter->tmpstr);
635 return TRUE;
636 }
637
db_dict_value_iter_deinit(struct db_dict_value_iter ** _iter,const char ** error_r)638 int db_dict_value_iter_deinit(struct db_dict_value_iter **_iter,
639 const char **error_r)
640 {
641 struct db_dict_value_iter *iter = *_iter;
642
643 *_iter = NULL;
644
645 *error_r = iter->error;
646 if (iter->json_parser != NULL) {
647 if (json_parser_deinit(&iter->json_parser, &iter->error) < 0 &&
648 *error_r == NULL)
649 *error_r = iter->error;
650 }
651
652 pool_unref(&iter->pool);
653 return *error_r != NULL ? -1 : 0;
654 }
655