X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ffrontend%2Fconnection.c;h=91196dcd4448125864073bff616ce24f9d406809;hb=192c24079685a32bcfff24e332c460ced0e51565;hp=096a7590444c3ef467372f606ee70dda9cdbbe72;hpb=3a48bac5a41bff96412b1ac8f15bdc97cb9e28be;p=sysdb.git diff --git a/src/frontend/connection.c b/src/frontend/connection.c index 096a759..91196dc 100644 --- a/src/frontend/connection.c +++ b/src/frontend/connection.c @@ -26,9 +26,10 @@ */ #include "sysdb.h" -#include "core/error.h" #include "core/object.h" +#include "core/plugin.h" #include "frontend/connection-private.h" +#include "utils/error.h" #include "utils/strbuf.h" #include "utils/proto.h" @@ -38,10 +39,20 @@ #include #include +#include #include +#include + +/* + * private variables + */ + +static pthread_key_t conn_ctx_key; +static _Bool conn_ctx_key_initialized = 0; + /* - * private data types + * private types */ /* name of connection objects */ @@ -145,10 +156,78 @@ static sdb_type_t connection_type = { /* destroy = */ connection_destroy, }; +/* + * private helper functions + */ + +static void +sdb_conn_ctx_destructor(void *c) +{ + sdb_object_t *conn = c; + + if (! conn) + return; + sdb_object_deref(conn); +} /* sdb_conn_ctx_destructor */ + +static void +sdb_conn_ctx_init(void) +{ + if (conn_ctx_key_initialized) + return; + + pthread_key_create(&conn_ctx_key, sdb_conn_ctx_destructor); + conn_ctx_key_initialized = 1; +} /* sdb_conn_ctx_init */ + +static void +sdb_conn_set_ctx(sdb_conn_t *conn) +{ + sdb_conn_ctx_init(); + if (conn) + sdb_object_ref(SDB_OBJ(conn)); + pthread_setspecific(conn_ctx_key, conn); +} /* sdb_conn_set_ctx */ + +static sdb_conn_t * +sdb_conn_get_ctx(void) +{ + if (! conn_ctx_key_initialized) + return NULL; + return pthread_getspecific(conn_ctx_key); +} /* sdb_conn_get_ctx */ + /* * connection handler functions */ +/* + * connection_log: + * Send a log message originating from the current thread to the client. + */ +static int +connection_log(int prio, const char *msg, + sdb_object_t __attribute__((unused)) *user_data) +{ + sdb_conn_t *conn; + + conn = sdb_conn_get_ctx(); + /* no connection associated to this thread + * or user not authenticated yet => don't leak any information */ + if ((! conn) || (! conn->username)) + return 0; + + /* XXX: make the log-level configurable by the client at runtime */ + if (prio >= SDB_LOG_DEBUG) + return 0; + + /* TODO: Use CONNECTION_LOG_? */ + if (sdb_connection_send(conn, CONNECTION_LOG, + (uint32_t)strlen(msg), msg) < 0) + return -1; + return 0; +} /* connection_log */ + static uint32_t connection_get_int32(sdb_conn_t *conn, size_t offset) { @@ -173,6 +252,13 @@ command_handle(sdb_conn_t *conn) sdb_log(SDB_LOG_DEBUG, "frontend: Handling command %u (len: %u)", conn->cmd, conn->cmd_len); + if ((! conn->username) && (conn->cmd != CONNECTION_STARTUP)) { + const char *errmsg = "Authentication required"; + sdb_connection_send(conn, CONNECTION_ERROR, + (uint32_t)strlen(errmsg), errmsg); + return -1; + } + /* reset */ sdb_strbuf_sprintf(conn->errbuf, ""); @@ -184,13 +270,57 @@ command_handle(sdb_conn_t *conn) status = sdb_fe_session_start(conn); break; + case CONNECTION_QUERY: + { + sdb_llist_t *parsetree; + sdb_conn_node_t *node = NULL; + + parsetree = sdb_fe_parse(sdb_strbuf_string(conn->buf), + (int)conn->cmd_len); + if (! parsetree) { + sdb_log(SDB_LOG_ERR, "frontend: Failed to parse query '%s'", + sdb_strbuf_string(conn->buf)); + status = -1; + break; + } + + switch (sdb_llist_len(parsetree)) { + case 0: + /* skipping empty command */ + break; + case 1: + node = SDB_CONN_NODE(sdb_llist_get(parsetree, 0)); + break; + + default: + sdb_log(SDB_LOG_WARNING, "frontend: Ignoring %d command%s " + "in multi-statement query '%s'", + sdb_llist_len(parsetree) - 1, + sdb_llist_len(parsetree) == 2 ? "" : "s", + sdb_strbuf_string(conn->buf)); + node = SDB_CONN_NODE(sdb_llist_get(parsetree, 0)); + } + + if (node) { + status = sdb_fe_exec(conn, node); + sdb_object_deref(SDB_OBJ(node)); + } + + sdb_llist_destroy(parsetree); + break; + } + + case CONNECTION_FETCH: + status = sdb_fe_fetch(conn, sdb_strbuf_string(conn->buf)); + break; case CONNECTION_LIST: status = sdb_fe_list(conn); break; default: { - sdb_log(SDB_LOG_WARNING, "frontend: Ignoring invalid command"); + sdb_log(SDB_LOG_WARNING, "frontend: Ignoring invalid command %#x", + conn->cmd); sdb_strbuf_sprintf(conn->errbuf, "Invalid command %#x", conn->cmd); status = -1; break; @@ -257,6 +387,13 @@ connection_read(sdb_conn_t *conn) * public API */ +int +sdb_connection_enable_logging(void) +{ + return sdb_plugin_register_log("connection-logger", connection_log, + /* user_data = */ NULL); +} /* sdb_connection_enable_logging */ + sdb_conn_t * sdb_connection_accept(int fd) { @@ -280,6 +417,8 @@ sdb_connection_read(sdb_conn_t *conn) { ssize_t n = 0; + sdb_conn_set_ctx(conn); + while (42) { ssize_t status = connection_read(conn); @@ -295,6 +434,8 @@ sdb_connection_read(sdb_conn_t *conn) n += status; } + + sdb_conn_set_ctx(NULL); return n; } /* sdb_connection_read */