summaryrefslogtreecommitdiff
path: root/src/core/backend_helpers.c
diff options
context:
space:
mode:
authorsss <sss@dark-alexandr.net>2023-01-17 00:38:19 +0300
committersss <sss@dark-alexandr.net>2023-01-17 00:38:19 +0300
commitcc3f33db7a8d3c4ad373e646b199808e01bc5d9b (patch)
treeec09d690c7656ab5f2cc72607e05fb359c24d8b2 /src/core/backend_helpers.c
added webrdp public code
Diffstat (limited to 'src/core/backend_helpers.c')
-rw-r--r--src/core/backend_helpers.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/src/core/backend_helpers.c b/src/core/backend_helpers.c
new file mode 100644
index 0000000..ab40fac
--- /dev/null
+++ b/src/core/backend_helpers.c
@@ -0,0 +1,459 @@
+/* BSD-2-Clause license
+ *
+ * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>.
+ *
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "globals.h"
+#include "ws_session.h"
+#include "wrdp_thpool_internals.h"
+#include "webrdp_module_api.h"
+#include "task.h"
+#include "rdp_backend_api.h"
+#include "thread_sync.h"
+#include "utilities.h"
+#include "thread_impl.h"
+#include "curl_helpers.h"
+
+#include <errno.h>
+#include "base64_url.h"
+
+bool
+backend_validate(wrdp_backend_module *backend)
+{
+ if (!backend->callbacks_module->init)
+ {
+ return false;
+ }
+ if (!backend->callbacks_input->kcomb
+ && !backend->callbacks_input->kpress
+ && !backend->callbacks_input->kupdown
+ && !backend->callbacks_input->mouse
+ && !backend->callbacks_input->unicode)
+ {
+ /* backend can't handle any input */
+ return false;
+ }
+ return true;
+}
+
+static bool
+validate_backend_name(const char *name)
+{
+ if (!strcmp(name, "rdp"))
+ {
+ return true;
+ }
+ return false;
+}
+
+void
+backend_remove_from_pool(wrdp_backend_module *backend)
+{
+ wrdp_thpool_task *task = backend->wrdp_thpool_task;
+
+ user_pool_msg *pmsg = calloc(1, sizeof(user_pool_msg));
+ if (!pmsg)
+ {
+ perror("calloc");
+ return;
+ }
+ pmsg->type = msg_type_destroy_ws_backend_info;
+ pmsg->backend = backend;
+
+ wrdp_thpool_send_msg_to_pool(task->thread->pool, pmsg);
+}
+
+static bool
+backend_create(const char *name, ws_session *session)
+{
+ wrdp_backend_module *backend = 0;
+ task_info *info = session->task_info;
+ wrdp_thpool_task *task = 0;
+
+ if (session->sid_base64)
+ {
+ size_t sid_len = strlen(session->sid_base64);
+ char *attach_sid = malloc(sid_len + 1);
+ memcpy(attach_sid, session->sid_base64, sid_len);
+ attach_sid[sid_len] = 0;
+ session->attach_sid_base64 = attach_sid;
+ }
+
+ if (!validate_backend_name(name))
+ {
+ return false;
+ }
+ backend = calloc(1, sizeof(wrdp_backend_module));
+ if (!backend)
+ {
+ perror("calloc");
+ return false;
+ }
+ bool module_initialized = false;
+ info->backend = backend;
+ backend->task_info = info;
+ session->task_info = info;
+ info->wrdp_thpool_task = session->wrdp_thpool_task;
+ backend->wrdp_thpool_task = session->wrdp_thpool_task;
+ task = session->wrdp_thpool_task;
+ task->userdata = info;
+ {
+ struct ws_session_list_entry_s *entry
+ = calloc(1, sizeof(struct ws_session_list_entry_s));
+ if (!entry)
+ {
+ perror("calloc");
+ goto error;
+ }
+ entry->session = session;
+ backend->sessions_list_head
+ = calloc(1, sizeof(SLIST_HEAD(h, ws_session_list_entry_s)));
+ SLIST_HEAD(sessions_head,
+ ws_session_list_entry_s) *sessions_list_head_p
+ = backend->sessions_list_head;
+ SLIST_INIT(sessions_list_head_p);
+ SLIST_INSERT_HEAD(sessions_list_head_p, entry, entries);
+ info->settings = g_globals.settings.ws_session_defaults;
+ }
+ SLIST_INIT(&(session->curls_easy_head));
+
+ backend->callbacks_input = calloc(1, sizeof(wrdp_backend_cb_input));
+ if (!backend->callbacks_input)
+ {
+ perror("calloc");
+ goto error;
+ }
+ backend->callbacks_module = calloc(1, sizeof(wrdp_backend_cb_module));
+ if (!backend->callbacks_module)
+ {
+ perror("calloc");
+ goto error;
+ }
+ backend->callbacks_clipbrd
+ = calloc(1, sizeof(wrdp_backend_cb_clipboard));
+ if (!backend->callbacks_clipbrd)
+ {
+ perror("calloc");
+ goto error;
+ }
+ backend->callbacks_ft = calloc(1, sizeof(wrdp_backend_cb_filetransfer));
+ if (!backend->callbacks_ft)
+ {
+ perror("calloc");
+ goto error;
+ }
+ if (!strcmp(name, "rdp"))
+ {
+ module_initialized = rdp_create(g_globals.exports, backend);
+ if (!module_initialized)
+ {
+ goto error;
+ }
+ }
+ strcpy(info->backend_name, name);
+ info->backend = backend;
+ if (!backend_validate(info->backend))
+ {
+ info->backend = 0;
+ goto error;
+ }
+ info->backend->callbacks_module->set_task_info(
+ info, info->backend->backend_internals);
+ {
+ /* TODO: do it in main thread */
+ user_pool_msg *pmsg = calloc(1, sizeof(user_pool_msg));
+ wrdp_thpool_task *task = session->wrdp_thpool_task;
+ if (!pmsg)
+ {
+ perror("calloc");
+ goto error;
+ }
+ pmsg->type = msg_type_backend_created;
+ pmsg->backend = backend;
+ wrdp_thpool_send_msg_to_pool(task->thread->pool, pmsg);
+ }
+ {
+ wrdp_thpool_task *task = session->wrdp_thpool_task;
+ info->ev_timer_watcher = calloc(1, sizeof(ev_timer));
+ if (!info->ev_timer_watcher)
+ {
+ perror("calloc");
+ goto error;
+ }
+ ev_timer_init(
+ info->ev_timer_watcher, task_timeouts_check_cb, 1., 0.);
+ info->ev_timer_watcher->data = info;
+ info->ev_timer_watcher->repeat = 1;
+ ev_timer_again(
+ task->thread->ev_th_loop, info->ev_timer_watcher);
+ }
+ return true;
+error:
+ if (backend)
+ {
+ if (backend->callbacks_input)
+ {
+ free(backend->callbacks_input);
+ }
+ if (backend->callbacks_module)
+ {
+ free(backend->callbacks_module);
+ }
+ if (backend->callbacks_clipbrd)
+ {
+ free(backend->callbacks_clipbrd);
+ }
+ if (backend->callbacks_ft)
+ {
+ free(backend->callbacks_ft);
+ }
+ backend_remove_from_pool(backend);
+ }
+ return false;
+}
+
+void
+backend_destroy(wrdp_backend_module *backend)
+{
+ if (backend->callbacks_input)
+ {
+ free(backend->callbacks_input);
+ }
+ if (backend->callbacks_module)
+ {
+ free(backend->callbacks_module);
+ }
+ if (backend->callbacks_ft)
+ {
+ free(backend->callbacks_ft);
+ }
+ if (backend->callbacks_clipbrd)
+ {
+ free(backend->callbacks_clipbrd);
+ }
+ if (backend->sessions_list_head)
+ {
+ free(backend->sessions_list_head);
+ }
+ backend_remove_from_pool(backend);
+}
+
+extern void task_destroy_timers(wrdp_thpool_task *task);
+
+void
+backend_task_destroy(wrdp_thpool_task *task)
+{
+ task_destroy_timers(task);
+
+ task_info *info = task->userdata;
+ backend_destroy(info->backend);
+
+ free(info);
+}
+
+static void
+ws_session_child_init_cb(wrdp_thpool_task *task, void *userdata)
+{
+ ws_session *session = userdata;
+ session->wrdp_thpool_task = task;
+}
+
+static bool
+backend_find(ws_session *session)
+{
+ for (struct backend_s *t1 = LIST_FIRST(&(g_globals.backends_head)); t1;
+ t1 = LIST_NEXT(t1, entries))
+ {
+ //TODO: WTF?
+ if (!t1->backend)
+ continue;
+
+ SLIST_HEAD(sessions_head,
+ ws_session_list_entry_s) *sessions_list_head_p
+ = t1->backend->sessions_list_head;
+ for (struct ws_session_list_entry_s *s
+ = SLIST_FIRST(sessions_list_head_p);
+ s; s = SLIST_NEXT(s, entries))
+ {
+ if (s->session && session->attach_sid_base64
+ && s->session->sid_base64
+ && !strcmp(session->attach_sid_base64,
+ s->session->sid_base64))
+ {
+ if (session == s->session)
+ {
+ return true;
+ }
+ struct ws_session_list_entry_s *entry = calloc(
+ 1, sizeof(struct ws_session_list_entry_s));
+ wrdp_thpool_task *t;
+ if (!entry)
+ {
+ session->session_state
+ = ws_session_error;
+ perror("calloc");
+ return false;
+ }
+ entry->session = session;
+ session->task_info = t1->backend->task_info;
+ SLIST_INSERT_HEAD(
+ sessions_list_head_p, entry, entries);
+ t = t1->backend->wrdp_thpool_task;
+ if (!wrdp_thread_pool_move_task_to_thread(
+ g_globals.thpool, ws_run_session,
+ ws_stop_session, t->thread->thread_id,
+ ws_session_child_init_cb,
+ session->wrdp_thpool_task, session))
+ {
+ /* TODO: cleanup ? */
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+backend_get(const char *name, ws_session *session)
+{
+ bool found = false;
+ if (session->attach_sid_base64)
+ {
+ found = backend_find(session);
+ }
+ else
+ {
+ found = backend_create(name, session);
+ }
+ return found;
+}
+
+void
+backend_fill_settings(ws_session *session)
+{
+ while (!SLIST_EMPTY(&(session->backend_settings_head)))
+ {
+ task_info *info = session->task_info;
+ struct backend_setting_s *s
+ = SLIST_FIRST(&(session->backend_settings_head));
+ SLIST_REMOVE_HEAD(&(session->backend_settings_head), entries);
+ if (s->type == setting_int)
+ {
+ info->backend->callbacks_module->set_setting_int(
+ &(s->setting_int),
+ info->backend->backend_internals);
+ free(s->setting_int.name);
+ free(s);
+ }
+ else if (s->type == setting_string)
+ {
+ info->backend->callbacks_module->set_setting_str(
+ &(s->setting_string),
+ info->backend->backend_internals);
+ free(s->setting_string.name);
+ free(s->setting_string.value);
+ free(s);
+ }
+ }
+}
+
+bool
+handle_backend_setting_int(const char *name, int64_t val, ws_session *session)
+{
+ task_info *info = session->task_info;
+ if (!info || !info->backend)
+ {
+ if (!SLIST_EMPTY(&(session->backend_settings_head)))
+ {
+ for (struct backend_setting_s *s
+ = SLIST_FIRST(&(session->backend_settings_head));
+ s; s = SLIST_NEXT(s, entries))
+ {
+ if (s->type != setting_int)
+ continue;
+ if (strcmp(s->setting_int.name, name))
+ continue;
+ s->setting_int.value = val;
+ return true;
+ }
+ }
+ struct backend_setting_s *s
+ = calloc(1, sizeof(struct backend_setting_s));
+ if (!s)
+ {
+ perror("calloc");
+ return false;
+ }
+ s->setting_int.name = strdup(name);
+ s->setting_int.value = val;
+ s->type = setting_int;
+ SLIST_INSERT_HEAD(
+ &(session->backend_settings_head), s, entries);
+ }
+ else
+ {
+ backend_setting_int s;
+ s.name = (char *)name;
+ s.value = val;
+ if (!info->backend->callbacks_module->set_setting_int(
+ &s, info->backend->backend_internals))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+handle_backend_setting_string(
+ const char *name, const char *val, ws_session *session)
+{
+ task_info *info = session->task_info;
+ if (!info || !info->backend)
+ {
+ if (!SLIST_EMPTY(&(session->backend_settings_head)))
+ {
+ for (struct backend_setting_s *s
+ = SLIST_FIRST(&(session->backend_settings_head));
+ s; s = SLIST_NEXT(s, entries))
+ {
+ if (s->type != setting_string)
+ continue;
+ if (strcmp(s->setting_string.name, name))
+ continue;
+ free(s->setting_string.value);
+ s->setting_string.value = strdup(val);
+ return true;
+ }
+ }
+ struct backend_setting_s *s
+ = calloc(1, sizeof(struct backend_setting_s));
+ if (!s)
+ {
+ perror("calloc");
+ return false;
+ }
+ s->setting_string.name = strdup(name);
+ s->setting_string.value = strdup(val);
+ s->type = setting_string;
+ SLIST_INSERT_HEAD(
+ &(session->backend_settings_head), s, entries);
+ }
+ else
+ {
+ backend_setting_str s;
+ s.name = (char *)name;
+ s.value = (char *)val;
+ info->backend->callbacks_module->set_setting_str(
+ &s, info->backend->backend_internals);
+ }
+ return true;
+}