From bcf1cf2afb9692b0db555e6ecf662a2fbd19793d Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 31 Oct 2016 22:05:11 +0200 Subject: [PATCH] lib: API change - var_expand_func_table.func() can now return error. None of the existing functions were changed to return errors (yet). --- src/auth/auth-request-var-expand.c | 22 +++++++---- src/auth/db-dict.c | 23 +++++++----- src/auth/db-ldap.c | 48 ++++++++++++++++-------- src/lib-storage/mail-storage-service.c | 9 +++-- src/lib-storage/mail-user.c | 9 +++-- src/lib/test-var-expand.c | 51 +++++++++++++++++++++----- src/lib/var-expand.c | 7 ++-- src/lib/var-expand.h | 11 ++++-- src/login-common/client-common.c | 18 ++++++--- 9 files changed, 137 insertions(+), 61 deletions(-) diff --git a/src/auth/auth-request-var-expand.c b/src/auth/auth-request-var-expand.c index ccc49f1f17..3cbfc96c46 100644 --- a/src/auth/auth-request-var-expand.c +++ b/src/auth/auth-request-var-expand.c @@ -195,20 +195,25 @@ static const char *field_get_default(const char *data) } } -static const char * -auth_request_var_expand_func_passdb(const char *data, void *context) +static int +auth_request_var_expand_func_passdb(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct auth_request_var_expand_ctx *ctx = context; const char *field_name = t_strcut(data, ':'); const char *value; value = auth_fields_find(ctx->auth_request->extra_fields, field_name); - return ctx->escape_func(value != NULL ? value : field_get_default(data), - ctx->auth_request); + *value_r = ctx->escape_func(value != NULL ? value : field_get_default(data), + ctx->auth_request); + return 1; } -static const char * -auth_request_var_expand_func_userdb(const char *data, void *context) +static int +auth_request_var_expand_func_userdb(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct auth_request_var_expand_ctx *ctx = context; const char *field_name = t_strcut(data, ':'); @@ -216,8 +221,9 @@ auth_request_var_expand_func_userdb(const char *data, void *context) value = ctx->auth_request->userdb_reply == NULL ? NULL : auth_fields_find(ctx->auth_request->userdb_reply, field_name); - return ctx->escape_func(value != NULL ? value : field_get_default(data), - ctx->auth_request); + *value_r = ctx->escape_func(value != NULL ? value : field_get_default(data), + ctx->auth_request); + return 1; } const struct var_expand_func_table auth_request_var_funcs_table[] = { diff --git a/src/auth/db-dict.c b/src/auth/db-dict.c index c10a5e3f25..4559e556e7 100644 --- a/src/auth/db-dict.c +++ b/src/auth/db-dict.c @@ -567,38 +567,43 @@ db_dict_value_iter_object_next(struct db_dict_value_iter *iter, i_unreached(); } -static const char * -db_dict_field_find(const char *data, void *context) +static int +db_dict_field_find(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct db_dict_value_iter *iter = context; struct db_dict_iter_key *key; - const char *name, *value, *ret, *dotname = strchr(data, '.'); + const char *name, *value, *dotname = strchr(data, '.'); string_t *tmpstr; + *value_r = NULL; + if (dotname != NULL) data = t_strdup_until(data, dotname++); key = db_dict_iter_find_key(iter, data); if (key == NULL) - return NULL; + return 1; switch (key->key->parsed_format) { case DB_DICT_VALUE_FORMAT_VALUE: - return dotname != NULL ? NULL : + *value_r = dotname != NULL ? NULL : (key->value == NULL ? "" : key->value); + return 1; case DB_DICT_VALUE_FORMAT_JSON: if (dotname == NULL) - return NULL; + return 1; db_dict_value_iter_json_init(iter, key->value); - ret = ""; + *value_r = ""; tmpstr = t_str_new(64); while (db_dict_value_iter_json_next(iter, tmpstr, &name, &value)) { if (strcmp(name, dotname) == 0) { - ret = t_strdup(value); + *value_r = t_strdup(value); break; } } (void)json_parser_deinit(&iter->json_parser, &iter->error); - return ret; + return 1; } i_unreached(); } diff --git a/src/auth/db-ldap.c b/src/auth/db-ldap.c index 9fd4ac33f0..efdb4139fe 100644 --- a/src/auth/db-ldap.c +++ b/src/auth/db-ldap.c @@ -593,8 +593,10 @@ struct ldap_field_find_subquery_context { const char *name; }; -static const char * -db_ldap_field_subquery_find(const char *data, void *context) +static int +db_ldap_field_subquery_find(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct ldap_field_find_subquery_context *ctx = context; char *ldap_attr; @@ -609,10 +611,10 @@ db_ldap_field_subquery_find(const char *data, void *context) array_append(&ctx->attr_names, &ldap_attr, 1); } } - return NULL; + *value_r = NULL; + return 1; } - static int ldap_request_send_subquery(struct ldap_connection *conn, struct ldap_request_search *request, @@ -1349,8 +1351,10 @@ struct ldap_field_find_context { pool_t pool; }; -static const char * -db_ldap_field_find(const char *data, void *context) +static int +db_ldap_field_find(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct ldap_field_find_context *ctx = context; char *ldap_attr; @@ -1360,7 +1364,8 @@ db_ldap_field_find(const char *data, void *context) if (strchr(ldap_attr, '@') == NULL) array_append(&ctx->attr_names, &ldap_attr, 1); } - return NULL; + *value_r = NULL; + return 1; } void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist, @@ -1624,7 +1629,9 @@ static const char *db_ldap_field_get_default(const char *data) } } -static const char *db_ldap_field_expand(const char *data, void *context) +static int +db_ldap_field_expand(const char *data, void *context, + const char **value_r, const char **error_r ATTR_UNUSED) { struct db_ldap_result_iterate_context *ctx = context; struct db_ldap_value *ldap_value; @@ -1635,33 +1642,42 @@ static const char *db_ldap_field_expand(const char *data, void *context) /* requested ldap attribute wasn't returned at all */ if (ctx->debug != NULL) str_printfa(ctx->debug, "; %s missing", field_name); - return db_ldap_field_get_default(data); + *value_r = db_ldap_field_get_default(data); + return 1; } ldap_value->used = TRUE; if (ldap_value->values[0] == NULL) { /* no value for ldap attribute */ - return db_ldap_field_get_default(data); + *value_r = db_ldap_field_get_default(data); + return 1; } if (ldap_value->values[1] != NULL) { auth_request_log_warning(ctx->auth_request, AUTH_SUBSYS_DB, "Multiple values found for '%s', using value '%s'", field_name, ldap_value->values[0]); } - return ldap_value->values[0]; + *value_r = ldap_value->values[0]; + return 1; } -static const char *db_ldap_field_ptr_expand(const char *data, void *context) +static int +db_ldap_field_ptr_expand(const char *data, void *context, + const char **value_r, const char **error_r) { struct db_ldap_result_iterate_context *ctx = context; const char *field_name, *suffix; + int ret; suffix = strchr(t_strcut(data, ':'), '@'); - field_name = db_ldap_field_expand(data, ctx); - if (field_name[0] == '\0') - return ""; + if ((ret = db_ldap_field_expand(data, ctx, &field_name, error_r)) <= 0) + return ret; + if (field_name[0] == '\0') { + *value_r = ""; + return 1; + } field_name = t_strconcat(field_name, suffix, NULL); - return db_ldap_field_expand(field_name, ctx); + return db_ldap_field_expand(field_name, ctx, value_r, error_r); } static struct var_expand_func_table ldap_var_funcs_table[] = { diff --git a/src/lib-storage/mail-storage-service.c b/src/lib-storage/mail-storage-service.c index 74b89c3fc8..725eb78f8d 100644 --- a/src/lib-storage/mail-storage-service.c +++ b/src/lib-storage/mail-storage-service.c @@ -793,13 +793,16 @@ const char *mail_storage_service_fields_var_expand(const char *data, return field_get_default(data); } -static const char * -mail_storage_service_input_var_userdb(const char *data, void *context) +static int +mail_storage_service_input_var_userdb(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct mail_storage_service_user *user = context; - return mail_storage_service_fields_var_expand(data, + *value_r = mail_storage_service_fields_var_expand(data, user == NULL ? NULL : user->input.userdb_fields); + return 1; } static int diff --git a/src/lib-storage/mail-user.c b/src/lib-storage/mail-user.c index 5083b1bce2..f3ddd772f8 100644 --- a/src/lib-storage/mail-user.c +++ b/src/lib-storage/mail-user.c @@ -272,12 +272,15 @@ mail_user_var_expand_table(struct mail_user *user) return user->var_expand_table; } -static const char * -mail_user_var_expand_func_userdb(const char *data, void *context) +static int +mail_user_var_expand_func_userdb(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct mail_user *user = context; - return mail_storage_service_fields_var_expand(data, user->userdb_fields); + *value_r = mail_storage_service_fields_var_expand(data, user->userdb_fields); + return 1; } void mail_user_set_home(struct mail_user *user, const char *home) diff --git a/src/lib/test-var-expand.c b/src/lib/test-var-expand.c index 8b23f7ce3d..93d8b60dae 100644 --- a/src/lib/test-var-expand.c +++ b/src/lib/test-var-expand.c @@ -106,22 +106,49 @@ static void test_var_get_key_range(void) test_end(); } -static const char *test_var_expand_func1(const char *data, void *context) +static int test_var_expand_func1(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { test_assert(*(int *)context == 0xabcdef); - return t_strdup_printf("<%s>", data); + *value_r = t_strdup_printf("<%s>", data); + return 1; } -static const char *test_var_expand_func2(const char *data ATTR_UNUSED, - void *context ATTR_UNUSED) +static int test_var_expand_func2(const char *data ATTR_UNUSED, + void *context ATTR_UNUSED, + const char **value_r, + const char **error_r ATTR_UNUSED) { - return ""; + *value_r = ""; + return 1; } -static const char *test_var_expand_func3(const char *data ATTR_UNUSED, - void *context ATTR_UNUSED) +static int test_var_expand_func3(const char *data ATTR_UNUSED, + void *context ATTR_UNUSED, + const char **value_r, + const char **error_r ATTR_UNUSED) { - return NULL; + *value_r = NULL; + return 1; +} + +static int test_var_expand_func4(const char *data, + void *context ATTR_UNUSED, + const char **value_r ATTR_UNUSED, + const char **error_r) +{ + *error_r = t_strdup_printf("Unknown data %s", data == NULL ? "" : data); + return 0; +} + +static int test_var_expand_func5(const char *data ATTR_UNUSED, + void *context ATTR_UNUSED, + const char **value_r ATTR_UNUSED, + const char **error_r) +{ + *error_r = "Internal error"; + return -1; } static void test_var_expand_with_funcs(void) @@ -130,7 +157,11 @@ static void test_var_expand_with_funcs(void) { "%{func1}", "<>", 1 }, { "%{func1:foo}", "", 1 }, { "%{func2}", "", 1 }, - { "%{func3}", "", 1 } + { "%{func3}", "", 1 }, + { "%{func4}", "", 0 }, + { "%{func5}", "", -1 }, + { "%{func4}%{func5}", "", -1 }, + { "%{func5}%{func4}%{func3}", "", -1 }, }; static struct var_expand_table table[] = { { '\0', NULL, NULL } @@ -139,6 +170,8 @@ static void test_var_expand_with_funcs(void) { "func1", test_var_expand_func1 }, { "func2", test_var_expand_func2 }, { "func3", test_var_expand_func3 }, + { "func4", test_var_expand_func4 }, + { "func5", test_var_expand_func5 }, { NULL, NULL } }; string_t *str = t_str_new(128); diff --git a/src/lib/var-expand.c b/src/lib/var-expand.c index 2483cbf047..405e9f7988 100644 --- a/src/lib/var-expand.c +++ b/src/lib/var-expand.c @@ -196,7 +196,8 @@ var_expand_func(const struct var_expand_func_table *func_table, const char *key, const char *data, void *context, const char **var_r, const char **error_r) { - const char *value; + const char *value = NULL; + int ret; if (strcmp(key, "env") == 0) { value = getenv(data); @@ -206,9 +207,9 @@ var_expand_func(const struct var_expand_func_table *func_table, if (func_table != NULL) { for (; func_table->key != NULL; func_table++) { if (strcmp(func_table->key, key) == 0) { - value = func_table->func(data, context); + ret = func_table->func(data, context, &value, error_r); *var_r = value != NULL ? value : ""; - return 1; + return ret; } } } diff --git a/src/lib/var-expand.h b/src/lib/var-expand.h index e93884fd80..40798b0a58 100644 --- a/src/lib/var-expand.h +++ b/src/lib/var-expand.h @@ -9,14 +9,17 @@ struct var_expand_table { struct var_expand_func_table { const char *key; - /* %{key:data}, or data is "" with %{key}, */ - const char *(*func)(const char *data, void *context); + /* %{key:data}, or data is "" with %{key}. + Returns 1 on success, 0 if data is invalid, -1 on temporary error. */ + int (*func)(const char *data, void *context, + const char **value_r, const char **error_r); }; /* Expand % variables in src and append the string in dest. table must end with key = 0. Returns 1 on success, 0 if the format string - contained invalid/unknown %variables. Even in case of errors the dest string - is still written as fully as possible. */ + contained invalid/unknown %variables, -1 if one of the functions returned + temporary error. Even in case of errors the dest string is still written as + fully as possible. */ int var_expand(string_t *dest, const char *str, const struct var_expand_table *table, const char **error_r); diff --git a/src/login-common/client-common.c b/src/login-common/client-common.c index 44377998ae..b08cddc4e0 100644 --- a/src/login-common/client-common.c +++ b/src/login-common/client-common.c @@ -600,24 +600,30 @@ static bool have_username_key(const char *str) return FALSE; } -static const char * -client_var_expand_func_passdb(const char *data, void *context) +static int +client_var_expand_func_passdb(const char *data, void *context, + const char **value_r, + const char **error_r ATTR_UNUSED) { struct client *client = context; const char *field_name = data; unsigned int i, field_name_len; + *value_r = NULL; + if (client->auth_passdb_args == NULL) - return NULL; + return 1; field_name_len = strlen(field_name); for (i = 0; client->auth_passdb_args[i] != NULL; i++) { if (strncmp(client->auth_passdb_args[i], field_name, field_name_len) == 0 && - client->auth_passdb_args[i][field_name_len] == '=') - return client->auth_passdb_args[i] + field_name_len+1; + client->auth_passdb_args[i][field_name_len] == '=') { + *value_r = client->auth_passdb_args[i] + field_name_len+1; + return 1; + } } - return NULL; + return 1; } static const char *