dovecot-2.2: dict-sql: If value isn't a hexblob as expected, log...
dovecot at dovecot.org
dovecot at dovecot.org
Fri Sep 25 15:18:20 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/fbff1e801300
changeset: 19220:fbff1e801300
user: Timo Sirainen <tss at iki.fi>
date: Fri Sep 25 18:16:56 2015 +0300
description:
dict-sql: If value isn't a hexblob as expected, log an error instead of killing the whole process.
diffstat:
src/lib-dict/dict-sql.c | 184 +++++++++++++++++++++++++++++++----------------
1 files changed, 120 insertions(+), 64 deletions(-)
diffs (truncated from 445 to 300 lines):
diff -r 8183663ad7c0 -r fbff1e801300 src/lib-dict/dict-sql.c
--- a/src/lib-dict/dict-sql.c Thu Sep 24 20:58:04 2015 +0300
+++ b/src/lib-dict/dict-sql.c Fri Sep 25 18:16:56 2015 +0300
@@ -211,44 +211,48 @@
return NULL;
}
-static void
+static int
sql_dict_value_escape(string_t *str, struct sql_dict *dict,
bool value_is_hexblob, const char *field_name,
- const char *value, const char *value_suffix)
+ const char *value, const char *value_suffix,
+ const char **error_r)
{
buffer_t *buf;
if (!value_is_hexblob) {
str_printfa(str, "'%s%s'", sql_escape_string(dict->db, value),
value_suffix);
- return;
+ return 0;
}
buf = buffer_create_dynamic(pool_datastack_create(), strlen(value)/2);
if (hex_to_binary(value, buf) < 0) {
/* we shouldn't get untrusted input here. it's also a bit
annoying to handle this error. */
- i_fatal("dict-sql: field %s value isn't hexblob: %s",
- field_name, value);
+ *error_r = t_strdup_printf("field %s value isn't hexblob: %s",
+ field_name, value);
+ return -1;
}
str_append(buf, value_suffix);
str_append(str, sql_escape_blob(dict->db, buf->data, buf->used));
+ return 0;
}
-static void
+static int
sql_dict_field_escape_value(string_t *str, struct sql_dict *dict,
const struct dict_sql_field *field,
- const char *value, const char *value_suffix)
+ const char *value, const char *value_suffix,
+ const char **error_r)
{
- sql_dict_value_escape(str, dict, field->value_is_hexblob,
- field->name, value, value_suffix);
+ return sql_dict_value_escape(str, dict, field->value_is_hexblob,
+ field->name, value, value_suffix, error_r);
}
-static void
+static int
sql_dict_where_build(struct sql_dict *dict, const struct dict_sql_map *map,
const ARRAY_TYPE(const_string) *values_arr,
char key1, enum sql_recurse_type recurse_type,
- string_t *query)
+ string_t *query, const char **error_r)
{
const struct dict_sql_field *sql_fields;
const char *const *values;
@@ -262,7 +266,7 @@
if (count2 == 0 && !priv) {
/* we want everything */
- return;
+ return 0;
}
str_append(query, " WHERE");
@@ -272,7 +276,9 @@
if (i > 0)
str_append(query, " AND");
str_printfa(query, " %s = ", sql_fields[i].name);
- sql_dict_field_escape_value(query, dict, &sql_fields[i], values[i], "");
+ if (sql_dict_field_escape_value(query, dict, &sql_fields[i],
+ values[i], "", error_r) < 0)
+ return -1;
}
switch (recurse_type) {
case SQL_DICT_RECURSE_NONE:
@@ -282,11 +288,13 @@
str_append(query, " AND");
if (i < count2) {
str_printfa(query, " %s LIKE ", sql_fields[i].name);
- sql_dict_field_escape_value(query, dict, &sql_fields[i],
- values[i], "/%");
+ if (sql_dict_field_escape_value(query, dict, &sql_fields[i],
+ values[i], "/%", error_r) < 0)
+ return -1;
str_printfa(query, " AND %s NOT LIKE ", sql_fields[i].name);
- sql_dict_field_escape_value(query, dict, &sql_fields[i],
- values[i], "/%/%");
+ if (sql_dict_field_escape_value(query, dict, &sql_fields[i],
+ values[i], "/%/%", error_r) < 0)
+ return -1;
} else {
str_printfa(query, " %s LIKE '%%' AND "
"%s NOT LIKE '%%/%%'",
@@ -299,8 +307,9 @@
str_append(query, " AND");
str_printfa(query, " %s LIKE ",
sql_fields[i].name);
- sql_dict_field_escape_value(query, dict, &sql_fields[i],
- values[i], "/%");
+ if (sql_dict_field_escape_value(query, dict, &sql_fields[i],
+ values[i], "/%", error_r) < 0)
+ return -1;
}
break;
}
@@ -310,6 +319,7 @@
str_printfa(query, " %s = '%s'", map->username_field,
sql_escape_string(dict->db, dict->username));
}
+ return 0;
}
static int
@@ -318,6 +328,7 @@
{
const struct dict_sql_map *map;
ARRAY_TYPE(const_string) values;
+ const char *error;
map = *map_r = sql_dict_find_map(dict, key, &values);
if (map == NULL) {
@@ -326,8 +337,11 @@
}
str_printfa(query, "SELECT %s FROM %s",
map->value_field, map->table);
- sql_dict_where_build(dict, map, &values, key[0],
- SQL_DICT_RECURSE_NONE, query);
+ if (sql_dict_where_build(dict, map, &values, key[0],
+ SQL_DICT_RECURSE_NONE, query, &error) < 0) {
+ i_error("sql dict lookup: Failed to lookup key %s: %s", key, error);
+ return -1;
+ }
return 0;
}
@@ -483,9 +497,9 @@
return NULL;
}
-static bool
+static int
sql_dict_iterate_build_next_query(struct sql_dict_iterate_context *ctx,
- string_t *query)
+ string_t *query, const char **error_r)
{
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict;
const struct dict_sql_map *map;
@@ -495,8 +509,10 @@
unsigned int i, count;
map = sql_dict_iterate_find_next_map(ctx, &values);
- if (map == NULL)
- return FALSE;
+ if (map == NULL) {
+ *error_r = "Invalid/unmapped path";
+ return 0;
+ }
if (ctx->result != NULL) {
sql_result_unref(ctx->result);
@@ -529,9 +545,10 @@
recurse_type = SQL_DICT_RECURSE_NONE;
else
recurse_type = SQL_DICT_RECURSE_ONE;
- sql_dict_where_build(dict, map, &values,
- ctx->paths[ctx->path_idx][0],
- recurse_type, query);
+ if (sql_dict_where_build(dict, map, &values,
+ ctx->paths[ctx->path_idx][0],
+ recurse_type, query, error_r) < 0)
+ return -1;
if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_KEY) != 0) {
str_append(query, " ORDER BY ");
@@ -544,7 +561,7 @@
str_printfa(query, " ORDER BY %s", map->value_field);
ctx->map = map;
- return TRUE;
+ return 1;
}
static void sql_dict_iterate_callback(struct sql_result *result,
@@ -556,17 +573,20 @@
ctx->ctx.async_callback(ctx->ctx.async_context);
}
-static bool sql_dict_iterate_next_query(struct sql_dict_iterate_context *ctx)
+static int sql_dict_iterate_next_query(struct sql_dict_iterate_context *ctx,
+ const char **error_r)
{
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict;
- bool ret;
+ char *error = NULL;
+ int ret;
T_BEGIN {
string_t *query = t_str_new(256);
- ret = sql_dict_iterate_build_next_query(ctx, query);
- if (!ret) {
+ ret = sql_dict_iterate_build_next_query(ctx, query, error_r);
+ if (ret <= 0) {
/* failed */
+ error = i_strdup(*error_r);
} else if ((ctx->flags & DICT_ITERATE_FLAG_ASYNC) == 0) {
ctx->result = sql_query_s(dict->db, str_c(query));
} else {
@@ -575,6 +595,8 @@
sql_dict_iterate_callback, ctx);
}
} T_END;
+ *error_r = t_strdup(error);
+ i_free(error);
return ret;
}
@@ -584,6 +606,7 @@
{
struct sql_dict_iterate_context *ctx;
unsigned int i, path_count;
+ const char *error;
pool_t pool;
pool = pool_alloconly_create("sql dict iterate", 512);
@@ -598,9 +621,9 @@
ctx->paths[i] = p_strdup(pool, paths[i]);
ctx->key = str_new(pool, 256);
- if (!sql_dict_iterate_next_query(ctx)) {
- i_error("sql dict iterate: Invalid/unmapped path: %s",
- paths[0]);
+ if (sql_dict_iterate_next_query(ctx, &error) <= 0) {
+ i_error("sql dict iterate failed for %s: %s",
+ paths[0], error);
ctx->result = NULL;
ctx->failed = TRUE;
return &ctx->ctx;
@@ -613,7 +636,7 @@
{
struct sql_dict_iterate_context *ctx =
(struct sql_dict_iterate_context *)_ctx;
- const char *p, *value;
+ const char *p, *value, *error;
unsigned int i, sql_field_i, count;
int ret;
@@ -635,8 +658,9 @@
/* see if there are more results in the next map.
don't do it if we're looking for an exact match, since we
already should have handled it. */
- if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0 ||
- !sql_dict_iterate_next_query(ctx))
+ if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0)
+ return FALSE;
+ if ((ret = sql_dict_iterate_next_query(ctx, &error)) == 0)
return FALSE;
}
if (ret < 0) {
@@ -806,7 +830,8 @@
bool inc;
};
-static const char *sql_dict_set_query(const struct dict_sql_build_query *build)
+static int sql_dict_set_query(const struct dict_sql_build_query *build,
+ const char **query_r, const char **error_r)
{
struct sql_dict *dict = build->dict;
const struct dict_sql_build_query_field *fields;
@@ -831,9 +856,10 @@
if (build->inc)
str_append(suffix, fields[i].value);
else {
- sql_dict_value_escape(suffix, dict,
+ if (sql_dict_value_escape(suffix, dict,
fields[i].map->value_hexblob,
- "value", fields[i].value, "");
+ "value", fields[i].value, "", error_r) < 0)
+ return -1;
}
}
if (build->key1 == DICT_PATH_PRIVATE[0]) {
@@ -849,14 +875,17 @@
for (i = 0; i < count; i++) {
str_printfa(prefix, ",%s", sql_fields[i].name);
str_append_c(suffix, ',');
- sql_dict_field_escape_value(suffix, dict, &sql_fields[i],
- extra_values[i], "");
+ if (sql_dict_field_escape_value(suffix, dict, &sql_fields[i],
+ extra_values[i], "", error_r) < 0)
+ return -1;
}
More information about the dovecot-cvs
mailing list