diff --git a/client/tp_assist_win/ts_http_rpc.cpp b/client/tp_assist_win/ts_http_rpc.cpp index d1a3a0f..6238c89 100644 --- a/client/tp_assist_win/ts_http_rpc.cpp +++ b/client/tp_assist_win/ts_http_rpc.cpp @@ -1,1160 +1,1185 @@ -#include "stdafx.h" - -#pragma warning(disable:4091) - -#include -#include -#include - -#pragma comment(lib, "Crypt32.lib") - -#include - -#include "ts_http_rpc.h" -#include "dlg_main.h" -#include "ts_ver.h" - -/* -1. -SecureCRT支持设置标签页的标题,命令行参数 /N "tab name"就可以 -Example: -To launch a new Telnet session, displaying the name "Houston, TX" on the tab, use the following: -/T /N "Houston, TX" /TELNET 192.168.0.6 - -2. -多次启动的SecureCRT放到一个窗口的不同标签页中,使用参数: /T - SecureCRT.exe /T /N "TP#ssh://192.168.1.3" /SSH2 /L root /PASSWORD 1234 120.26.109.25 - -3. -telnet客户端的启动: - putty.exe telnet://administrator@127.0.0.1:52389 -如果是SecureCRT,则需要 - SecureCRT.exe /T /N "TP#telnet://192.168.1.3" /SCRIPT X:\path\to\startup.vbs /TELNET 127.0.0.1 52389 -其中,startup.vbs的内容为: ----------文件开始--------- -#$language = "VBScript" -#$interface = "1.0" -Sub main - crt.Screen.Synchronous = True - crt.Screen.WaitForString "ogin: " - crt.Screen.Send "SESSION-ID" & VbCr - crt.Screen.Synchronous = False -End Sub ----------文件结束--------- - -4. 为了让putty的窗口标签显示正常的IP,可以尝试在连接成功后,主动向服务端发送下列命令: - PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@192.168.1.2: \w\a\]$PS1" -手工测试了,ubuntu服务器可以,不知道是否能够支持所有的Linux。SecureCRT对此表示忽略。 -*/ - -//#define RDP_CLIENT_SYSTEM_BUILTIN -// #define RDP_CLIENT_SYSTEM_ACTIVE_CONTROL -//#define RDP_CLIENT_FREERDP - - -//#ifdef RDP_CLIENT_SYSTEM_BUILTIN - -//connect to console:i:%d -//compression:i:1 -//bitmapcachepersistenable:i:1 - -std::string rdp_content = "\ -administrative session:i:%d\n\ -screen mode id:i:%d\n\ -use multimon:i:0\n\ -desktopwidth:i:%d\n\ -desktopheight:i:%d\n\ -session bpp:i:16\n\ -winposstr:s:0,1,%d,%d,%d,%d\n\ -compression:i:1\n\ -bitmapcachepersistenable:i:1\n\ -keyboardhook:i:2\n\ -audiocapturemode:i:0\n\ -videoplaybackmode:i:1\n\ -connection type:i:7\n\ -networkautodetect:i:1\n\ -bandwidthautodetect:i:1\n\ -displayconnectionbar:i:1\n\ -enableworkspacereconnect:i:0\n\ -disable wallpaper:i:1\n\ -allow font smoothing:i:0\n\ -allow desktop composition:i:0\n\ -disable full window drag:i:1\n\ -disable menu anims:i:1\n\ -disable themes:i:1\n\ -disable cursor setting:i:1\n\ -full address:s:%s:%d\n\ -audiomode:i:0\n\ -redirectprinters:i:0\n\ -redirectcomports:i:0\n\ -redirectsmartcards:i:0\n\ -redirectclipboard:i:1\n\ -redirectposdevices:i:0\n\ -autoreconnection enabled:i:0\n\ -authentication level:i:2\n\ -prompt for credentials:i:0\n\ -negotiate security layer:i:1\n\ -remoteapplicationmode:i:0\n\ -alternate shell:s:\n\ -shell working directory:s:\n\ -gatewayhostname:s:\n\ -gatewayusagemethod:i:4\n\ -gatewaycredentialssource:i:4\n\ -gatewayprofileusagemethod:i:0\n\ -promptcredentialonce:i:0\n\ -gatewaybrokeringtype:i:0\n\ -use redirection server name:i:0\n\ -rdgiskdcproxy:i:0\n\ -kdcproxyname:s:\n\ -drivestoredirect:s:*\n\ -username:s:%s\n\ -password 51:b:%s\n\ -"; - -//redirectdirectx:i:0\n\ -//prompt for credentials on client:i:0\n\ - -//#endif - - -TsHttpRpc g_http_interface; - -void http_rpc_main_loop(void) -{ - if (!g_http_interface.init(TS_HTTP_RPC_HOST, TS_HTTP_RPC_PORT)) - { - EXLOGE("[ERROR] can not start HTTP-RPC listener, maybe port %d is already in use.\n", TS_HTTP_RPC_PORT); - return; - } - - EXLOGW("======================================================\n"); - EXLOGW("[rpc] TeleportAssist-HTTP-RPC ready on %s:%d\n", TS_HTTP_RPC_HOST, TS_HTTP_RPC_PORT); - - g_http_interface.run(); - - EXLOGW("[rpc] main loop end.\n"); -} - -void http_rpc_stop(void) -{ - g_http_interface.stop(); -} - -#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') - -int ts_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded) -{ - int i, j, a, b; - - for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) - { - if (src[i] == '%') - { - if (i < src_len - 2 && isxdigit(*(const unsigned char *)(src + i + 1)) && - isxdigit(*(const unsigned char *)(src + i + 2))) { - a = tolower(*(const unsigned char *)(src + i + 1)); - b = tolower(*(const unsigned char *)(src + i + 2)); - dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b)); - i += 2; - } - else - { - return -1; - } - } - else if (is_form_url_encoded && src[i] == '+') - { - dst[j] = ' '; - } - else - { - dst[j] = src[i]; - } - } - - dst[j] = '\0'; /* Null-terminate the destination */ - - return i >= src_len ? j : -1; -} - -bool calc_psw51b(const char* password, std::string& ret) -{ - DATA_BLOB DataIn; - DATA_BLOB DataOut; - - ex_wstr w_pswd; - ex_astr2wstr(password, w_pswd, EX_CODEPAGE_ACP); - - DataIn.cbData = w_pswd.length() * sizeof(wchar_t); - DataIn.pbData = (BYTE*)w_pswd.c_str(); - - - if (!CryptProtectData(&DataIn, L"psw", NULL, NULL, NULL, 0, &DataOut)) - return false; - - char szRet[5] = {0}; - for (int i = 0; i < DataOut.cbData; ++i) - { - sprintf_s(szRet, 5, "%02X", DataOut.pbData[i]); - ret += szRet; - } - - LocalFree(DataOut.pbData); - return true; -} - -TsHttpRpc::TsHttpRpc() -{ - m_stop = false; - mg_mgr_init(&m_mg_mgr, NULL); -} - -TsHttpRpc::~TsHttpRpc() -{ - mg_mgr_free(&m_mg_mgr); -} - -bool TsHttpRpc::init(const char* ip, int port) -{ - char file_name[MAX_PATH] = { 0 }; - if (!GetModuleFileNameA(NULL, file_name, MAX_PATH)) - return false; - - int len = strlen(file_name); - - if (file_name[len] == '\\') - { - file_name[len] = '\0'; - } - char* match = strrchr(file_name, '\\'); - if (match != NULL) - { - *match = '\0'; - } - - struct mg_connection* nc = NULL; - - char addr[128] = { 0 }; - if (0 == strcmp(ip, "127.0.0.1") || 0 == strcmp(ip, "localhost")) - ex_strformat(addr, 128, "tcp://127.0.0.1:%d", port); - else - ex_strformat(addr, 128, "tcp://%s:%d", ip, port); - - nc = mg_bind(&m_mg_mgr, addr, _mg_event_handler); - if (nc == NULL) - { - EXLOGE("[rpc] TsHttpRpc::init %s:%d\n", ip, port); - return false; - } - nc->user_data = this; - - mg_set_protocol_http_websocket(nc); - - m_content_type_map[".js"] = "application/javascript"; - m_content_type_map[".png"] = "image/png"; - m_content_type_map[".jpeg"] = "image/jpeg"; - m_content_type_map[".jpg"] = "image/jpeg"; - m_content_type_map[".gif"] = "image/gif"; - m_content_type_map[".ico"] = "image/x-icon"; - m_content_type_map[".json"] = "image/json"; - m_content_type_map[".html"] = "text/html"; - m_content_type_map[".css"] = "text/css"; - m_content_type_map[".tif"] = "image/tiff"; - m_content_type_map[".tiff"] = "image/tiff"; - m_content_type_map[".svg"] = "text/html"; - - return true; -} - -void TsHttpRpc::run(void) -{ - while(!m_stop) - { - mg_mgr_poll(&m_mg_mgr, 500); - } -} - -void TsHttpRpc::stop(void) -{ - m_stop = true; -} - -void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_data) -{ - struct http_message *hm = (struct http_message*)ev_data; - - TsHttpRpc* _this = (TsHttpRpc*)nc->user_data; - if (NULL == _this) - { - EXLOGE("[ERROR] invalid http request.\n"); - return; - } - - switch (ev) - { - case MG_EV_HTTP_REQUEST: - { - ex_astr uri; - ex_chars _uri; - _uri.resize(hm->uri.len + 1); - memset(&_uri[0], 0, hm->uri.len + 1); - memcpy(&_uri[0], hm->uri.p, hm->uri.len); - uri = &_uri[0]; - -#ifdef EX_DEBUG - char* dbg_method = NULL; - if (hm->method.len == 3 && 0 == memcmp(hm->method.p, "GET", hm->method.len)) - dbg_method = "GET"; - else if (hm->method.len == 4 && 0 == memcmp(hm->method.p, "POST", hm->method.len)) - dbg_method = "POST"; - else - dbg_method = "UNSUPPORTED-HTTP-METHOD"; - - EXLOGV("[rpc] got %s request: %s\n", dbg_method, uri.c_str()); -#endif - ex_astr ret_buf; - bool b_is_index = false; - - if (uri == "/") - { - ex_wstr page = L"Teleport助手\n\n
Teleport助手工作正常!
"; - ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); - - mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); - nc->flags |= MG_F_SEND_AND_CLOSE; - return; - } - - if (uri == "/config") - { - uri = "/index.html"; - b_is_index = true; - } - - ex_astr temp; - int offset = uri.find("/", 1); - if (offset > 0) - { - temp = uri.substr(1, offset-1); - - if(temp == "api") { - ex_astr method; - ex_astr json_param; - int rv = _this->_parse_request(hm, method, json_param); - if (0 != rv) - { - EXLOGE("[ERROR] http-rpc got invalid request.\n"); - _this->_create_json_ret(ret_buf, rv); - } - else - { - _this->_process_js_request(method, json_param, ret_buf); - } - - mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); - nc->flags |= MG_F_SEND_AND_CLOSE; - return; - } - } - - - ex_astr file_suffix; - offset = uri.rfind("."); - if (offset > 0) - { - file_suffix = uri.substr(offset, uri.length()); - } - - ex_wstr2astr(g_env.m_site_path, temp); - ex_astr index_path = temp + uri; - - - FILE* file = ex_fopen(index_path.c_str(), "rb"); - if (file) - { - unsigned long file_size = 0; - char* buf = 0; - size_t ret = 0; - - fseek(file, 0, SEEK_END); - file_size = ftell(file); - buf = new char[file_size]; - memset(buf, 0, file_size); - fseek(file, 0, SEEK_SET); - ret = fread(buf, 1, file_size, file); - fclose(file); - - ex_astr content_type = _this->get_content_type(file_suffix); - - mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n", file_size, content_type.c_str()); - mg_send(nc, buf, (int)file_size); - delete []buf; - nc->flags |= MG_F_SEND_AND_CLOSE; - return; - } - else if (b_is_index) - { - ex_wstr page = L"404 Not Found

404 Not Found


Teleport Assistor configuration page not found.

"; - ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); - - mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); - nc->flags |= MG_F_SEND_AND_CLOSE; - return; - } - - } - break; - default: - break; - } -} - -int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args) -{ - if (NULL == req) - return TPE_FAILED; - - bool is_get = true; - if (req->method.len == 3 && 0 == memcmp(req->method.p, "GET", req->method.len)) - is_get = true; - else if (req->method.len == 4 && 0 == memcmp(req->method.p, "POST", req->method.len)) - is_get = false; - else - return TPE_HTTP_METHOD; - - ex_astrs strs; - - size_t pos_start = 1; // 跳过第一个字节,一定是 '/' - - size_t i = 0; - for (i = pos_start; i < req->uri.len; ++i) - { - if (req->uri.p[i] == '/') - { - if (i - pos_start > 0) - { - ex_astr tmp_uri; - tmp_uri.assign(req->uri.p + pos_start, i - pos_start); - strs.push_back(tmp_uri); - } - pos_start = i + 1; // 跳过当前找到的分隔符 - } - } - if (pos_start < req->uri.len) - { - ex_astr tmp_uri; - tmp_uri.assign(req->uri.p + pos_start, req->uri.len - pos_start); - strs.push_back(tmp_uri); - } - - if (0 == strs.size() || strs[0] != "api") - return TPE_PARAM; - - if (is_get) - { - if (2 == strs.size()) - { - func_cmd = strs[1]; - } - else if (3 == strs.size()) - { - func_cmd = strs[1]; - func_args = strs[2]; - } - else - { - return TPE_PARAM; - } - } - else - { - if (2 == strs.size()) - { - func_cmd = strs[1]; - } - else - { - return TPE_PARAM; - } - - if (req->body.len > 0) - { - func_args.assign(req->body.p, req->body.len); - } - } - - if (func_args.length() > 0) - { - // 将参数进行 url-decode 解码 - int len = func_args.length() * 2; - ex_chars sztmp; - sztmp.resize(len); - memset(&sztmp[0], 0, len); - if (-1 == ts_url_decode(func_args.c_str(), func_args.length(), &sztmp[0], len, 0)) - return TPE_HTTP_URL_ENCODE; - - func_args = &sztmp[0]; - } - - EXLOGV("[rpc] method=%s, json_param=%s\n", func_cmd.c_str(), func_args.c_str()); - - return TPE_OK; -} - -void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf) -{ - if (func_cmd == "get_version") - { - _rpc_func_get_version(func_args, buf); - } - else if (func_cmd == "run") - { - _rpc_func_run_client(func_args, buf); - } - else if (func_cmd == "rdp_play") - { - _rpc_func_rdp_play(func_args, buf); - } - else if (func_cmd == "get_config") - { - _rpc_func_get_config(func_args, buf); - } - else if (func_cmd == "set_config") - { - _rpc_func_set_config(func_args, buf); - } - else if (func_cmd == "file_action") - { - _rpc_func_file_action(func_args, buf); - } - else - { - EXLOGE("[rpc] got unknown command: %s\n", func_cmd.c_str()); - _create_json_ret(buf, TPE_UNKNOWN_CMD); - } -} - -void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode) -{ - // 返回: {"code":123} - - Json::FastWriter jr_writer; - Json::Value jr_root; - - jr_root["code"] = errcode; - buf = jr_writer.write(jr_root); -} - -void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root) -{ - Json::FastWriter jr_writer; - buf = jr_writer.write(jr_root); -} - -void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) -{ - // 入参:{"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2} - // authmode: 1=password, 2=private-key - // protocol: 1=rdp, 2=ssh - // SSH返回: {"code":0, "data":{"sid":"0123abcde"}} - // RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}} - - Json::Reader jreader; - Json::Value jsRoot; - - if (!jreader.parse(func_args.c_str(), jsRoot)) - { - _create_json_ret(buf, TPE_JSON_FORMAT); - return; - } - if (!jsRoot.isObject()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - // 判断参数是否正确 - if (!jsRoot["teleport_ip"].isString() - || !jsRoot["teleport_port"].isNumeric() || !jsRoot["remote_host_ip"].isString() - || !jsRoot["session_id"].isString() || !jsRoot["protocol_type"].isNumeric() || !jsRoot["protocol_sub_type"].isNumeric() - ) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - int pro_type = jsRoot["protocol_type"].asUInt(); - int pro_sub = jsRoot["protocol_sub_type"].asInt(); - - ex_astr teleport_ip = jsRoot["teleport_ip"].asCString(); - int teleport_port = jsRoot["teleport_port"].asUInt(); - - ex_astr real_host_ip = jsRoot["remote_host_ip"].asCString(); - ex_astr sid = jsRoot["session_id"].asCString(); - - ex_wstr w_exe_path; - WCHAR w_szCommandLine[MAX_PATH] = { 0 }; - - - ex_wstr w_sid; - ex_astr2wstr(sid, w_sid); - ex_wstr w_teleport_ip; - ex_astr2wstr(teleport_ip, w_teleport_ip); - ex_wstr w_real_host_ip; - ex_astr2wstr(real_host_ip, w_real_host_ip); - WCHAR w_port[32] = { 0 }; - swprintf_s(w_port, _T("%d"), teleport_port); - - ex_wstr tmp_rdp_file; // for .rdp file - - if (pro_type == TP_PROTOCOL_TYPE_RDP) - { - //============================================== - // RDP - //============================================== - - int rdp_w = 800; - int rdp_h = 640; - bool rdp_console = false; - - if (!jsRoot["rdp_width"].isNull()) { - if (jsRoot["rdp_width"].isNumeric()) { - rdp_w = jsRoot["rdp_width"].asUInt(); - } - else { - _create_json_ret(buf, TPE_PARAM); - return; - } - } - - if (!jsRoot["rdp_height"].isNull()) { - if (jsRoot["rdp_height"].isNumeric()) { - rdp_h = jsRoot["rdp_height"].asUInt(); - } - else { - _create_json_ret(buf, TPE_PARAM); - return; - } - } - - if (!jsRoot["rdp_console"].isNull()) { - if (jsRoot["rdp_console"].isBool()) { - rdp_console = jsRoot["rdp_console"].asBool(); - } - else { - _create_json_ret(buf, TPE_PARAM); - return; - } - } - - - int split_pos = sid.length() - 2; - ex_astr real_sid = sid.substr(0, split_pos); - ex_astr str_pwd_len = sid.substr(split_pos, sid.length()); - int n_pwd_len = strtol(str_pwd_len.c_str(), NULL, 16); - n_pwd_len -= real_sid.length(); - n_pwd_len -= 2; - char szPwd[256] = { 0 }; - for (int i = 0; i < n_pwd_len; i++) - { - szPwd[i] = '*'; - } - - ex_astr2wstr(real_sid, w_sid); - - w_exe_path = _T("\""); - w_exe_path += g_cfg.rdp_app + _T("\" "); - - ex_wstr rdp_name = g_cfg.rdp_name; - if (rdp_name == L"mstsc") { - w_exe_path += g_cfg.rdp_cmdline; - - int width = 0; - int higth = 0; - int cx = 0; - int cy = 0; - - int display = 1; - int iWidth = GetSystemMetrics(SM_CXSCREEN); - int iHeight = GetSystemMetrics(SM_CYSCREEN); - - if (rdp_w == 0 || rdp_h == 0) { - //全屏 - width = iWidth; - higth = iHeight; - display = 2; - } - else { - width = rdp_w; - higth = rdp_h; - display = 1; - } - - cx = (iWidth - width) / 2; - cy = (iHeight - higth) / 2; - if (cx < 0) - { - cx = 0; - } - if (cy < 0) - { - cy = 0; - } - - int console_mode = 0; - if (rdp_console) - console_mode = 1; - - std::string psw51b; - if (!calc_psw51b(szPwd, psw51b)) - { - EXLOGE("calc password failed.\n"); - _create_json_ret(buf, TPE_FAILED); - return; - } - - real_sid = "01" + real_sid; - - char sz_rdp_file_content[4096] = { 0 }; - sprintf_s(sz_rdp_file_content, rdp_content.c_str(), - console_mode, display, width, higth - , cx, cy, cx + width + 100, cy + higth + 100 - , teleport_ip.c_str(), teleport_port - , real_sid.c_str() - , psw51b.c_str() - ); - - char sz_file_name[MAX_PATH] = { 0 }; - char temp_path[MAX_PATH] = { 0 }; - DWORD ret = GetTempPathA(MAX_PATH, temp_path); - if (ret <= 0) - { - EXLOGE("fopen failed (%d).\n", GetLastError()); - _create_json_ret(buf, TPE_FAILED); - return; - } - - ex_astr temp_host_ip = real_host_ip; - ex_replace_all(temp_host_ip, ".", "-"); - - sprintf_s(sz_file_name, ("%s%s.rdp"), temp_path, temp_host_ip.c_str()); - - FILE* f = NULL; - if (fopen_s(&f, sz_file_name, "wt") != 0) - { - EXLOGE("fopen failed (%d).\n", GetLastError()); - _create_json_ret(buf, TPE_OPENFILE); - return; - } - // Write a string into the file. - fwrite(sz_rdp_file_content, strlen(sz_rdp_file_content), 1, f); - fclose(f); - ex_astr2wstr(sz_file_name, tmp_rdp_file); - - // 变量替换 - ex_replace_all(w_exe_path, _T("{tmp_rdp_file}"), tmp_rdp_file); - } - else if (g_cfg.rdp_name == L"freerdp") { - w_exe_path += L"{size} {console} {clipboard} {drives} "; - w_exe_path += g_cfg.rdp_cmdline; - - ex_wstr w_screen; - - if (rdp_w == 0 || rdp_h == 0) { - //全屏 - w_screen = _T("/f"); - } - else { - char sz_size[64] = {0}; - ex_strformat(sz_size, 63, "/size:%dx%d", rdp_w, rdp_h); - ex_astr2wstr(sz_size, w_screen); - } - - wchar_t* w_console = NULL; - - if (rdp_console) - { - w_console = L"/admin"; - } - else - { - w_console = L""; - } - - ex_wstr w_password; - ex_astr2wstr(szPwd, w_password); - w_exe_path += L" /p:"; - w_exe_path += w_password; - - w_sid = L"02" + w_sid; - - w_exe_path += L" /gdi:sw"; // 使用软件渲染,gdi:hw使用硬件加速,但是会出现很多黑块(录像回放时又是正常的!) - w_exe_path += L" -grab-keyboard"; // [new style] 防止启动FreeRDP后,失去本地键盘响应,必须得先最小化一下FreeRDP窗口(不过貌似不起作用) - - // 变量替换 - ex_replace_all(w_exe_path, _T("{size}"), w_screen); - ex_replace_all(w_exe_path, _T("{console}"), w_console); - //ex_replace_all(w_exe_path, _T("{clipboard}"), L"+clipboard"); - ex_replace_all(w_exe_path, _T("{clipboard}"), L"/clipboard"); - ex_replace_all(w_exe_path, _T("{drives}"), L"/drives"); - } - else { - _create_json_ret(buf, TPE_FAILED); - return; - } - } - else if (pro_type == TP_PROTOCOL_TYPE_SSH) - { - //============================================== - // SSH - //============================================== - - if (pro_sub == TP_PROTOCOL_TYPE_SSH_SHELL) - { - w_exe_path = _T("\""); - w_exe_path += g_cfg.ssh_app + _T("\" "); - w_exe_path += g_cfg.ssh_cmdline; - } - else - { - w_exe_path = _T("\""); - w_exe_path += g_cfg.scp_app + _T("\" "); - w_exe_path += g_cfg.scp_cmdline; - } - } - else if (pro_type == TP_PROTOCOL_TYPE_TELNET) - { - //============================================== - // TELNET - //============================================== - w_exe_path = _T("\""); - w_exe_path += g_cfg.telnet_app + _T("\" "); - w_exe_path += g_cfg.telnet_cmdline; - } - - ex_replace_all(w_exe_path, _T("{host_port}"), w_port); - ex_replace_all(w_exe_path, _T("{host_ip}"), w_teleport_ip.c_str()); - ex_replace_all(w_exe_path, _T("{user_name}"), w_sid.c_str()); - ex_replace_all(w_exe_path, _T("{real_ip}"), w_real_host_ip.c_str()); - ex_replace_all(w_exe_path, _T("{assist_tools_path}"), g_env.m_tools_path.c_str()); - - - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - Json::Value root_ret; - ex_astr utf8_path; - ex_wstr2astr(w_exe_path, utf8_path, EX_CODEPAGE_UTF8); - root_ret["path"] = utf8_path; - - if (!CreateProcess(NULL, (wchar_t *)w_exe_path.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) - { - EXLOGE(_T("CreateProcess() failed. Error=0x%08X.\n %s\n"), GetLastError(), w_exe_path.c_str()); - root_ret["code"] = TPE_START_CLIENT; - _create_json_ret(buf, root_ret); - return; - } - - root_ret["code"] = TPE_OK; - _create_json_ret(buf, root_ret); -} - -void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) -{ - Json::Reader jreader; - Json::Value jsRoot; - - if (!jreader.parse(func_args.c_str(), jsRoot)) - { - _create_json_ret(buf, TPE_JSON_FORMAT); - return; - } - - // 判断参数是否正确 - if (!jsRoot["rid"].isInt() - || !jsRoot["web"].isString() - || !jsRoot["sid"].isString() - || !jsRoot["user"].isString() - || !jsRoot["acc"].isString() - || !jsRoot["host"].isString() - || !jsRoot["start"].isString() - ) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - int rid = jsRoot["rid"].asInt(); - ex_astr a_url_base = jsRoot["web"].asCString(); - ex_astr a_sid = jsRoot["sid"].asCString(); - ex_astr a_user = jsRoot["user"].asCString(); - ex_astr a_acc = jsRoot["acc"].asCString(); - ex_astr a_host = jsRoot["host"].asCString(); - ex_astr a_start = jsRoot["start"].asCString(); - - char cmd_args[1024] = { 0 }; - ex_strformat(cmd_args, 1023, "%d \"%s\" \"%09d-%s-%s-%s-%s\"", rid, a_sid.c_str(), rid, a_user.c_str(), a_acc.c_str(), a_host.c_str(), a_start.c_str()); - - // TODO: 理论上不应该由助手来提前做域名转为IP这样的操作,而是应该讲域名发送给播放器,由播放器自己去处理 - // 但是在改造FreeRDP制作的播放器时,为了从服务器上下载文件,使用了Mongoose库,如果传入的是域名,会出现问题(貌似是异步查询DNS的问题) - // 所以暂时先由助手进行域名IP转换。 - { - unsigned int port_i = 0; - struct mg_str scheme, query, fragment, user_info, host, path; - - if (mg_parse_uri(mg_mk_str(a_url_base.c_str()), &scheme, &user_info, &host, &port_i, &path, &query, &fragment) != 0) { - EXLOGE(_T("parse url failed.\n")); - Json::Value root_ret; - root_ret["code"] = TPE_PARAM; - _create_json_ret(buf, root_ret); - return; - } - - ex_astr _scheme; - _scheme.assign(scheme.p, scheme.len); - - // 将host从域名转换为IP - ex_astr str_tp_host; - str_tp_host.assign(host.p, host.len); - struct hostent *tp_host = gethostbyname(str_tp_host.c_str()); - if (NULL == tp_host) { - EXLOGE(_T("resolve host name failed.\n")); - Json::Value root_ret; - root_ret["code"] = TPE_PARAM; - _create_json_ret(buf, root_ret); - return; - } - - int i = 0; - char* _ip = NULL; - if (tp_host->h_addrtype == AF_INET) - { - struct in_addr addr; - while (tp_host->h_addr_list[i] != 0) { - addr.s_addr = *(u_long *)tp_host->h_addr_list[i++]; - _ip = inet_ntoa(addr); - break; - } - } - - if (NULL == _ip) { - EXLOGE(_T("resolve host name failed.\n")); - Json::Value root_ret; - root_ret["code"] = TPE_PARAM; - _create_json_ret(buf, root_ret); - return; - } - - char _url_base[256]; - ex_strformat(_url_base, 255, "%s://%s:%d", _scheme.c_str(), _ip, port_i); - a_url_base = _url_base; - } - - ex_wstr w_url_base; - ex_astr2wstr(a_url_base, w_url_base); - ex_wstr w_cmd_args; - ex_astr2wstr(cmd_args, w_cmd_args); - - ex_wstr w_exe_path; - w_exe_path = _T("\""); - w_exe_path += g_env.m_tools_path + _T("\\tprdp\\tprdp-replay.exe\""); - w_exe_path += _T(" \""); - w_exe_path += w_url_base; - w_exe_path += _T("\" "); - w_exe_path += w_cmd_args; - - Json::Value root_ret; - ex_astr utf8_path; - ex_wstr2astr(w_exe_path, utf8_path, EX_CODEPAGE_UTF8); - root_ret["cmdline"] = utf8_path; - - EXLOGD(w_exe_path.c_str()); - - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - if (!CreateProcess(NULL, (wchar_t *)w_exe_path.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) - { - EXLOGE(_T("CreateProcess() failed. Error=0x%08X.\n %s\n"), GetLastError(), w_exe_path.c_str()); - root_ret["code"] = TPE_START_CLIENT; - _create_json_ret(buf, root_ret); - return; - } - - root_ret["code"] = TPE_OK; - _create_json_ret(buf, root_ret); - return; -} - -void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf) -{ - Json::Value jr_root; - jr_root["code"] = 0; - jr_root["data"] = g_cfg.get_root(); - _create_json_ret(buf, jr_root); -} - -void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf) -{ - Json::Reader jreader; - Json::Value jsRoot; - if (!jreader.parse(func_args.c_str(), jsRoot)) - { - _create_json_ret(buf, TPE_JSON_FORMAT); - return; - } - - if(!g_cfg.save(func_args)) - _create_json_ret(buf, TPE_FAILED); - else - _create_json_ret(buf, TPE_OK); -} - -void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) { - - Json::Reader jreader; - Json::Value jsRoot; - - if (!jreader.parse(func_args.c_str(), jsRoot)) - { - _create_json_ret(buf, TPE_JSON_FORMAT); - return; - } - // 判断参数是否正确 - if (!jsRoot["action"].isNumeric()) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - int action = jsRoot["action"].asUInt(); - - HWND hParent = GetForegroundWindow(); - if (NULL == hParent) - hParent = g_hDlgMain; - - BOOL ret = FALSE; - wchar_t wszReturnPath[MAX_PATH] = _T(""); - - if (action == 1 || action == 2) - { - OPENFILENAME ofn; - ex_wstr wsDefaultName; - ex_wstr wsDefaultPath; - StringCchCopy(wszReturnPath, MAX_PATH, wsDefaultName.c_str()); - - ZeroMemory(&ofn, sizeof(ofn)); - - ofn.lStructSize = sizeof(ofn); - ofn.lpstrTitle = _T("选择文件"); - ofn.hwndOwner = hParent; - ofn.lpstrFilter = _T("可执行程序 (*.exe)\0*.exe\0"); - ofn.lpstrFile = wszReturnPath; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrInitialDir = wsDefaultPath.c_str(); - ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST; - - if (action == 1) - { - ofn.Flags |= OFN_FILEMUSTEXIST; - ret = GetOpenFileName(&ofn); - } - else - { - ofn.Flags |= OFN_OVERWRITEPROMPT; - ret = GetSaveFileName(&ofn); - } - } - else if (action == 3) - { - BROWSEINFO bi; - ZeroMemory(&bi, sizeof(BROWSEINFO)); - bi.hwndOwner = NULL; - bi.pidlRoot = NULL; - bi.pszDisplayName = wszReturnPath; //此参数如为NULL则不能显示对话框 - bi.lpszTitle = _T("选择目录"); - bi.ulFlags = BIF_RETURNONLYFSDIRS; - bi.lpfn = NULL; - bi.iImage = 0; //初始化入口参数bi结束 - LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//调用显示选择对话框 - if (pIDList) - { - ret = true; - SHGetPathFromIDList(pIDList, wszReturnPath); - } - else - { - ret = false; - } - } - else if (action == 4) - { - ex_wstr wsDefaultName; - ex_wstr wsDefaultPath; - - if (wsDefaultPath.length() == 0) - { - _create_json_ret(buf, TPE_PARAM); - return; - } - - ex_wstr::size_type pos = 0; - - while (ex_wstr::npos != (pos = wsDefaultPath.find(L"/", pos))) - { - wsDefaultPath.replace(pos, 1, L"\\"); - pos += 1; - } - - ex_wstr wArg = L"/select, \""; - wArg += wsDefaultPath; - wArg += L"\""; - if ((int)ShellExecute(hParent, _T("open"), _T("explorer"), wArg.c_str(), NULL, SW_SHOW) > 32) - ret = true; - else - ret = false; - } - - if (ret) - { - if (action == 1 || action == 2 || action == 3) - { - ex_astr utf8_path; - ex_wstr2astr(wszReturnPath, utf8_path, EX_CODEPAGE_UTF8); - Json::Value root; - root["code"] = TPE_OK; - root["path"] = utf8_path; - _create_json_ret(buf, root); - - return; - } - else - { - _create_json_ret(buf, TPE_OK); - return; - } - } - else - { - _create_json_ret(buf, TPE_DATA); - return; - } -} - -void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf) -{ - Json::Value root_ret; - ex_wstr w_version = TP_ASSIST_VER; - ex_astr version; - ex_wstr2astr(w_version, version, EX_CODEPAGE_UTF8); - root_ret["version"] = version; - root_ret["code"] = TPE_OK; - _create_json_ret(buf, root_ret); - return; -} +#include "stdafx.h" + +#pragma warning(disable:4091) + +#include +#include +#include + +#pragma comment(lib, "Crypt32.lib") + +#include + +#include "ts_http_rpc.h" +#include "dlg_main.h" +#include "ts_ver.h" + +/* +1. +SecureCRT支持设置标签页的标题,命令行参数 /N "tab name"就可以 +Example: +To launch a new Telnet session, displaying the name "Houston, TX" on the tab, use the following: +/T /N "Houston, TX" /TELNET 192.168.0.6 + +2. +多次启动的SecureCRT放到一个窗口的不同标签页中,使用参数: /T + SecureCRT.exe /T /N "TP#ssh://192.168.1.3" /SSH2 /L root /PASSWORD 1234 120.26.109.25 + +3. +telnet客户端的启动: + putty.exe telnet://administrator@127.0.0.1:52389 +如果是SecureCRT,则需要 + SecureCRT.exe /T /N "TP#telnet://192.168.1.3" /SCRIPT X:\path\to\startup.vbs /TELNET 127.0.0.1 52389 +其中,startup.vbs的内容为: +---------文件开始--------- +#$language = "VBScript" +#$interface = "1.0" +Sub main + crt.Screen.Synchronous = True + crt.Screen.WaitForString "ogin: " + crt.Screen.Send "SESSION-ID" & VbCr + crt.Screen.Synchronous = False +End Sub +---------文件结束--------- + +4. 为了让putty的窗口标签显示正常的IP,可以尝试在连接成功后,主动向服务端发送下列命令: + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@192.168.1.2: \w\a\]$PS1" +手工测试了,ubuntu服务器可以,不知道是否能够支持所有的Linux。SecureCRT对此表示忽略。 +*/ + +//#define RDP_CLIENT_SYSTEM_BUILTIN +// #define RDP_CLIENT_SYSTEM_ACTIVE_CONTROL +//#define RDP_CLIENT_FREERDP + + +//#ifdef RDP_CLIENT_SYSTEM_BUILTIN + +//connect to console:i:%d +//compression:i:1 +//bitmapcachepersistenable:i:1 + +std::string rdp_content = "\ +administrative session:i:%d\n\ +screen mode id:i:%d\n\ +use multimon:i:0\n\ +desktopwidth:i:%d\n\ +desktopheight:i:%d\n\ +session bpp:i:16\n\ +winposstr:s:0,1,%d,%d,%d,%d\n\ +compression:i:1\n\ +bitmapcachepersistenable:i:1\n\ +keyboardhook:i:2\n\ +audiocapturemode:i:0\n\ +videoplaybackmode:i:1\n\ +connection type:i:7\n\ +networkautodetect:i:1\n\ +bandwidthautodetect:i:1\n\ +displayconnectionbar:i:1\n\ +enableworkspacereconnect:i:0\n\ +disable wallpaper:i:1\n\ +allow font smoothing:i:0\n\ +allow desktop composition:i:0\n\ +disable full window drag:i:1\n\ +disable menu anims:i:1\n\ +disable themes:i:1\n\ +disable cursor setting:i:1\n\ +full address:s:%s:%d\n\ +audiomode:i:0\n\ +redirectprinters:i:0\n\ +redirectcomports:i:0\n\ +redirectsmartcards:i:0\n\ +redirectclipboard:i:%d\n\ +redirectposdevices:i:0\n\ +autoreconnection enabled:i:0\n\ +authentication level:i:2\n\ +prompt for credentials:i:0\n\ +negotiate security layer:i:1\n\ +remoteapplicationmode:i:0\n\ +alternate shell:s:\n\ +shell working directory:s:\n\ +gatewayhostname:s:\n\ +gatewayusagemethod:i:4\n\ +gatewaycredentialssource:i:4\n\ +gatewayprofileusagemethod:i:0\n\ +promptcredentialonce:i:0\n\ +gatewaybrokeringtype:i:0\n\ +use redirection server name:i:0\n\ +rdgiskdcproxy:i:0\n\ +kdcproxyname:s:\n\ +drivestoredirect:s:%s\n\ +username:s:%s\n\ +password 51:b:%s\n\ +"; + +//redirectdirectx:i:0\n\ +//prompt for credentials on client:i:0\n\ + +//#endif + + +TsHttpRpc g_http_interface; + +void http_rpc_main_loop(void) +{ + if (!g_http_interface.init(TS_HTTP_RPC_HOST, TS_HTTP_RPC_PORT)) + { + EXLOGE("[ERROR] can not start HTTP-RPC listener, maybe port %d is already in use.\n", TS_HTTP_RPC_PORT); + return; + } + + EXLOGW("======================================================\n"); + EXLOGW("[rpc] TeleportAssist-HTTP-RPC ready on %s:%d\n", TS_HTTP_RPC_HOST, TS_HTTP_RPC_PORT); + + g_http_interface.run(); + + EXLOGW("[rpc] main loop end.\n"); +} + +void http_rpc_stop(void) +{ + g_http_interface.stop(); +} + +#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') + +int ts_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded) +{ + int i, j, a, b; + + for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) + { + if (src[i] == '%') + { + if (i < src_len - 2 && isxdigit(*(const unsigned char *)(src + i + 1)) && + isxdigit(*(const unsigned char *)(src + i + 2))) { + a = tolower(*(const unsigned char *)(src + i + 1)); + b = tolower(*(const unsigned char *)(src + i + 2)); + dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b)); + i += 2; + } + else + { + return -1; + } + } + else if (is_form_url_encoded && src[i] == '+') + { + dst[j] = ' '; + } + else + { + dst[j] = src[i]; + } + } + + dst[j] = '\0'; /* Null-terminate the destination */ + + return i >= src_len ? j : -1; +} + +bool calc_psw51b(const char* password, std::string& ret) +{ + DATA_BLOB DataIn; + DATA_BLOB DataOut; + + ex_wstr w_pswd; + ex_astr2wstr(password, w_pswd, EX_CODEPAGE_ACP); + + DataIn.cbData = w_pswd.length() * sizeof(wchar_t); + DataIn.pbData = (BYTE*)w_pswd.c_str(); + + + if (!CryptProtectData(&DataIn, L"psw", NULL, NULL, NULL, 0, &DataOut)) + return false; + + char szRet[5] = {0}; + for (int i = 0; i < DataOut.cbData; ++i) + { + sprintf_s(szRet, 5, "%02X", DataOut.pbData[i]); + ret += szRet; + } + + LocalFree(DataOut.pbData); + return true; +} + +TsHttpRpc::TsHttpRpc() +{ + m_stop = false; + mg_mgr_init(&m_mg_mgr, NULL); +} + +TsHttpRpc::~TsHttpRpc() +{ + mg_mgr_free(&m_mg_mgr); +} + +bool TsHttpRpc::init(const char* ip, int port) +{ + char file_name[MAX_PATH] = { 0 }; + if (!GetModuleFileNameA(NULL, file_name, MAX_PATH)) + return false; + + int len = strlen(file_name); + + if (file_name[len] == '\\') + { + file_name[len] = '\0'; + } + char* match = strrchr(file_name, '\\'); + if (match != NULL) + { + *match = '\0'; + } + + struct mg_connection* nc = NULL; + + char addr[128] = { 0 }; + if (0 == strcmp(ip, "127.0.0.1") || 0 == strcmp(ip, "localhost")) + ex_strformat(addr, 128, "tcp://127.0.0.1:%d", port); + else + ex_strformat(addr, 128, "tcp://%s:%d", ip, port); + + nc = mg_bind(&m_mg_mgr, addr, _mg_event_handler); + if (nc == NULL) + { + EXLOGE("[rpc] TsHttpRpc::init %s:%d\n", ip, port); + return false; + } + nc->user_data = this; + + mg_set_protocol_http_websocket(nc); + + m_content_type_map[".js"] = "application/javascript"; + m_content_type_map[".png"] = "image/png"; + m_content_type_map[".jpeg"] = "image/jpeg"; + m_content_type_map[".jpg"] = "image/jpeg"; + m_content_type_map[".gif"] = "image/gif"; + m_content_type_map[".ico"] = "image/x-icon"; + m_content_type_map[".json"] = "image/json"; + m_content_type_map[".html"] = "text/html"; + m_content_type_map[".css"] = "text/css"; + m_content_type_map[".tif"] = "image/tiff"; + m_content_type_map[".tiff"] = "image/tiff"; + m_content_type_map[".svg"] = "text/html"; + + return true; +} + +void TsHttpRpc::run(void) +{ + while(!m_stop) + { + mg_mgr_poll(&m_mg_mgr, 500); + } +} + +void TsHttpRpc::stop(void) +{ + m_stop = true; +} + +void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_data) +{ + struct http_message *hm = (struct http_message*)ev_data; + + TsHttpRpc* _this = (TsHttpRpc*)nc->user_data; + if (NULL == _this) + { + EXLOGE("[ERROR] invalid http request.\n"); + return; + } + + switch (ev) + { + case MG_EV_HTTP_REQUEST: + { + ex_astr uri; + ex_chars _uri; + _uri.resize(hm->uri.len + 1); + memset(&_uri[0], 0, hm->uri.len + 1); + memcpy(&_uri[0], hm->uri.p, hm->uri.len); + uri = &_uri[0]; + +#ifdef EX_DEBUG + char* dbg_method = NULL; + if (hm->method.len == 3 && 0 == memcmp(hm->method.p, "GET", hm->method.len)) + dbg_method = "GET"; + else if (hm->method.len == 4 && 0 == memcmp(hm->method.p, "POST", hm->method.len)) + dbg_method = "POST"; + else + dbg_method = "UNSUPPORTED-HTTP-METHOD"; + + EXLOGV("[rpc] got %s request: %s\n", dbg_method, uri.c_str()); +#endif + ex_astr ret_buf; + bool b_is_index = false; + + if (uri == "/") + { + ex_wstr page = L"Teleport助手\n\n
Teleport助手工作正常!
"; + ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); + + mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); + nc->flags |= MG_F_SEND_AND_CLOSE; + return; + } + + if (uri == "/config") + { + uri = "/index.html"; + b_is_index = true; + } + + ex_astr temp; + int offset = uri.find("/", 1); + if (offset > 0) + { + temp = uri.substr(1, offset-1); + + if(temp == "api") { + ex_astr method; + ex_astr json_param; + int rv = _this->_parse_request(hm, method, json_param); + if (0 != rv) + { + EXLOGE("[ERROR] http-rpc got invalid request.\n"); + _this->_create_json_ret(ret_buf, rv); + } + else + { + _this->_process_js_request(method, json_param, ret_buf); + } + + mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); + nc->flags |= MG_F_SEND_AND_CLOSE; + return; + } + } + + + ex_astr file_suffix; + offset = uri.rfind("."); + if (offset > 0) + { + file_suffix = uri.substr(offset, uri.length()); + } + + ex_wstr2astr(g_env.m_site_path, temp); + ex_astr index_path = temp + uri; + + + FILE* file = ex_fopen(index_path.c_str(), "rb"); + if (file) + { + unsigned long file_size = 0; + char* buf = 0; + size_t ret = 0; + + fseek(file, 0, SEEK_END); + file_size = ftell(file); + buf = new char[file_size]; + memset(buf, 0, file_size); + fseek(file, 0, SEEK_SET); + ret = fread(buf, 1, file_size, file); + fclose(file); + + ex_astr content_type = _this->get_content_type(file_suffix); + + mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n", file_size, content_type.c_str()); + mg_send(nc, buf, (int)file_size); + delete []buf; + nc->flags |= MG_F_SEND_AND_CLOSE; + return; + } + else if (b_is_index) + { + ex_wstr page = L"404 Not Found

404 Not Found


Teleport Assistor configuration page not found.

"; + ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); + + mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); + nc->flags |= MG_F_SEND_AND_CLOSE; + return; + } + + } + break; + default: + break; + } +} + +int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_astr& func_args) +{ + if (NULL == req) + return TPE_FAILED; + + bool is_get = true; + if (req->method.len == 3 && 0 == memcmp(req->method.p, "GET", req->method.len)) + is_get = true; + else if (req->method.len == 4 && 0 == memcmp(req->method.p, "POST", req->method.len)) + is_get = false; + else + return TPE_HTTP_METHOD; + + ex_astrs strs; + + size_t pos_start = 1; // 跳过第一个字节,一定是 '/' + + size_t i = 0; + for (i = pos_start; i < req->uri.len; ++i) + { + if (req->uri.p[i] == '/') + { + if (i - pos_start > 0) + { + ex_astr tmp_uri; + tmp_uri.assign(req->uri.p + pos_start, i - pos_start); + strs.push_back(tmp_uri); + } + pos_start = i + 1; // 跳过当前找到的分隔符 + } + } + if (pos_start < req->uri.len) + { + ex_astr tmp_uri; + tmp_uri.assign(req->uri.p + pos_start, req->uri.len - pos_start); + strs.push_back(tmp_uri); + } + + if (0 == strs.size() || strs[0] != "api") + return TPE_PARAM; + + if (is_get) + { + if (2 == strs.size()) + { + func_cmd = strs[1]; + } + else if (3 == strs.size()) + { + func_cmd = strs[1]; + func_args = strs[2]; + } + else + { + return TPE_PARAM; + } + } + else + { + if (2 == strs.size()) + { + func_cmd = strs[1]; + } + else + { + return TPE_PARAM; + } + + if (req->body.len > 0) + { + func_args.assign(req->body.p, req->body.len); + } + } + + if (func_args.length() > 0) + { + // 将参数进行 url-decode 解码 + int len = func_args.length() * 2; + ex_chars sztmp; + sztmp.resize(len); + memset(&sztmp[0], 0, len); + if (-1 == ts_url_decode(func_args.c_str(), func_args.length(), &sztmp[0], len, 0)) + return TPE_HTTP_URL_ENCODE; + + func_args = &sztmp[0]; + } + + EXLOGV("[rpc] method=%s, json_param=%s\n", func_cmd.c_str(), func_args.c_str()); + + return TPE_OK; +} + +void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func_args, ex_astr& buf) +{ + if (func_cmd == "get_version") + { + _rpc_func_get_version(func_args, buf); + } + else if (func_cmd == "run") + { + _rpc_func_run_client(func_args, buf); + } + else if (func_cmd == "rdp_play") + { + _rpc_func_rdp_play(func_args, buf); + } + else if (func_cmd == "get_config") + { + _rpc_func_get_config(func_args, buf); + } + else if (func_cmd == "set_config") + { + _rpc_func_set_config(func_args, buf); + } + else if (func_cmd == "file_action") + { + _rpc_func_file_action(func_args, buf); + } + else + { + EXLOGE("[rpc] got unknown command: %s\n", func_cmd.c_str()); + _create_json_ret(buf, TPE_UNKNOWN_CMD); + } +} + +void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode) +{ + // 返回: {"code":123} + + Json::FastWriter jr_writer; + Json::Value jr_root; + + jr_root["code"] = errcode; + buf = jr_writer.write(jr_root); +} + +void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root) +{ + Json::FastWriter jr_writer; + buf = jr_writer.write(jr_root); +} + +void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) +{ + // 入参:{"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2} + // authmode: 1=password, 2=private-key + // protocol: 1=rdp, 2=ssh + // SSH返回: {"code":0, "data":{"sid":"0123abcde"}} + // RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}} + + Json::Reader jreader; + Json::Value jsRoot; + + if (!jreader.parse(func_args.c_str(), jsRoot)) + { + _create_json_ret(buf, TPE_JSON_FORMAT); + return; + } + if (!jsRoot.isObject()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + // 判断参数是否正确 + if (!jsRoot["teleport_ip"].isString() + || !jsRoot["teleport_port"].isNumeric() || !jsRoot["remote_host_ip"].isString() + || !jsRoot["session_id"].isString() || !jsRoot["protocol_type"].isNumeric() || !jsRoot["protocol_sub_type"].isNumeric() + || !jsRoot["protocol_flag"].isNumeric() + ) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + int pro_type = jsRoot["protocol_type"].asUInt(); + int pro_sub = jsRoot["protocol_sub_type"].asInt(); + ex_u32 protocol_flag = jsRoot["protocol_flag"].asUInt(); + + ex_astr teleport_ip = jsRoot["teleport_ip"].asCString(); + int teleport_port = jsRoot["teleport_port"].asUInt(); + + ex_astr real_host_ip = jsRoot["remote_host_ip"].asCString(); + ex_astr sid = jsRoot["session_id"].asCString(); + + ex_wstr w_exe_path; + WCHAR w_szCommandLine[MAX_PATH] = { 0 }; + + + ex_wstr w_sid; + ex_astr2wstr(sid, w_sid); + ex_wstr w_teleport_ip; + ex_astr2wstr(teleport_ip, w_teleport_ip); + ex_wstr w_real_host_ip; + ex_astr2wstr(real_host_ip, w_real_host_ip); + WCHAR w_port[32] = { 0 }; + swprintf_s(w_port, _T("%d"), teleport_port); + + ex_wstr tmp_rdp_file; // for .rdp file + + if (pro_type == TP_PROTOCOL_TYPE_RDP) + { + //============================================== + // RDP + //============================================== + + bool flag_clipboard = (protocol_flag & TP_FLAG_RDP_CLIPBOARD); + bool flag_disk = (protocol_flag & TP_FLAG_RDP_DISK); + bool flag_console = (protocol_flag & TP_FLAG_RDP_CONSOLE); + + int rdp_w = 800; + int rdp_h = 640; + bool rdp_console = false; + + if (!jsRoot["rdp_width"].isNull()) { + if (jsRoot["rdp_width"].isNumeric()) { + rdp_w = jsRoot["rdp_width"].asUInt(); + } + else { + _create_json_ret(buf, TPE_PARAM); + return; + } + } + + if (!jsRoot["rdp_height"].isNull()) { + if (jsRoot["rdp_height"].isNumeric()) { + rdp_h = jsRoot["rdp_height"].asUInt(); + } + else { + _create_json_ret(buf, TPE_PARAM); + return; + } + } + + if (!jsRoot["rdp_console"].isNull()) { + if (jsRoot["rdp_console"].isBool()) { + rdp_console = jsRoot["rdp_console"].asBool(); + } + else { + _create_json_ret(buf, TPE_PARAM); + return; + } + } + + if (!flag_console) + rdp_console = false; + + + int split_pos = sid.length() - 2; + ex_astr real_sid = sid.substr(0, split_pos); + ex_astr str_pwd_len = sid.substr(split_pos, sid.length()); + int n_pwd_len = strtol(str_pwd_len.c_str(), NULL, 16); + n_pwd_len -= real_sid.length(); + n_pwd_len -= 2; + char szPwd[256] = { 0 }; + for (int i = 0; i < n_pwd_len; i++) + { + szPwd[i] = '*'; + } + + ex_astr2wstr(real_sid, w_sid); + + w_exe_path = _T("\""); + w_exe_path += g_cfg.rdp_app + _T("\" "); + + ex_wstr rdp_name = g_cfg.rdp_name; + if (rdp_name == L"mstsc") { + w_exe_path += g_cfg.rdp_cmdline; + + int width = 0; + int higth = 0; + int cx = 0; + int cy = 0; + + int display = 1; + int iWidth = GetSystemMetrics(SM_CXSCREEN); + int iHeight = GetSystemMetrics(SM_CYSCREEN); + + if (rdp_w == 0 || rdp_h == 0) { + //全屏 + width = iWidth; + higth = iHeight; + display = 2; + } + else { + width = rdp_w; + higth = rdp_h; + display = 1; + } + + cx = (iWidth - width) / 2; + cy = (iHeight - higth) / 2; + if (cx < 0) + { + cx = 0; + } + if (cy < 0) + { + cy = 0; + } + +// int console_mode = 0; +// if (rdp_console) +// console_mode = 1; + + std::string psw51b; + if (!calc_psw51b(szPwd, psw51b)) + { + EXLOGE("calc password failed.\n"); + _create_json_ret(buf, TPE_FAILED); + return; + } + + real_sid = "01" + real_sid; + + char sz_rdp_file_content[4096] = { 0 }; + sprintf_s(sz_rdp_file_content, rdp_content.c_str() + , (flag_console && rdp_console) ? 1 : 0 + , display, width, higth + , cx, cy, cx + width + 100, cy + higth + 100 + , flag_clipboard ? 1 : 0 + , teleport_ip.c_str(), teleport_port + , flag_disk ? "*" : "" + , real_sid.c_str() + , psw51b.c_str() + ); + + char sz_file_name[MAX_PATH] = { 0 }; + char temp_path[MAX_PATH] = { 0 }; + DWORD ret = GetTempPathA(MAX_PATH, temp_path); + if (ret <= 0) + { + EXLOGE("fopen failed (%d).\n", GetLastError()); + _create_json_ret(buf, TPE_FAILED); + return; + } + + ex_astr temp_host_ip = real_host_ip; + ex_replace_all(temp_host_ip, ".", "-"); + + sprintf_s(sz_file_name, ("%s%s.rdp"), temp_path, temp_host_ip.c_str()); + + FILE* f = NULL; + if (fopen_s(&f, sz_file_name, "wt") != 0) + { + EXLOGE("fopen failed (%d).\n", GetLastError()); + _create_json_ret(buf, TPE_OPENFILE); + return; + } + // Write a string into the file. + fwrite(sz_rdp_file_content, strlen(sz_rdp_file_content), 1, f); + fclose(f); + ex_astr2wstr(sz_file_name, tmp_rdp_file); + + // 变量替换 + ex_replace_all(w_exe_path, _T("{tmp_rdp_file}"), tmp_rdp_file); + } + else if (g_cfg.rdp_name == L"freerdp") { + w_exe_path += L"{size} {console} {clipboard} {drives} "; + w_exe_path += g_cfg.rdp_cmdline; + + ex_wstr w_screen; + + if (rdp_w == 0 || rdp_h == 0) { + //全屏 + w_screen = _T("/f"); + } + else { + char sz_size[64] = {0}; + ex_strformat(sz_size, 63, "/size:%dx%d", rdp_w, rdp_h); + ex_astr2wstr(sz_size, w_screen); + } + +// wchar_t* w_console = NULL; +// +// if (flag_console && rdp_console) +// { +// w_console = L"/admin"; +// } +// else +// { +// w_console = L""; +// } + + ex_wstr w_password; + ex_astr2wstr(szPwd, w_password); + w_exe_path += L" /p:"; + w_exe_path += w_password; + + w_sid = L"02" + w_sid; + + w_exe_path += L" /gdi:sw"; // 使用软件渲染,gdi:hw使用硬件加速,但是会出现很多黑块(录像回放时又是正常的!) + w_exe_path += L" -grab-keyboard"; // [new style] 防止启动FreeRDP后,失去本地键盘响应,必须得先最小化一下FreeRDP窗口(不过貌似不起作用) + + // 变量替换 + ex_replace_all(w_exe_path, _T("{size}"), w_screen); + + if (flag_console && rdp_console) + ex_replace_all(w_exe_path, _T("{console}"), L"/admin"); + else + ex_replace_all(w_exe_path, _T("{console}"), L""); + + //ex_replace_all(w_exe_path, _T("{clipboard}"), L"+clipboard"); + + if(flag_clipboard) + ex_replace_all(w_exe_path, _T("{clipboard}"), L"/clipboard"); + else + ex_replace_all(w_exe_path, _T("{clipboard}"), L"-clipboard"); + + if(flag_disk) + ex_replace_all(w_exe_path, _T("{drives}"), L"/drives"); + else + ex_replace_all(w_exe_path, _T("{drives}"), L"-drives"); + } + else { + _create_json_ret(buf, TPE_FAILED); + return; + } + } + else if (pro_type == TP_PROTOCOL_TYPE_SSH) + { + //============================================== + // SSH + //============================================== + + if (pro_sub == TP_PROTOCOL_TYPE_SSH_SHELL) + { + w_exe_path = _T("\""); + w_exe_path += g_cfg.ssh_app + _T("\" "); + w_exe_path += g_cfg.ssh_cmdline; + } + else + { + w_exe_path = _T("\""); + w_exe_path += g_cfg.scp_app + _T("\" "); + w_exe_path += g_cfg.scp_cmdline; + } + } + else if (pro_type == TP_PROTOCOL_TYPE_TELNET) + { + //============================================== + // TELNET + //============================================== + w_exe_path = _T("\""); + w_exe_path += g_cfg.telnet_app + _T("\" "); + w_exe_path += g_cfg.telnet_cmdline; + } + + ex_replace_all(w_exe_path, _T("{host_port}"), w_port); + ex_replace_all(w_exe_path, _T("{host_ip}"), w_teleport_ip.c_str()); + ex_replace_all(w_exe_path, _T("{user_name}"), w_sid.c_str()); + ex_replace_all(w_exe_path, _T("{real_ip}"), w_real_host_ip.c_str()); + ex_replace_all(w_exe_path, _T("{assist_tools_path}"), g_env.m_tools_path.c_str()); + + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + Json::Value root_ret; + ex_astr utf8_path; + ex_wstr2astr(w_exe_path, utf8_path, EX_CODEPAGE_UTF8); + root_ret["path"] = utf8_path; + + if (!CreateProcess(NULL, (wchar_t *)w_exe_path.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + EXLOGE(_T("CreateProcess() failed. Error=0x%08X.\n %s\n"), GetLastError(), w_exe_path.c_str()); + root_ret["code"] = TPE_START_CLIENT; + _create_json_ret(buf, root_ret); + return; + } + + root_ret["code"] = TPE_OK; + _create_json_ret(buf, root_ret); +} + +void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) +{ + Json::Reader jreader; + Json::Value jsRoot; + + if (!jreader.parse(func_args.c_str(), jsRoot)) + { + _create_json_ret(buf, TPE_JSON_FORMAT); + return; + } + + // 判断参数是否正确 + if (!jsRoot["rid"].isInt() + || !jsRoot["web"].isString() + || !jsRoot["sid"].isString() + || !jsRoot["user"].isString() + || !jsRoot["acc"].isString() + || !jsRoot["host"].isString() + || !jsRoot["start"].isString() + ) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + int rid = jsRoot["rid"].asInt(); + ex_astr a_url_base = jsRoot["web"].asCString(); + ex_astr a_sid = jsRoot["sid"].asCString(); + ex_astr a_user = jsRoot["user"].asCString(); + ex_astr a_acc = jsRoot["acc"].asCString(); + ex_astr a_host = jsRoot["host"].asCString(); + ex_astr a_start = jsRoot["start"].asCString(); + + char cmd_args[1024] = { 0 }; + ex_strformat(cmd_args, 1023, "%d \"%s\" \"%09d-%s-%s-%s-%s\"", rid, a_sid.c_str(), rid, a_user.c_str(), a_acc.c_str(), a_host.c_str(), a_start.c_str()); + + // TODO: 理论上不应该由助手来提前做域名转为IP这样的操作,而是应该讲域名发送给播放器,由播放器自己去处理 + // 但是在改造FreeRDP制作的播放器时,为了从服务器上下载文件,使用了Mongoose库,如果传入的是域名,会出现问题(貌似是异步查询DNS的问题) + // 所以暂时先由助手进行域名IP转换。 + { + unsigned int port_i = 0; + struct mg_str scheme, query, fragment, user_info, host, path; + + if (mg_parse_uri(mg_mk_str(a_url_base.c_str()), &scheme, &user_info, &host, &port_i, &path, &query, &fragment) != 0) { + EXLOGE(_T("parse url failed.\n")); + Json::Value root_ret; + root_ret["code"] = TPE_PARAM; + _create_json_ret(buf, root_ret); + return; + } + + ex_astr _scheme; + _scheme.assign(scheme.p, scheme.len); + + // 将host从域名转换为IP + ex_astr str_tp_host; + str_tp_host.assign(host.p, host.len); + struct hostent *tp_host = gethostbyname(str_tp_host.c_str()); + if (NULL == tp_host) { + EXLOGE(_T("resolve host name failed.\n")); + Json::Value root_ret; + root_ret["code"] = TPE_PARAM; + _create_json_ret(buf, root_ret); + return; + } + + int i = 0; + char* _ip = NULL; + if (tp_host->h_addrtype == AF_INET) + { + struct in_addr addr; + while (tp_host->h_addr_list[i] != 0) { + addr.s_addr = *(u_long *)tp_host->h_addr_list[i++]; + _ip = inet_ntoa(addr); + break; + } + } + + if (NULL == _ip) { + EXLOGE(_T("resolve host name failed.\n")); + Json::Value root_ret; + root_ret["code"] = TPE_PARAM; + _create_json_ret(buf, root_ret); + return; + } + + char _url_base[256]; + ex_strformat(_url_base, 255, "%s://%s:%d", _scheme.c_str(), _ip, port_i); + a_url_base = _url_base; + } + + ex_wstr w_url_base; + ex_astr2wstr(a_url_base, w_url_base); + ex_wstr w_cmd_args; + ex_astr2wstr(cmd_args, w_cmd_args); + + ex_wstr w_exe_path; + w_exe_path = _T("\""); + w_exe_path += g_env.m_tools_path + _T("\\tprdp\\tprdp-replay.exe\""); + w_exe_path += _T(" \""); + w_exe_path += w_url_base; + w_exe_path += _T("\" "); + w_exe_path += w_cmd_args; + + Json::Value root_ret; + ex_astr utf8_path; + ex_wstr2astr(w_exe_path, utf8_path, EX_CODEPAGE_UTF8); + root_ret["cmdline"] = utf8_path; + + EXLOGD(w_exe_path.c_str()); + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + if (!CreateProcess(NULL, (wchar_t *)w_exe_path.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + EXLOGE(_T("CreateProcess() failed. Error=0x%08X.\n %s\n"), GetLastError(), w_exe_path.c_str()); + root_ret["code"] = TPE_START_CLIENT; + _create_json_ret(buf, root_ret); + return; + } + + root_ret["code"] = TPE_OK; + _create_json_ret(buf, root_ret); + return; +} + +void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf) +{ + Json::Value jr_root; + jr_root["code"] = 0; + jr_root["data"] = g_cfg.get_root(); + _create_json_ret(buf, jr_root); +} + +void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf) +{ + Json::Reader jreader; + Json::Value jsRoot; + if (!jreader.parse(func_args.c_str(), jsRoot)) + { + _create_json_ret(buf, TPE_JSON_FORMAT); + return; + } + + if(!g_cfg.save(func_args)) + _create_json_ret(buf, TPE_FAILED); + else + _create_json_ret(buf, TPE_OK); +} + +void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) { + + Json::Reader jreader; + Json::Value jsRoot; + + if (!jreader.parse(func_args.c_str(), jsRoot)) + { + _create_json_ret(buf, TPE_JSON_FORMAT); + return; + } + // 判断参数是否正确 + if (!jsRoot["action"].isNumeric()) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + int action = jsRoot["action"].asUInt(); + + HWND hParent = GetForegroundWindow(); + if (NULL == hParent) + hParent = g_hDlgMain; + + BOOL ret = FALSE; + wchar_t wszReturnPath[MAX_PATH] = _T(""); + + if (action == 1 || action == 2) + { + OPENFILENAME ofn; + ex_wstr wsDefaultName; + ex_wstr wsDefaultPath; + StringCchCopy(wszReturnPath, MAX_PATH, wsDefaultName.c_str()); + + ZeroMemory(&ofn, sizeof(ofn)); + + ofn.lStructSize = sizeof(ofn); + ofn.lpstrTitle = _T("选择文件"); + ofn.hwndOwner = hParent; + ofn.lpstrFilter = _T("可执行程序 (*.exe)\0*.exe\0"); + ofn.lpstrFile = wszReturnPath; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrInitialDir = wsDefaultPath.c_str(); + ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST; + + if (action == 1) + { + ofn.Flags |= OFN_FILEMUSTEXIST; + ret = GetOpenFileName(&ofn); + } + else + { + ofn.Flags |= OFN_OVERWRITEPROMPT; + ret = GetSaveFileName(&ofn); + } + } + else if (action == 3) + { + BROWSEINFO bi; + ZeroMemory(&bi, sizeof(BROWSEINFO)); + bi.hwndOwner = NULL; + bi.pidlRoot = NULL; + bi.pszDisplayName = wszReturnPath; //此参数如为NULL则不能显示对话框 + bi.lpszTitle = _T("选择目录"); + bi.ulFlags = BIF_RETURNONLYFSDIRS; + bi.lpfn = NULL; + bi.iImage = 0; //初始化入口参数bi结束 + LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//调用显示选择对话框 + if (pIDList) + { + ret = true; + SHGetPathFromIDList(pIDList, wszReturnPath); + } + else + { + ret = false; + } + } + else if (action == 4) + { + ex_wstr wsDefaultName; + ex_wstr wsDefaultPath; + + if (wsDefaultPath.length() == 0) + { + _create_json_ret(buf, TPE_PARAM); + return; + } + + ex_wstr::size_type pos = 0; + + while (ex_wstr::npos != (pos = wsDefaultPath.find(L"/", pos))) + { + wsDefaultPath.replace(pos, 1, L"\\"); + pos += 1; + } + + ex_wstr wArg = L"/select, \""; + wArg += wsDefaultPath; + wArg += L"\""; + if ((int)ShellExecute(hParent, _T("open"), _T("explorer"), wArg.c_str(), NULL, SW_SHOW) > 32) + ret = true; + else + ret = false; + } + + if (ret) + { + if (action == 1 || action == 2 || action == 3) + { + ex_astr utf8_path; + ex_wstr2astr(wszReturnPath, utf8_path, EX_CODEPAGE_UTF8); + Json::Value root; + root["code"] = TPE_OK; + root["path"] = utf8_path; + _create_json_ret(buf, root); + + return; + } + else + { + _create_json_ret(buf, TPE_OK); + return; + } + } + else + { + _create_json_ret(buf, TPE_DATA); + return; + } +} + +void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf) +{ + Json::Value root_ret; + ex_wstr w_version = TP_ASSIST_VER; + ex_astr version; + ex_wstr2astr(w_version, version, EX_CODEPAGE_UTF8); + root_ret["version"] = version; + root_ret["code"] = TPE_OK; + _create_json_ret(buf, root_ret); + return; +} diff --git a/common/teleport/teleport_const.h b/common/teleport/teleport_const.h index 22b5cc2..3c5b25e 100644 --- a/common/teleport/teleport_const.h +++ b/common/teleport/teleport_const.h @@ -58,6 +58,27 @@ #define TP_SESS_STAT_ERR_START_IO 108 // 会话结束,因为网络中断 +//======================================================= +// 授权标记 +//======================================================= +#define TP_FLAG_ALL 0xFFFFFFFF +// 会话记录相关 +#define TP_FLAG_RECORD_REPLAY 0x00000001 // 允许记录历史(录像回放) +#define TP_FLAG_RECORD_REAL_TIME 0x00000002 // 允许实时监控 +// RDP相关 +#define TP_FLAG_RDP_DESKTOP 0x00000001 // 允许远程桌面 +#define TP_FLAG_RDP_CLIPBOARD 0x00000002 // 允许剪贴板 +#define TP_FLAG_RDP_DISK 0x00000004 // 允许磁盘映射 +#define TP_FLAG_RDP_APP 0x00000008 // 允许远程APP(尚未实现) +#define TP_FLAG_RDP_CONSOLE 0x00001000 //允许连接到管理员会话(RDP的console选项) +// SSH相关 +#define TP_FLAG_SSH_SHELL 0x00000001 // 允许SHELL +#define TP_FLAG_SSH_SFTP 0x00000002 // 允许SFTP +#define TP_FLAG_SSH_X11 0x00000004 // 允许X11转发(尚未实现) +#define TP_FLAG_SSH_EXEC 0x00000008 // 允许exec执行远程命令(尚未实现) +#define TP_FLAG_SSH_TUNNEL 0x00000010 // allow ssh tunnel. (not impl.) + + //======================================================= // 错误值 //======================================================= diff --git a/server/tp_core/common/protocol_interface.h b/server/tp_core/common/protocol_interface.h index 60fa17c..c7a68ee 100644 --- a/server/tp_core/common/protocol_interface.h +++ b/server/tp_core/common/protocol_interface.h @@ -38,6 +38,7 @@ typedef struct TPP_CONNECT_INFO int protocol_type; int protocol_sub_type; int protocol_flag; + int record_flag; int auth_type; }TPP_CONNECT_INFO; diff --git a/server/tp_core/core/ts_main.cpp b/server/tp_core/core/ts_main.cpp index 6dd355c..65cdb82 100644 --- a/server/tp_core/core/ts_main.cpp +++ b/server/tp_core/core/ts_main.cpp @@ -44,6 +44,7 @@ TPP_CONNECT_INFO* tpp_get_connect_info(const char* sid) info->protocol_type = sinfo.protocol_type; info->protocol_sub_type = sinfo.protocol_sub_type; info->protocol_flag = sinfo.protocol_flag; + info->record_flag = sinfo.record_flag; info->auth_type= sinfo.auth_type; return info; diff --git a/server/tp_core/core/ts_session.cpp b/server/tp_core/core/ts_session.cpp index 45cfa4c..a708e1b 100644 --- a/server/tp_core/core/ts_session.cpp +++ b/server/tp_core/core/ts_session.cpp @@ -87,6 +87,7 @@ bool TsSessionManager::get_connect_info(const ex_astr& sid, TS_CONNECT_INFO& inf info.protocol_type = it->second->protocol_type; info.protocol_sub_type = it->second->protocol_sub_type; info.protocol_flag = it->second->protocol_flag; + info.record_flag = it->second->record_flag; info.auth_type = it->second->auth_type; it->second->ref_count++; diff --git a/server/tp_core/core/ts_session.h b/server/tp_core/core/ts_session.h index 7227810..23271de 100644 --- a/server/tp_core/core/ts_session.h +++ b/server/tp_core/core/ts_session.h @@ -33,6 +33,7 @@ typedef struct TS_CONNECT_INFO int protocol_type; int protocol_sub_type; int protocol_flag; + int record_flag; int auth_type; int ref_count;// 这个连接信息的引用计数,如果创建的连接信息从来未被使用,则超过30秒后自动销毁 diff --git a/server/tp_core/core/ts_web_rpc.cpp b/server/tp_core/core/ts_web_rpc.cpp index e4a01bb..cf5b899 100644 --- a/server/tp_core/core/ts_web_rpc.cpp +++ b/server/tp_core/core/ts_web_rpc.cpp @@ -83,9 +83,11 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) EXLOGE("connection info: need `protocol_sub_type`.\n"); if(!_jret["auth_type"].isInt()) EXLOGE("connection info: need `auth_type`.\n"); - if(!_jret["protocol_flag"].isInt()) - EXLOGE("connection info: need `protocol_flag`.\n"); - if(!_jret["_enc"].isInt()) + if (!_jret["protocol_flag"].isUInt()) + EXLOGE("connection info: need `protocol_flag`.\n"); + if (!_jret["record_flag"].isUInt()) + EXLOGE("connection info: need `record_flag`.\n"); + if (!_jret["_enc"].isInt()) EXLOGE("connection info: need `_enc`.\n"); if(!_jret["user_username"].isString()) EXLOGE("connection info: need `user_username`.\n"); @@ -112,7 +114,8 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) || !_jret["protocol_type"].isInt() || !_jret["protocol_sub_type"].isInt() || !_jret["auth_type"].isInt() - || !_jret["protocol_flag"].isInt() + || !_jret["protocol_flag"].isUInt() + || !_jret["record_flag"].isUInt() || !_jret["_enc"].isInt() || !_jret["user_username"].isString() @@ -145,6 +148,7 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) int protocol_sub_type = 0; int auth_type = 0; int protocol_flag = 0; + int record_flag = 0; bool _enc; user_id = _jret["user_id"].asInt(); @@ -161,7 +165,8 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) password_prompt = _jret["password_prompt"].asString(); protocol_type = _jret["protocol_type"].asInt(); protocol_sub_type = _jret["protocol_sub_type"].asInt(); - protocol_flag = _jret["protocol_flag"].asInt(); + protocol_flag = _jret["protocol_flag"].asUInt(); + record_flag = _jret["record_flag"].asUInt(); auth_type = _jret["auth_type"].asInt(); _enc = _jret["_enc"].asBool(); @@ -204,6 +209,7 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) info.protocol_sub_type = protocol_sub_type; info.auth_type = auth_type; info.protocol_flag = protocol_flag; + info.record_flag = record_flag; return TPE_OK; } diff --git a/server/tp_core/protocol/telnet/telnet_conn.cpp b/server/tp_core/protocol/telnet/telnet_conn.cpp index 9fe3942..73cea71 100644 --- a/server/tp_core/protocol/telnet/telnet_conn.cpp +++ b/server/tp_core/protocol/telnet/telnet_conn.cpp @@ -1,9 +1,9 @@ -#include "telnet_conn.h" -#include "telnet_session.h" -#include "../../common/ts_memstream.h" -#include "../../common/ts_const.h" -#include - +#include "telnet_conn.h" +#include "telnet_session.h" +#include "../../common/ts_memstream.h" +#include "../../common/ts_const.h" +#include + ex_astr _uv_str_error(int retcode) { ex_astr err; @@ -11,262 +11,262 @@ ex_astr _uv_str_error(int retcode) err += ":"; err += uv_strerror(retcode); return std::move(err); -} - -TelnetConn::TelnetConn(TelnetSession *sess, bool is_server_side) : m_session(sess), m_is_server(is_server_side) { - if (is_server_side) { - m_name = "cli<->tp"; - m_state = TELNET_CONN_STATE_CONNECTED; - } - else { - m_name = "tp<->srv"; - m_state = TELNET_CONN_STATE_FREE; - } - - m_timer_running = false; - - uv_tcp_init(sess->get_loop(), &m_handle); - m_handle.data = this; -} - -TelnetConn::~TelnetConn() { -} - -bool TelnetConn::start_recv() { - int err = uv_read_start((uv_stream_t *)&m_handle, _on_alloc, _on_recv); - if (err != 0) { - EXLOGE("[telnet] [%s] can not start to read.\n", m_name); - m_session->close(TP_SESS_STAT_ERR_IO); - return false; - } - - return true; -} - -void TelnetConn::close() { - if (m_state == TELNET_CONN_STATE_FREE || m_state == TELNET_CONN_STATE_CLOSING) - return; - - if (m_timer_running) { - m_timer_running = false; - uv_timer_stop(&m_timer_connect_timeout); - - EXLOGW("[telnet] [%s] try to close while it connecting.\n", m_name); - m_state = TELNET_CONN_STATE_CLOSING; - uv_close(handle(), NULL); - - return; - } - - uv_read_stop((uv_stream_t*)&m_handle); - uv_close(handle() , _uv_on_closed); -} - -void TelnetConn::_uv_on_closed(uv_handle_t *handle) { - TelnetConn *_this = (TelnetConn *)handle->data; - _this->m_state = TELNET_CONN_STATE_FREE; - _this->m_session->on_conn_close(); -} - -void TelnetConn::_on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - TelnetConn *_this = (TelnetConn *) handle->data; - buf->base = (char *) calloc(1, suggested_size); - buf->len = suggested_size; -} - -void TelnetConn::_on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { - TelnetConn *_this = (TelnetConn *) handle->data; - - if (nread == 0) { - free(buf->base); - return; - } - else if (nread < 0) { - free(buf->base); - - if (nread == UV_EOF) - EXLOGD("[telnet] [%s] [recv] disconnected.\n", _this->m_name); - else if(nread == UV_ECONNRESET) - EXLOGD("[telnet] [%s] [recv] connection reset by peer.\n", _this->m_name); - else - EXLOGD("[telnet] [%s] [recv] %s.\n", _this->m_name, _uv_str_error(nread).c_str()); - - -// if (nread == -4077) -// EXLOGD("[telnet] [%s] [recv] disconnected.\n", _this->m_name); -// else if (nread == -104) -// EXLOGD("[telnet] [%s] [recv] connection reset by peer.\n", _this->m_name); -// else -// EXLOGD("[telnet] [%s] [recv] nread=%d.\n", _this->m_name, nread); - - _this->m_session->close(TP_SESS_STAT_END); - return; - } - else { -// #ifdef LOG_DATA -// if(!_this->m_session->is_relay()) -// EXLOG_BIN((ex_u8*)buf->base, nread, "[telnet] [%s] RECV %d.", _this->m_name, nread); -// #endif - } - - _this->m_buf_data.append((ex_u8 *) buf->base, nread); - free(buf->base); - - _this->m_session->do_next(_this); -} - -bool TelnetConn::send(MemBuffer &mbuf) { - return _raw_send(mbuf.data(), mbuf.size()); -} - -bool TelnetConn::send(const ex_u8 *data, size_t size) { - return _raw_send(data, size); -} - -bool TelnetConn::_raw_send(const ex_u8 *data, size_t size) { -// #ifdef LOG_DATA -// if (!m_session->is_relay()) -// EXLOG_BIN(data, size, "[telnet] [%s] SEND %dB.", m_name, size); -// #endif - - uv_write_t *w = (uv_write_t *) calloc(1, sizeof(uv_write_t)); - - ex_u8 *_data = (ex_u8 *) calloc(1, size); - if (NULL == _data) { - free(w); - EXLOGE("[telnet] alloc buffer %dB failed.\n", size); - return false; - } - memcpy(_data, data, size); - - uv_buf_t *_buf = (uv_buf_t *) calloc(1, sizeof(uv_buf_t)); - _buf->base = (char *) _data; - _buf->len = size; - - w->data = _buf; - if (0 == uv_write(w, (uv_stream_t *) &m_handle, _buf, 1, _on_send_done)) - return true; - else { - EXLOGE("[telnet] [%s] raw_send() failed.\n", m_name); - return false; - } -} - -void TelnetConn::_on_send_done(uv_write_t *req, int status) { - uv_buf_t *_buf = (uv_buf_t *) req->data; - free(_buf->base); - free(_buf); - free(req); - - if (status == UV_ECANCELED) { - EXLOGE("[telnet] _on_send_done() got UV_ECANCELED.\n"); - return; - } -} - -void TelnetConn::connect(const char *server_ip, ex_u16 server_port) { - m_server_ip = server_ip; - m_server_port = server_port; - - if (m_state == TELNET_CONN_STATE_CONNECTED) { - // 当前已经连接上了服务器了,断开重连 - EXLOGV("[telnet] [%s] [%s] try to disconnect. %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port); - m_state = TELNET_CONN_STATE_CLOSING; - uv_close((uv_handle_t *) &m_handle, _uv_on_reconnect); - return; - } - else { - EXLOGV("[telnet] [%s] [%s] try to connect to real TELNET server at %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port); - } - - struct sockaddr_in addr; - uv_ip4_addr(server_ip, server_port, &addr); - - uv_connect_t *conn_req = (uv_connect_t *) calloc(1, sizeof(uv_connect_t)); - conn_req->data = this; - - // 设置一个超时回调,如果超时发生时连接尚未完成,就报错 - uv_timer_init(m_session->get_loop(), &m_timer_connect_timeout); - m_timer_connect_timeout.data = this; - -#ifdef EX_DEBUG - uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 5000, 0); -#else - uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 10000, 0); -#endif - - m_timer_running = true; - - //m_is_connecting = true; - m_state = TELNET_CONN_STATE_CONNECTING; - int err = 0; - if ((err = uv_tcp_connect(conn_req, &m_handle, (const struct sockaddr *) &addr, _uv_on_connected)) != 0) { - free(conn_req); - EXLOGE("[telnet] [%s] can not connect to server: %s\n", m_name, uv_strerror(err)); - - m_timer_running = false; - uv_timer_stop(&m_timer_connect_timeout); - uv_close((uv_handle_t*)&m_timer_connect_timeout, _uv_on_timer_connect_timeout_closed); - - m_state = TELNET_CONN_STATE_FREE; - m_session->close(TP_SESS_STAT_ERR_CONNECT); - } -} - -void TelnetConn::_uv_on_connect_timeout(uv_timer_t *timer) -{ - TelnetConn *_this = (TelnetConn *)timer->data; - - if (_this->m_timer_running) { - _this->m_timer_running = false; - uv_timer_stop(&_this->m_timer_connect_timeout); - uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed); - } - - // 如果在连接成功之前就超时了,则关闭连接 - EXLOGE("[telnet] [%s] timeout when connect to real TELNET server, cancel connection.\n", _this->m_name); - _this->m_state = TELNET_CONN_STATE_CLOSING; - uv_close(_this->handle(), _uv_on_closed); -} - -void TelnetConn::_uv_on_reconnect(uv_handle_t *handle) { - TelnetConn *_this = (TelnetConn *)handle->data; - _this->m_state = TELNET_CONN_STATE_FREE; - - uv_tcp_init(_this->m_session->get_loop(), &_this->m_handle); - _this->m_handle.data = _this; - - _this->connect(_this->m_server_ip.c_str(), _this->m_server_port); -} - -void TelnetConn::_uv_on_connected(uv_connect_t *req, int status) { - TelnetConn *_this = (TelnetConn *)req->data; - free(req); - - if (_this->m_timer_running) { - _this->m_timer_running = false; - uv_timer_stop(&_this->m_timer_connect_timeout); - uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed); - } - - if (status != 0) { - EXLOGE("[telnet] [%s] cannot connect to real TELNET server. %s\n", _this->m_name, uv_strerror(status)); - _this->m_state = TELNET_CONN_STATE_FREE; - _this->m_session->close(TP_SESS_STAT_ERR_CONNECT); - return; - } - - EXLOGW("[telnet] [%s] real TELNET server connected.\n", _this->m_session->client_addr()); - _this->m_state = TELNET_CONN_STATE_CONNECTED; - - if (!_this->start_recv()) { - _this->m_session->close(TP_SESS_STAT_ERR_IO); - return; - } - - _this->m_session->do_next(_this, s_server_connected); -} - -//static -void TelnetConn::_uv_on_timer_connect_timeout_closed(uv_handle_t *handle) { -} +} + +TelnetConn::TelnetConn(TelnetSession *sess, bool is_server_side) : m_session(sess), m_is_server(is_server_side) { + if (is_server_side) { + m_name = "cli<->tp"; + m_state = TELNET_CONN_STATE_CONNECTED; + } + else { + m_name = "tp<->srv"; + m_state = TELNET_CONN_STATE_FREE; + } + + m_timer_running = false; + + uv_tcp_init(sess->get_loop(), &m_handle); + m_handle.data = this; +} + +TelnetConn::~TelnetConn() { +} + +bool TelnetConn::start_recv() { + int err = uv_read_start((uv_stream_t *)&m_handle, _on_alloc, _on_recv); + if (err != 0) { + EXLOGE("[telnet] [%s] can not start to read.\n", m_name); + m_session->close(TP_SESS_STAT_ERR_IO); + return false; + } + + return true; +} + +void TelnetConn::close() { + if (m_state == TELNET_CONN_STATE_FREE || m_state == TELNET_CONN_STATE_CLOSING) + return; + + if (m_timer_running) { + m_timer_running = false; + uv_timer_stop(&m_timer_connect_timeout); + + EXLOGW("[telnet] [%s] try to close while it connecting.\n", m_name); + m_state = TELNET_CONN_STATE_CLOSING; + uv_close(handle(), NULL); + + return; + } + + uv_read_stop((uv_stream_t*)&m_handle); + uv_close(handle() , _uv_on_closed); +} + +void TelnetConn::_uv_on_closed(uv_handle_t *handle) { + TelnetConn *_this = (TelnetConn *)handle->data; + _this->m_state = TELNET_CONN_STATE_FREE; + _this->m_session->on_conn_close(); +} + +void TelnetConn::_on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + TelnetConn *_this = (TelnetConn *) handle->data; + buf->base = (char *) calloc(1, suggested_size); + buf->len = suggested_size; +} + +void TelnetConn::_on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { + TelnetConn *_this = (TelnetConn *) handle->data; + + if (nread == 0) { + free(buf->base); + return; + } + else if (nread < 0) { + free(buf->base); + + if (nread == UV_EOF) + EXLOGD("[telnet] [%s] [recv] disconnected.\n", _this->m_name); + else if(nread == UV_ECONNRESET) + EXLOGD("[telnet] [%s] [recv] connection reset by peer.\n", _this->m_name); + else + EXLOGD("[telnet] [%s] [recv] %s.\n", _this->m_name, _uv_str_error(nread).c_str()); + + +// if (nread == -4077) +// EXLOGD("[telnet] [%s] [recv] disconnected.\n", _this->m_name); +// else if (nread == -104) +// EXLOGD("[telnet] [%s] [recv] connection reset by peer.\n", _this->m_name); +// else +// EXLOGD("[telnet] [%s] [recv] nread=%d.\n", _this->m_name, nread); + + _this->m_session->close(TP_SESS_STAT_END); + return; + } + else { +// #ifdef LOG_DATA +// if(!_this->m_session->is_relay()) +// EXLOG_BIN((ex_u8*)buf->base, nread, "[telnet] [%s] RECV %d.", _this->m_name, nread); +// #endif + } + + _this->m_buf_data.append((ex_u8 *) buf->base, nread); + free(buf->base); + + _this->m_session->do_next(_this); +} + +bool TelnetConn::send(MemBuffer &mbuf) { + return _raw_send(mbuf.data(), mbuf.size()); +} + +bool TelnetConn::send(const ex_u8 *data, size_t size) { + return _raw_send(data, size); +} + +bool TelnetConn::_raw_send(const ex_u8 *data, size_t size) { +// #ifdef LOG_DATA +// if (!m_session->is_relay()) +// EXLOG_BIN(data, size, "[telnet] [%s] SEND %dB.", m_name, size); +// #endif + + uv_write_t *w = (uv_write_t *) calloc(1, sizeof(uv_write_t)); + + ex_u8 *_data = (ex_u8 *) calloc(1, size); + if (NULL == _data) { + free(w); + EXLOGE("[telnet] alloc buffer %dB failed.\n", size); + return false; + } + memcpy(_data, data, size); + + uv_buf_t *_buf = (uv_buf_t *) calloc(1, sizeof(uv_buf_t)); + _buf->base = (char *) _data; + _buf->len = size; + + w->data = _buf; + if (0 == uv_write(w, (uv_stream_t *) &m_handle, _buf, 1, _on_send_done)) + return true; + else { + EXLOGE("[telnet] [%s] raw_send() failed.\n", m_name); + return false; + } +} + +void TelnetConn::_on_send_done(uv_write_t *req, int status) { + uv_buf_t *_buf = (uv_buf_t *) req->data; + free(_buf->base); + free(_buf); + free(req); + + if (status == UV_ECANCELED) { + EXLOGE("[telnet] _on_send_done() got UV_ECANCELED.\n"); + return; + } +} + +void TelnetConn::connect(const char *server_ip, ex_u16 server_port) { + m_server_ip = server_ip; + m_server_port = server_port; + + if (m_state == TELNET_CONN_STATE_CONNECTED) { + // 当前已经连接上了服务器了,断开重连 + EXLOGV("[telnet] [%s] [%s] try to disconnect. %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port); + m_state = TELNET_CONN_STATE_CLOSING; + uv_close((uv_handle_t *) &m_handle, _uv_on_reconnect); + return; + } + else { + EXLOGV("[telnet] [%s] [%s] try to connect to real TELNET server at %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port); + } + + struct sockaddr_in addr; + uv_ip4_addr(server_ip, server_port, &addr); + + uv_connect_t *conn_req = (uv_connect_t *) calloc(1, sizeof(uv_connect_t)); + conn_req->data = this; + + // 设置一个超时回调,如果超时发生时连接尚未完成,就报错 + uv_timer_init(m_session->get_loop(), &m_timer_connect_timeout); + m_timer_connect_timeout.data = this; + +#ifdef EX_DEBUG + uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 5000, 0); +#else + uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 10000, 0); +#endif + + m_timer_running = true; + + //m_is_connecting = true; + m_state = TELNET_CONN_STATE_CONNECTING; + int err = 0; + if ((err = uv_tcp_connect(conn_req, &m_handle, (const struct sockaddr *) &addr, _uv_on_connected)) != 0) { + free(conn_req); + EXLOGE("[telnet] [%s] can not connect to server: %s\n", m_name, uv_strerror(err)); + + m_timer_running = false; + uv_timer_stop(&m_timer_connect_timeout); + uv_close((uv_handle_t*)&m_timer_connect_timeout, _uv_on_timer_connect_timeout_closed); + + m_state = TELNET_CONN_STATE_FREE; + m_session->close(TP_SESS_STAT_ERR_CONNECT); + } +} + +void TelnetConn::_uv_on_connect_timeout(uv_timer_t *timer) +{ + TelnetConn *_this = (TelnetConn *)timer->data; + + if (_this->m_timer_running) { + _this->m_timer_running = false; + uv_timer_stop(&_this->m_timer_connect_timeout); + uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed); + } + + // 如果在连接成功之前就超时了,则关闭连接 + EXLOGE("[telnet] [%s] timeout when connect to real TELNET server, cancel connection.\n", _this->m_name); + _this->m_state = TELNET_CONN_STATE_CLOSING; + uv_close(_this->handle(), _uv_on_closed); +} + +void TelnetConn::_uv_on_reconnect(uv_handle_t *handle) { + TelnetConn *_this = (TelnetConn *)handle->data; + _this->m_state = TELNET_CONN_STATE_FREE; + + uv_tcp_init(_this->m_session->get_loop(), &_this->m_handle); + _this->m_handle.data = _this; + + _this->connect(_this->m_server_ip.c_str(), _this->m_server_port); +} + +void TelnetConn::_uv_on_connected(uv_connect_t *req, int status) { + TelnetConn *_this = (TelnetConn *)req->data; + free(req); + + if (_this->m_timer_running) { + _this->m_timer_running = false; + uv_timer_stop(&_this->m_timer_connect_timeout); + uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed); + } + + if (status != 0) { + EXLOGE("[telnet] [%s] cannot connect to real TELNET server. %s\n", _this->m_name, uv_strerror(status)); + _this->m_state = TELNET_CONN_STATE_FREE; + _this->m_session->close(TP_SESS_STAT_ERR_CONNECT); + return; + } + + EXLOGW("[telnet] [%s] real TELNET server connected.\n", _this->m_session->client_addr()); + _this->m_state = TELNET_CONN_STATE_CONNECTED; + + if (!_this->start_recv()) { + _this->m_session->close(TP_SESS_STAT_ERR_IO); + return; + } + + _this->m_session->do_next(_this, s_server_connected); +} + +//static +void TelnetConn::_uv_on_timer_connect_timeout_closed(uv_handle_t *handle) { +} diff --git a/server/www/teleport/static/js/tp-assist.js b/server/www/teleport/static/js/tp-assist.js index eb635a2..4c072d4 100644 --- a/server/www/teleport/static/js/tp-assist.js +++ b/server/www/teleport/static/js/tp-assist.js @@ -108,7 +108,8 @@ $assist.do_teleport = function (args, func_success, func_error) { // rdp_console: args.rdp_console, session_id: session_id, protocol_type: parseInt(args.protocol_type), - protocol_sub_type: parseInt(args.protocol_sub_type) + protocol_sub_type: parseInt(args.protocol_sub_type), + protocol_flag: parseInt(ret.data.protocol_flag) }; if(args.protocol_type === TP_PROTOCOL_TYPE_RDP) { diff --git a/server/www/teleport/webroot/app/controller/ops.py b/server/www/teleport/webroot/app/controller/ops.py index e76acf3..6677929 100644 --- a/server/www/teleport/webroot/app/controller/ops.py +++ b/server/www/teleport/webroot/app/controller/ops.py @@ -131,14 +131,29 @@ class DoGetSessionIDHandler(TPBaseJsonHandler): if err != TPE_OK: return self.write_json(err) + policy_id = ops_auth['p_id'] acc_id = ops_auth['a_id'] host_id = ops_auth['h_id'] + err, policy_info = ops.get_by_id(policy_id) + if err != TPE_OK: + return self.write_json(err) + err, acc_info = account.get_account_info(acc_id) if err != TPE_OK: return self.write_json(err) # log.v(acc_info) + if acc_info['protocol_type'] == TP_PROTOCOL_TYPE_RDP: + acc_info['protocol_flag'] = policy_info['flag_rdp'] + elif acc_info['protocol_type'] == TP_PROTOCOL_TYPE_SSH: + acc_info['protocol_flag'] = policy_info['flag_ssh'] + elif acc_info['protocol_type'] == TP_PROTOCOL_TYPE_TELNET: + acc_info['protocol_flag'] = policy_info['flag_telnet'] + else: + acc_info['protocol_flag'] = 0 + acc_info['record_flag'] = policy_info['flag_record'] + elif _mode == 2: # 鐩存帴杩炴帴锛堟棤闇鎺堟潈锛夛紝蹇呴』鍏锋湁杩愮淮鎺堟潈绠$悊鐨勬潈闄愭柟鍙繘琛 ret = self.check_privilege(TP_PRIVILEGE_OPS_AUZ) @@ -152,6 +167,9 @@ class DoGetSessionIDHandler(TPBaseJsonHandler): if err != TPE_OK: return self.write_json(err) + acc_info['protocol_flag'] = TP_FLAG_ALL + acc_info['record_flag'] = TP_FLAG_ALL + elif _mode == 0: # 娴嬭瘯杩炴帴锛屽繀椤诲叿鏈変富鏈轰俊鎭垱寤恒佺紪杈戠殑鏉冮檺鏂瑰彲杩涜 ret = self.check_privilege(TP_PRIVILEGE_ASSET_CREATE) @@ -180,6 +198,8 @@ class DoGetSessionIDHandler(TPBaseJsonHandler): acc_info['auth_type'] = auth_type acc_info['protocol_type'] = _protocol_type acc_info['protocol_port'] = protocol_port + acc_info['protocol_flag'] = TP_FLAG_ALL + acc_info['record_flag'] = TP_FLAG_ALL acc_info['username'] = username acc_info['password'] = password @@ -226,7 +246,8 @@ class DoGetSessionIDHandler(TPBaseJsonHandler): conn_info['acc_username'] = acc_info['username'] conn_info['username_prompt'] = acc_info['username_prompt'] conn_info['password_prompt'] = acc_info['password_prompt'] - conn_info['protocol_flag'] = 1 + conn_info['protocol_flag'] = acc_info['protocol_flag'] + conn_info['record_flag'] = acc_info['record_flag'] conn_info['protocol_type'] = acc_info['protocol_type'] conn_info['protocol_sub_type'] = _protocol_sub_type @@ -261,6 +282,7 @@ class DoGetSessionIDHandler(TPBaseJsonHandler): data = dict() data['session_id'] = ret_data['sid'] data['host_ip'] = host_info['ip'] + data['protocol_flag'] = acc_info['protocol_flag'] if conn_info['protocol_type'] == TP_PROTOCOL_TYPE_RDP: data['teleport_port'] = tp_cfg().core.rdp.port diff --git a/server/www/teleport/webroot/app/controller/rpc.py b/server/www/teleport/webroot/app/controller/rpc.py index 9d0133d..0441421 100644 --- a/server/www/teleport/webroot/app/controller/rpc.py +++ b/server/www/teleport/webroot/app/controller/rpc.py @@ -69,6 +69,7 @@ class RpcHandler(TPBaseJsonHandler): if x is None: return self.write_json(TPE_NOT_EXISTS) else: + print(x) return self.write_json(TPE_OK, data=x) def _session_begin(self, param): diff --git a/server/www/teleport/webroot/app/model/ops.py b/server/www/teleport/webroot/app/model/ops.py index fe6a815..961d477 100644 --- a/server/www/teleport/webroot/app/model/ops.py +++ b/server/www/teleport/webroot/app/model/ops.py @@ -24,21 +24,6 @@ def get_by_id(pid): return TPE_OK, s.recorder[0] -# def get_by_username(username): -# s = SQL(get_db()) -# s.select_from('user', ['id', 'type', 'auth_type', 'username', 'surname', 'password', 'oath_secret', 'role_id', 'state', 'email', 'last_login'], alt_name='u') -# s.left_join('role', ['name', 'privilege'], join_on='r.id=u.id', alt_name='r', out_map={'name': 'role'}) -# s.where('u.username="{}"'.format(username)) -# err = s.query() -# if err != TPE_OK: -# return err -# -# if len(s.recorder) == 0: -# return TPE_NOT_EXISTS, {} -# -# return TPE_OK, s.recorder[0] -# - def get_policies(sql_filter, sql_order, sql_limit): dbtp = get_db().table_prefix s = SQL(get_db()) @@ -484,7 +469,7 @@ def rank_reorder(handler, pid, new_rank, start_rank, end_rank, direct): def get_auth(auth_id): db = get_db() s = SQL(db) - err = s.select_from('ops_map', ['id', 'h_id', 'u_id', 'a_id']).where('ops_map.uni_id="{}"'.format(auth_id)).query() + err = s.select_from('ops_map', ['id', 'p_id', 'h_id', 'u_id', 'a_id']).where('ops_map.uni_id="{}"'.format(auth_id)).query() if err != TPE_OK: return None, err if len(s.recorder) == 0: