"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/dict/dict-commands.c" between
dovecot-2.3.16.tar.gz and dovecot-2.3.17.tar.gz

About: Dovecot is an IMAP and POP3 server, written with security primarily in mind.

dict-commands.c  (dovecot-2.3.16):dict-commands.c  (dovecot-2.3.17)
/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */ /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h" #include "lib.h"
#include "array.h" #include "array.h"
#include "ostream.h" #include "ostream.h"
#include "str.h" #include "str.h"
#include "strescape.h" #include "strescape.h"
#include "stats-dist.h" #include "stats-dist.h"
#include "time-util.h" #include "time-util.h"
#include "dict-private.h"
#include "dict-client.h" #include "dict-client.h"
#include "dict-settings.h" #include "dict-settings.h"
#include "dict-connection.h" #include "dict-connection.h"
#include "dict-commands.h" #include "dict-commands.h"
#include "main.h" #include "main.h"
#define DICT_CLIENT_PROTOCOL_TIMINGS_MIN_VERSION 1 #define DICT_CLIENT_PROTOCOL_TIMINGS_MIN_VERSION 1
#define DICT_CLIENT_PROTOCOL_UNORDERED_MIN_VERSION 1 #define DICT_CLIENT_PROTOCOL_UNORDERED_MIN_VERSION 1
#define DICT_OUTPUT_OPTIMAL_SIZE 1024 #define DICT_OUTPUT_OPTIMAL_SIZE 1024
struct dict_cmd_func { struct dict_cmd_func {
enum dict_protocol_cmd cmd; enum dict_protocol_cmd cmd;
int (*func)(struct dict_connection_cmd *cmd, const char *line); int (*func)(struct dict_connection_cmd *cmd, const char *const *args);
}; };
struct dict_connection_cmd { struct dict_connection_cmd {
const struct dict_cmd_func *cmd; const struct dict_cmd_func *cmd;
struct dict_connection *conn; struct dict_connection *conn;
struct timeval start_timeval; struct timeval start_timeval;
struct event *event; struct event *event;
char *reply; char *reply;
struct dict_iterate_context *iter; struct dict_iterate_context *iter;
skipping to change at line 222 skipping to change at line 223
str_append_c(str, DICT_PROTOCOL_REPLY_FAIL); str_append_c(str, DICT_PROTOCOL_REPLY_FAIL);
str_append_tabescaped(str, result->error); str_append_tabescaped(str, result->error);
} }
dict_cmd_reply_handle_stats(cmd, str, cmd_stats.lookups); dict_cmd_reply_handle_stats(cmd, str, cmd_stats.lookups);
str_append_c(str, '\n'); str_append_c(str, '\n');
cmd->reply = i_strdup(str_c(str)); cmd->reply = i_strdup(str_c(str));
dict_connection_cmd_try_flush(&cmd); dict_connection_cmd_try_flush(&cmd);
} }
static int cmd_lookup(struct dict_connection_cmd *cmd, const char *line) static int cmd_lookup(struct dict_connection_cmd *cmd, const char *const *args)
{ {
/* <key> */ const char *username;
if (str_array_length(args) < 1) {
e_error(cmd->event, "LOOKUP: broken input");
return -1;
}
username = args[1];
/* <key> [<username>] */
dict_connection_cmd_async(cmd); dict_connection_cmd_async(cmd);
event_add_str(cmd->event, "key", line); event_add_str(cmd->event, "key", args[0]);
dict_lookup_async(cmd->conn->dict, line, cmd_lookup_callback, cmd); event_add_str(cmd->event, "user", username);
const struct dict_op_settings set = {
.username = username,
};
dict_lookup_async(cmd->conn->dict, &set, args[0], cmd_lookup_callback, cm
d);
return 1; return 1;
} }
static bool dict_connection_flush_if_full(struct dict_connection *conn) static bool dict_connection_flush_if_full(struct dict_connection *conn)
{ {
if (o_stream_get_buffer_used_size(conn->conn.output) > if (o_stream_get_buffer_used_size(conn->conn.output) >
DICT_OUTPUT_OPTIMAL_SIZE) { DICT_OUTPUT_OPTIMAL_SIZE) {
if (o_stream_flush(conn->conn.output) <= 0) { if (o_stream_flush(conn->conn.output) <= 0) {
/* continue later when there's more space /* continue later when there's more space
in output buffer */ in output buffer */
skipping to change at line 343 skipping to change at line 356
o_stream_uncork(conn->conn.output); o_stream_uncork(conn->conn.output);
} else { } else {
/* It's possible that the command gets finished via some other /* It's possible that the command gets finished via some other
code path. To make sure this doesn't cause hangs, uncork the code path. To make sure this doesn't cause hangs, uncork the
output when command gets freed. */ output when command gets freed. */
cmd->uncork_pending = TRUE; cmd->uncork_pending = TRUE;
} }
dict_connection_unref_safe(conn); dict_connection_unref_safe(conn);
} }
static int cmd_iterate(struct dict_connection_cmd *cmd, const char *line) static int cmd_iterate(struct dict_connection_cmd *cmd, const char *const *args)
{ {
const char *const *args; const char *username;
unsigned int flags; unsigned int flags;
uint64_t max_rows; uint64_t max_rows;
args = t_strsplit_tabescaped(line);
if (str_array_length(args) < 3 || if (str_array_length(args) < 3 ||
str_to_uint(args[0], &flags) < 0 || str_to_uint(args[0], &flags) < 0 ||
str_to_uint64(args[1], &max_rows) < 0) { str_to_uint64(args[1], &max_rows) < 0) {
e_error(cmd->event, "ITERATE: broken input"); e_error(cmd->event, "ITERATE: broken input");
return -1; return -1;
} }
dict_connection_cmd_async(cmd); dict_connection_cmd_async(cmd);
username = args[3];
/* <flags> <max_rows> <path> */ const struct dict_op_settings set = {
.username = username,
};
/* <flags> <max_rows> <path> [<username>] */
flags |= DICT_ITERATE_FLAG_ASYNC; flags |= DICT_ITERATE_FLAG_ASYNC;
event_add_str(cmd->event, "key", args[2]); event_add_str(cmd->event, "key", args[2]);
cmd->iter = dict_iterate_init_multiple(cmd->conn->dict, args+2, flags); event_add_str(cmd->event, "user", username);
cmd->iter = dict_iterate_init(cmd->conn->dict, &set, args[2], flags);
cmd->iter_flags = flags; cmd->iter_flags = flags;
if (max_rows > 0) if (max_rows > 0)
dict_iterate_set_limit(cmd->iter, max_rows); dict_iterate_set_limit(cmd->iter, max_rows);
dict_iterate_set_async_callback(cmd->iter, cmd_iterate_callback, cmd); dict_iterate_set_async_callback(cmd->iter, cmd_iterate_callback, cmd);
(void)dict_connection_cmd_output_more(cmd); (void)dict_connection_cmd_output_more(cmd);
return 1; return 1;
} }
static struct dict_connection_transaction * static struct dict_connection_transaction *
dict_connection_transaction_lookup(struct dict_connection *conn, dict_connection_transaction_lookup(struct dict_connection *conn,
skipping to change at line 404 skipping to change at line 422
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (transactions[i].id == id) { if (transactions[i].id == id) {
i_assert(transactions[i].ctx == NULL); i_assert(transactions[i].ctx == NULL);
array_delete(&conn->transactions, i, 1); array_delete(&conn->transactions, i, 1);
return; return;
} }
} }
i_unreached(); i_unreached();
} }
static int cmd_begin(struct dict_connection_cmd *cmd, const char *line) static int cmd_begin(struct dict_connection_cmd *cmd, const char *const *args)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
unsigned int id; unsigned int id;
const char *username;
if (str_array_length(args) < 1) {
e_error(cmd->event, "BEGIN: broken input");
return -1;
}
username = args[1];
if (str_to_uint(line, &id) < 0) { /* <id> [<username>] */
e_error(cmd->event, "Invalid transaction ID %s", line); if (str_to_uint(args[0], &id) < 0) {
e_error(cmd->event, "Invalid transaction ID %s", args[0]);
return -1; return -1;
} }
if (dict_connection_transaction_lookup(cmd->conn, id) != NULL) { if (dict_connection_transaction_lookup(cmd->conn, id) != NULL) {
e_error(cmd->event, "Transaction ID %u already exists", id); e_error(cmd->event, "Transaction ID %u already exists", id);
return -1; return -1;
} }
if (!array_is_created(&cmd->conn->transactions)) if (!array_is_created(&cmd->conn->transactions))
i_array_init(&cmd->conn->transactions, 4); i_array_init(&cmd->conn->transactions, 4);
/* <id> */ struct dict_op_settings set = {
.username = username,
};
trans = array_append_space(&cmd->conn->transactions); trans = array_append_space(&cmd->conn->transactions);
trans->id = id; trans->id = id;
trans->conn = cmd->conn; trans->conn = cmd->conn;
trans->ctx = dict_transaction_begin(cmd->conn->dict); trans->ctx = dict_transaction_begin(cmd->conn->dict, &set);
return 0; return 0;
} }
static int static int
dict_connection_transaction_lookup_parse(struct dict_connection *conn, dict_connection_transaction_lookup_parse(struct dict_connection *conn,
const char *line, const char *id_str,
struct dict_connection_transaction **tra ns_r) struct dict_connection_transaction **tra ns_r)
{ {
unsigned int id; unsigned int id;
if (str_to_uint(line, &id) < 0) { if (str_to_uint(id_str, &id) < 0) {
e_error(conn->conn.event, "Invalid transaction ID %s", line); e_error(conn->conn.event, "Invalid transaction ID %s", id_str);
return -1; return -1;
} }
*trans_r = dict_connection_transaction_lookup(conn, id); *trans_r = dict_connection_transaction_lookup(conn, id);
if (*trans_r == NULL) { if (*trans_r == NULL) {
e_error(conn->conn.event, "Transaction ID %u doesn't exist", id); e_error(conn->conn.event, "Transaction ID %u doesn't exist", id);
return -1; return -1;
} }
return 0; return 0;
} }
skipping to change at line 510 skipping to change at line 538
cmd_commit_finish(cmd, result, FALSE); cmd_commit_finish(cmd, result, FALSE);
} }
static void cmd_commit_callback_async(const struct dict_commit_result *result, static void cmd_commit_callback_async(const struct dict_commit_result *result,
struct dict_connection_cmd *cmd) struct dict_connection_cmd *cmd)
{ {
cmd_commit_finish(cmd, result, TRUE); cmd_commit_finish(cmd, result, TRUE);
} }
static int static int
cmd_commit(struct dict_connection_cmd *cmd, const char *line) cmd_commit(struct dict_connection_cmd *cmd, const char *const *args)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0 ) if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
return -1; return -1;
cmd->trans_id = trans->id; cmd->trans_id = trans->id;
event_add_str(cmd->event, "user", trans->ctx->set.username);
dict_connection_cmd_async(cmd); dict_connection_cmd_async(cmd);
dict_transaction_commit_async(&trans->ctx, cmd_commit_callback, cmd); dict_transaction_commit_async(&trans->ctx, cmd_commit_callback, cmd);
return 1; return 1;
} }
static int static int
cmd_commit_async(struct dict_connection_cmd *cmd, const char *line) cmd_commit_async(struct dict_connection_cmd *cmd, const char *const *args)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0 ) if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
return -1; return -1;
cmd->trans_id = trans->id; cmd->trans_id = trans->id;
event_add_str(cmd->event, "user", trans->ctx->set.username);
dict_connection_cmd_async(cmd); dict_connection_cmd_async(cmd);
dict_transaction_commit_async(&trans->ctx, cmd_commit_callback_async, cmd ); dict_transaction_commit_async(&trans->ctx, cmd_commit_callback_async, cmd );
return 1; return 1;
} }
static int cmd_rollback(struct dict_connection_cmd *cmd, const char *line) static int
cmd_rollback(struct dict_connection_cmd *cmd, const char *const *args)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0 ) if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
return -1; return -1;
event_add_str(cmd->event, "user", trans->ctx->set.username);
dict_transaction_rollback(&trans->ctx); dict_transaction_rollback(&trans->ctx);
dict_connection_transaction_array_remove(cmd->conn, trans->id); dict_connection_transaction_array_remove(cmd->conn, trans->id);
return 0; return 0;
} }
static int cmd_set(struct dict_connection_cmd *cmd, const char *line) static int cmd_set(struct dict_connection_cmd *cmd, const char *const *args)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
const char *const *args;
/* <id> <key> <value> */ /* <id> <key> <value> */
args = t_strsplit_tabescaped(line);
if (str_array_length(args) != 3) { if (str_array_length(args) != 3) {
e_error(cmd->event, "SET: broken input"); e_error(cmd->event, "SET: broken input");
return -1; return -1;
} }
if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0) if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
return -1; return -1;
event_add_str(cmd->event, "user", trans->ctx->set.username);
dict_set(trans->ctx, args[1], args[2]); dict_set(trans->ctx, args[1], args[2]);
return 0; return 0;
} }
static int cmd_unset(struct dict_connection_cmd *cmd, const char *line) static int cmd_unset(struct dict_connection_cmd *cmd, const char *const *args)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
const char *const *args;
/* <id> <key> */ /* <id> <key> */
args = t_strsplit_tabescaped(line);
if (str_array_length(args) != 2) { if (str_array_length(args) != 2) {
e_error(cmd->event, "UNSET: broken input"); e_error(cmd->event, "UNSET: broken input");
return -1; return -1;
} }
if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0) if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
return -1; return -1;
dict_unset(trans->ctx, args[1]); dict_unset(trans->ctx, args[1]);
return 0; return 0;
} }
static int cmd_atomic_inc(struct dict_connection_cmd *cmd, const char *line) static int
cmd_atomic_inc(struct dict_connection_cmd *cmd, const char *const *args)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
const char *const *args;
long long diff; long long diff;
/* <id> <key> <diff> */ /* <id> <key> <diff> */
args = t_strsplit_tabescaped(line);
if (str_array_length(args) != 3 || if (str_array_length(args) != 3 ||
str_to_llong(args[2], &diff) < 0) { str_to_llong(args[2], &diff) < 0) {
e_error(cmd->event, "ATOMIC_INC: broken input"); e_error(cmd->event, "ATOMIC_INC: broken input");
return -1; return -1;
} }
if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0) if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
return -1; return -1;
dict_atomic_inc(trans->ctx, args[1], diff); dict_atomic_inc(trans->ctx, args[1], diff);
return 0; return 0;
} }
static int cmd_timestamp(struct dict_connection_cmd *cmd, const char *line) static int cmd_timestamp(struct dict_connection_cmd *cmd, const char *const *arg s)
{ {
struct dict_connection_transaction *trans; struct dict_connection_transaction *trans;
const char *const *args;
long long tv_sec; long long tv_sec;
unsigned int tv_nsec; unsigned int tv_nsec;
/* <id> <secs> <nsecs> */ /* <id> <secs> <nsecs> */
args = t_strsplit_tabescaped(line);
if (str_array_length(args) != 3 || if (str_array_length(args) != 3 ||
str_to_llong(args[1], &tv_sec) < 0 || str_to_llong(args[1], &tv_sec) < 0 ||
str_to_uint(args[2], &tv_nsec) < 0) { str_to_uint(args[2], &tv_nsec) < 0) {
e_error(cmd->event, "TIMESTAMP: broken input"); e_error(cmd->event, "TIMESTAMP: broken input");
return -1; return -1;
} }
if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0) if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
return -1; return -1;
skipping to change at line 664 skipping to change at line 690
return &cmds[i]; return &cmds[i];
} }
return NULL; return NULL;
} }
int dict_command_input(struct dict_connection *conn, const char *line) int dict_command_input(struct dict_connection *conn, const char *line)
{ {
const struct dict_cmd_func *cmd_func; const struct dict_cmd_func *cmd_func;
struct dict_connection_cmd *cmd; struct dict_connection_cmd *cmd;
int ret; int ret;
const char *const *args;
cmd_func = dict_command_find((enum dict_protocol_cmd)*line); cmd_func = dict_command_find((enum dict_protocol_cmd)*line);
if (cmd_func == NULL) { if (cmd_func == NULL) {
e_error(conn->conn.event, "Unknown command %c", *line); e_error(conn->conn.event, "Unknown command %c", *line);
return -1; return -1;
} }
cmd = i_new(struct dict_connection_cmd, 1); cmd = i_new(struct dict_connection_cmd, 1);
cmd->conn = conn; cmd->conn = conn;
cmd->event = event_create(cmd->conn->conn.event); cmd->event = event_create(cmd->conn->conn.event);
cmd->cmd = cmd_func; cmd->cmd = cmd_func;
cmd->start_timeval = ioloop_timeval; cmd->start_timeval = ioloop_timeval;
array_push_back(&conn->cmds, &cmd); array_push_back(&conn->cmds, &cmd);
dict_connection_ref(conn); dict_connection_ref(conn);
if ((ret = cmd_func->func(cmd, line + 1)) <= 0) {
args = t_strsplit_tabescaped(line + 1);
if ((ret = cmd_func->func(cmd, args)) <= 0) {
dict_connection_cmd_remove(cmd); dict_connection_cmd_remove(cmd);
return ret; return ret;
} }
return 0; return 0;
} }
static bool dict_connection_cmds_try_output_more(struct dict_connection *conn) static bool dict_connection_cmds_try_output_more(struct dict_connection *conn)
{ {
struct dict_connection_cmd *cmd; struct dict_connection_cmd *cmd;
 End of changes. 42 change blocks. 
37 lines changed or deleted 67 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)