diff options
author | sss <sss@dark-alexandr.net> | 2023-01-17 00:38:19 +0300 |
---|---|---|
committer | sss <sss@dark-alexandr.net> | 2023-01-17 00:38:19 +0300 |
commit | cc3f33db7a8d3c4ad373e646b199808e01bc5d9b (patch) | |
tree | ec09d690c7656ab5f2cc72607e05fb359c24d8b2 /src/core/backend_helpers.c |
added webrdp public code
Diffstat (limited to 'src/core/backend_helpers.c')
-rw-r--r-- | src/core/backend_helpers.c | 459 |
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; +} |