#include "stdafx.h" #pragma warning(disable:4091) #include #include //#include // //#pragma comment(lib, "Crypt32.lib") #include //#ifndef MAX_PATH //# define MAX_PATH 1024 //#endif // #include "../AppDelegate-C-Interface.h" #include "ts_ws_client.h" #include "ts_ver.h" #include "ts_env.h" #include "ts_cfg.h" #include "ts_utils.h" //#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\ //bitmapcachepersistenable:i:1\n\ //bitmapcachesize:i:32000\n\ //compression: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\ //disableclipboardredirection:i:0\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\ //"; // https://www.donkz.nl/overview-rdp-file-settings/ // // authentication level:i:2\n // // // negotiate security layer:i:1\n // 0 = negotiation is not enabled and the session is started by using Secure Sockets Layer (SSL). // 1 = negotiation is enabled and the session is started by using x.224 encryption. //redirectdirectx:i:0\n\ //prompt for credentials on client:i:0\n\ //#endif TsWsClient g_ws_client; void* g_app = NULL; // //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", nullptr, nullptr, nullptr, 0, &DataOut)) // return false; // // char szRet[5] = { 0 }; // for (DWORD i = 0; i < DataOut.cbData; ++i) { // sprintf_s(szRet, 5, "%02X", DataOut.pbData[i]); // ret += szRet; // } // // LocalFree(DataOut.pbData); // return true; //} // static void TsWsClient::init_app(void* app) { g_app = app; } void TsWsClient::stop_all_client() { g_ws_client.stop(); } // ============================================================================ // static void TsWsClient::url_scheme_handler(const std::string& url) { // from command line: // teleport://register?param={"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"} // from system-url-protocol handler. why Windows add extra '/' for me??? // teleport://register/?param={"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"} std::string protocol; std::string method; std::string param; std::string::size_type pos_protocol = url.find("://"); if (pos_protocol == std::string::npos) { EXLOGE("[url-schema] invalid url: %s\n", url.c_str()); return; } std::string::size_type pos_method = url.find('?'); if (pos_method == std::string::npos) { EXLOGE("[url-schema] invalid url: %s\n", url.c_str()); return; } protocol.assign(url, 0, pos_protocol); if (protocol != "teleport") { EXLOGE("[url-schema] invalid protocol: %s\n", protocol.c_str()); return; } method.assign(url, pos_protocol + 3, pos_method - pos_protocol - 3); if (method.empty()) { EXLOGE("[ws] no method, what should I do now?\n"); return; } if (method[method.length() - 1] == '/') method.erase(method.length() - 1, 1); param.assign(url, pos_method + 7); // ?param= if (param.empty()) { EXLOGE("[url-schema] invalid protocol: %s\n", protocol.c_str()); return; } // decode param with url-decode. size_t len = param.length() * 2; ex_chars sztmp; sztmp.resize(len); memset(&sztmp[0], 0, len); if (-1 == ex_url_decode(param.c_str(), (int)param.length(), &sztmp[0], (int)len, 0)) { EXLOGE("[url-schema] url-decode param failed: %s\n", param.c_str()); return; } param = &sztmp[0]; EXLOGV("[url-schema] method=%s, json_param=%s\n", method.c_str(), param.c_str()); Json::CharReaderBuilder jcrb; std::unique_ptr const jreader(jcrb.newCharReader()); const char* str_json_begin = param.c_str(); Json::Value js_root; ex_astr err; if (!jreader->parse(str_json_begin, str_json_begin + param.length(), &js_root, &err)) { EXLOGE("[url-schema] param not in json format: %s\n", param.c_str()); return; } if (!js_root.isObject()) { EXLOGE("[url-schema] invalid param, need json object: %s\n", param.c_str()); return; } if (method == "register") { _process_register(param, js_root); } else if (method == "run") { _process_run(param, js_root); } else if (method == "replay_rdp") { _process_replay_rdp(param, js_root); } else { EXLOGE("[ws] unknown method: %s\n", method.c_str()); return; } } // static void TsWsClient::_process_register(const std::string& param, Json::Value& js_root) { // {"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"} // check param if (!js_root["ws_url"].isString() || !js_root["assist_id"].isNumeric() || !js_root["session_id"].isString()) { EXLOGE("[url-schema] invalid param: %s\n", param.c_str()); return; } std::string ws_url = js_root["ws_url"].asCString(); uint32_t assist_id = js_root["assist_id"].asUInt(); std::string session_id = js_root["session_id"].asCString(); std::string protocol; protocol.assign(ws_url, 0, 5); if (protocol == "ws://") { g_ws_client._register(false, ws_url, assist_id, session_id); } else if (protocol == "wss:/") { g_ws_client._register(true, ws_url, assist_id, session_id); } else { EXLOGE("[url-schema] invalid ws_url: %s\n", ws_url.c_str()); return; } } void TsWsClient::_process_run(const std::string& param, Json::Value& js_root) { // wrapper for _rpc_func_run_client(). Json::Value js_param; js_param["method"] = "run"; js_param["param"] = js_root; AssistMessage msg_req; std::string buf; _rpc_func_run_client(buf, msg_req, js_param); } void TsWsClient::_process_replay_rdp(const std::string& param, Json::Value& js_root) { // wrapper for _rpc_func_replay_rdp(). Json::Value js_param; js_param["method"] = "replay_rdp"; js_param["param"] = js_root; AssistMessage msg_req; std::string buf; _rpc_func_replay_rdp(buf, msg_req, js_param); } // ============================================================================ TsWsClient::TsWsClient() : ExThreadBase("ws-client-thread"), m_nc(NULL), m_assist_id(0) { mg_mgr_init(&m_mg_mgr, NULL); } TsWsClient::~TsWsClient() { mg_mgr_free(&m_mg_mgr); } void TsWsClient::_thread_loop(void) { while (!m_need_stop) { mg_mgr_poll(&m_mg_mgr, 500); } EXLOGV("[ws] main loop end.\n"); } void TsWsClient::_register(bool is_ssl, const std::string& ws_url, uint32_t assist_id, const std::string& session_id) { if (m_assist_id == 0) m_assist_id = assist_id; ex_wstr w_ver(TP_ASSIST_VER); ex_astr a_ver; ex_wstr2astr(w_ver, a_ver); // char msg[256] = { 0 }; ex_strformat( msg, 256, "{\"type\":0,\"method\":\"register\",\"param\":{\"client\":\"assist\",\"sid\":\"%s\",\"request_assist_id\":%u,\"assist_id\":%u,\"assist_ver\":\"%s\"}}", session_id.c_str(), assist_id, m_assist_id, a_ver.c_str()); if (!m_is_running) { // not start yet. std::string url = ws_url; url += msg; EXLOGD("mg_connect_ws: %s\n", url.c_str()); if (is_ssl) { struct mg_connect_opts opts; memset(&opts, 0, sizeof(opts)); opts.ssl_ca_cert = "*"; opts.ssl_server_name = "*"; m_nc = mg_connect_ws_opt(&m_mg_mgr, _mg_event_handler, opts, url.c_str(), "wss", NULL); } else { m_nc = mg_connect_ws(&m_mg_mgr, _mg_event_handler, url.c_str(), NULL, NULL); } // m_nc = mg_connect_ws(&m_mg_mgr, _mg_event_handler, url.c_str(), NULL, NULL); if (!m_nc) { EXLOGE("[ws] TsWsClient::init failed: %s\n", url.c_str()); return; } m_nc->user_data = this; start(); return; } EXLOGV("[ws] send: %s\n", msg); mg_send_websocket_frame(m_nc, WEBSOCKET_OP_TEXT, msg, strlen(msg)); } // static void TsWsClient::_mg_event_handler(struct mg_connection* nc, int ev, void* ev_data) { auto* _this = (TsWsClient*)nc->user_data; if (NULL == _this) { EXLOGE("[ERROR] invalid request.\n"); return; } switch (ev) { case MG_EV_CONNECT: { int status = *((int*)ev_data); if (status != 0) { EXLOGE("[ERROR] -- connect to ws server failed: %d\n", status); } break; } case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { auto* hm = (struct http_message*)ev_data; if (hm->resp_code == 101) { EXLOGV("-- ws server connected\n"); } else { EXLOGE("[ERROR] -- connect to ws server failed, HTTP code: %d\n", hm->resp_code); } break; } case MG_EV_WEBSOCKET_FRAME: { // on_message(). auto* wm = (struct websocket_message*)ev_data; // EXLOGV("%d: %s\n", wm->size, wm->data); std::string message; message.assign((const char*)wm->data, wm->size); std::string buf; _this->_on_message(message, buf); if (!buf.empty()) { mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf.c_str(), buf.length()); } break; } case MG_EV_CLOSE: { EXLOGV("-- ws server disconnected\n"); _this->m_need_stop = true; break; } } } void TsWsClient::_create_response(ex_astr& buf, const AssistMessage& msg_ret, int err_code) { Json::Value js_data(Json::objectValue); _create_response(buf, msg_ret, err_code, L"", js_data); } void TsWsClient::_create_response(ex_astr& buf, const AssistMessage& msg_ret, int err_code, const ex_wstr& message) { Json::Value js_data(Json::objectValue); _create_response(buf, msg_ret, err_code, message, js_data); } void TsWsClient::_create_response(ex_astr& buf, const AssistMessage& msg_ret, int err_code, const ex_wstr& message, Json::Value& data) { ex_astr _message; // ex_wstr2astr(message, _message, EX_CODEPAGE_UTF8); ex_wstr2astr(message, _message); Json::Value js_ret; js_ret["type"] = MESSAGE_TYPE_RESPONSE; js_ret["command_id"] = msg_ret.command_id; js_ret["method"] = msg_ret.method; js_ret["code"] = err_code; js_ret["message"] = _message; js_ret["data"] = data; Json::StreamWriterBuilder jwb; // jwb["emitUTF8"] = true; jwb["indentation"] = ""; // 压缩格式,没有换行和不必要的空白字符 std::unique_ptr js_writer(jwb.newStreamWriter()); ex_aoss os; js_writer->write(js_ret, &os); buf = os.str(); } void TsWsClient::_on_message(const std::string& message, std::string& buf) { // { // "type":0, // "method":"run", // "param":{ // "teleport_ip":"127.0.0.1","teleport_port":52189,"remote_host_ip":"39.97.125.170", // "remote_host_name":"tp4a.com","session_id":"9DE744","protocol_type":2, // "protocol_sub_type":200,"protocol_flag":4294967295 // } // } EXLOGW("on-message:\n", message.c_str()); AssistMessage msg_req; Json::CharReaderBuilder jrb; std::unique_ptr const js_reader(jrb.newCharReader()); const char* str_json_begin = message.c_str(); Json::Value js_root; ex_astr err; if (!js_reader->parse(str_json_begin, str_json_begin + message.length(), &js_root, &err)) { _create_response(buf, msg_req, TPE_JSON_FORMAT); return; } if (!js_root.isObject()) { _create_response(buf, msg_req, TPE_PARAM); return; } if (js_root["type"].isNull() || !js_root["type"].isInt()) { _create_response(buf, msg_req, TPE_PARAM); return; } int cmd_type = js_root["type"].asInt(); if (!(cmd_type == MESSAGE_TYPE_REQUEST || cmd_type == MESSAGE_TYPE_RESPONSE)) { _create_response(buf, msg_req, TPE_PARAM); return; } // 收到的信息已经是“返回值”了,说明已经是一条命令的结束了,不用继续处理 // todo: 可能需要记录日志,或者展示结果。 //if (cmd_type == MESSAGE_TYPE_RESPONSE) //{ // char msg[129] = { 0 }; // _snprintf_s(msg, 128, "%d %d", cmd_type, MESSAGE_TYPE_RESPONSE); // MessageBoxA(NULL, msg, "INFO", MB_OK); // return; //} if (js_root["method"].isNull() || !js_root["method"].isString() || js_root["command_id"].isNull() || !js_root["command_id"].isInt()) { _create_response(buf, msg_req, TPE_PARAM); return; } msg_req.command_id = js_root["command_id"].asInt(); msg_req.method = js_root["method"].asString(); if (msg_req.command_id == 0 || msg_req.method.empty()) { _create_response(buf, msg_req, TPE_PARAM); return; } if (msg_req.method == "run") { _rpc_func_run_client(buf, msg_req, js_root); } else if (msg_req.method == "replay_rdp") { _rpc_func_replay_rdp(buf, msg_req, js_root); } else if (msg_req.method == "get_config") { _rpc_func_get_config(buf, msg_req, js_root); } else if (msg_req.method == "set_config") { _rpc_func_set_config(buf, msg_req, js_root); } else if (msg_req.method == "select_file") { _rpc_func_select_file(buf, msg_req, js_root); } else { EXLOGE("[ws] got unknown command: %s\n", msg_req.method.c_str()); _create_response(buf, msg_req, TPE_UNKNOWN_CMD); } } void TsWsClient::_rpc_func_get_config(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root) { Json::Value& ret = g_cfg.get_root(); ret["os_type"] = "windows"; _create_response(buf, msg_req, TPE_OK, L"", ret); } void TsWsClient::_rpc_func_set_config(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root) { if (js_root["param"].isNull() || !js_root["param"].isObject()) { _create_response(buf, msg_req, TPE_PARAM); return; } Json::Value& js_param = js_root["param"]; Json::StreamWriterBuilder jwb; std::unique_ptr js_writer(jwb.newStreamWriter()); ex_aoss os; js_writer->write(js_param, &os); if (!g_cfg.save(os.str())) _create_response(buf, msg_req, TPE_FAILED); else _create_response(buf, msg_req, TPE_OK); } void TsWsClient::_rpc_func_select_file(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root) { // _create_response(buf, msg_req, TPE_FAILED, L"尚不支持在macOS平台选择应用,请手动填写应用程序路径!"); // _create_response(buf, msg_req, TPE_FAILED, L"尚不支持选择应用,请手动填写应用程序路径!"); if (js_root["param"].isNull() || !js_root["param"].isObject() || js_root["param"]["app_type"].isNull()) { _create_response(buf, msg_req, TPE_PARAM); return; } // Json::Value& js_param = js_root["param"]; HWND hParent = GetForegroundWindow(); if (NULL == hParent) hParent = NULL; BOOL ret = FALSE; wchar_t wszReturnPath[MAX_PATH] = _T(""); 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 = NULL;// L"Select application execute file"; ofn.hwndOwner = hParent; ofn.lpstrFilter = L"Execute file (*.exe)\0*.exe\0"; ofn.lpstrFile = wszReturnPath; ofn.nMaxFile = MAX_PATH; ofn.lpstrInitialDir = wsDefaultPath.c_str(); ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST; ofn.Flags |= OFN_FILEMUSTEXIST; ret = GetOpenFileNameW(&ofn); if (!ret) { _create_response(buf, msg_req, TPE_FAILED, L"用户取消了选择操作!"); return; } ex_astr utf8_path; ex_wstr2astr(wszReturnPath, utf8_path, EX_CODEPAGE_UTF8); Json::Value js_ret; js_ret["app_type"] = js_root["param"]["app_type"]; js_ret["app_path"] = utf8_path; _create_response(buf, msg_req, TPE_OK, L"", js_ret); } void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root) { // { // "method":"replay_rdp", // "param":{ // "rid":1234, // "web":"http://127.0.0.1:7190", // "sid":"tp_1622707094_1c8e4fd4006c6ad5" // } // } if (js_root["param"].isNull() || !js_root["param"].isObject()) { _create_response(buf, msg_req, TPE_PARAM); return; } Json::Value& js_param = js_root["param"]; // check param if (!js_param["rid"].isNumeric() || !js_param["web"].isString() || !js_param["sid"].isString() ) { _create_response(buf, msg_req, TPE_PARAM); return; } ex_astrs s_argv; ex_wstr w_exec_file = g_env.m_exec_path; ex_path_join(w_exec_file, false, L"tp-player.exe", nullptr); int rid = js_param["rid"].asInt(); ex_astr a_url_base = js_param["web"].asCString(); ex_astr a_sid = js_param["sid"].asCString(); char cmd_args[1024] = { 0 }; ex_strformat(cmd_args, 1023, "%s/%s/%d", a_url_base.c_str(), a_sid.c_str(), rid); ex_wstr w_cmd_args; ex_astr2wstr(cmd_args, w_cmd_args); // char total_cmd[1024] = { 0 }; // ex_strformat(total_cmd, 1023, "%s %s", exec_file.c_str(), cmd_args); wchar_t cmd[1024] = { 0 }; ex_wcsformat(cmd, 1023, L"%s %s", w_exec_file.c_str(), w_cmd_args.c_str()); ex_astr total_cmd; ex_wstr2astr(cmd, total_cmd); Json::Value js_ret; ex_astr utf8_path; //ex_wstr2astr(total_cmd, utf8_path, EX_CODEPAGE_UTF8); js_ret["cmdline"] = total_cmd; // EXLOGD(utf8_path.c_str()); STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { EXLOGE(_T("CreateProcess() failed. Error=0x%08X.\n %s\n"), GetLastError(), cmd); _create_response(buf, msg_req, TPE_START_CLIENT); return; } _create_response(buf, msg_req, TPE_OK, L"", js_ret); } void TsWsClient::_rpc_func_run_client(ex_astr& buf, AssistMessage& msg_req, Json::Value& js_root) { // { // "method":"run", // "param":{ // "teleport_ip":"127.0.0.1","teleport_port":52189,"remote_host_ip":"39.97.125.170", // "remote_host_name":"tp4a.com","session_id":"9DE744","protocol_type":2, // "protocol_sub_type":200,"protocol_flag":4294967295 // } // } // 判断参数是否正确 if (js_root["param"].isNull() || !js_root["param"].isObject()) { _create_response(buf, msg_req, TPE_PARAM); return; } Json::Value& js_param = js_root["param"]; if (!js_param["teleport_ip"].isString() || !js_param["teleport_port"].isNumeric() || !js_param["remote_host_ip"].isString() || !js_param["session_id"].isString() || !js_param["protocol_type"].isNumeric() || !js_param["protocol_sub_type"].isNumeric() || !js_param["protocol_flag"].isNumeric() ) { _create_response(buf, msg_req, TPE_PARAM); return; } const char* interactive_mode = "no"; bool is_interactive_mode = false; if (!js_param["is_interactive"].isNull()) { if (!js_param["is_interactive"].isBool()) { _create_response(buf, msg_req, TPE_PARAM); return; } if (js_param["is_interactive"].asBool()) { interactive_mode = "yes"; is_interactive_mode = true; } } int pro_type = js_param["protocol_type"].asUInt(); int pro_sub = js_param["protocol_sub_type"].asInt(); ex_u32 protocol_flag = js_param["protocol_flag"].asUInt(); ex_astr teleport_ip = js_param["teleport_ip"].asCString(); int teleport_port = js_param["teleport_port"].asUInt(); ex_astr real_host_ip = js_param["remote_host_ip"].asCString(); ex_astr remote_host_name = js_param["remote_host_name"].asCString(); ex_astr sid = js_param["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); ex_wstr w_remote_host_name; ex_astr2wstr(remote_host_name, w_remote_host_name, EX_CODEPAGE_UTF8); 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) == TP_FLAG_RDP_CLIPBOARD); bool flag_disk = ((protocol_flag & TP_FLAG_RDP_DISK) == TP_FLAG_RDP_DISK); bool flag_console = ((protocol_flag & TP_FLAG_RDP_CONSOLE) == TP_FLAG_RDP_CONSOLE); int rdp_w = 800; int rdp_h = 640; bool rdp_console = false; if (!js_param["rdp_width"].isNull()) { if (js_param["rdp_width"].isNumeric()) { rdp_w = js_param["rdp_width"].asUInt(); } else { _create_response(buf, msg_req, TPE_PARAM); return; } } if (!js_param["rdp_height"].isNull()) { if (js_param["rdp_height"].isNumeric()) { rdp_h = js_param["rdp_height"].asUInt(); } else { _create_response(buf, msg_req, TPE_PARAM); return; } } if (!js_param["rdp_console"].isNull()) { if (js_param["rdp_console"].isBool()) { rdp_console = js_param["rdp_console"].asBool(); } else { _create_response(buf, msg_req, 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(), nullptr, 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.application + _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)) if (!calc_psw51b("******", psw51b)) { EXLOGE("calc password failed.\n"); _create_response(buf, msg_req, TPE_PARAM); return; } //real_sid = "01" + real_sid; char sz_rdp_file_content[4096] = { 0 }; sprintf_s(sz_rdp_file_content, 4096, rdp_content.c_str() , (flag_console && rdp_console) ? 1 : 0 , display, width, higth , cx, cy, cx + width + 100, cy + higth + 100 , teleport_ip.c_str(), teleport_port , flag_clipboard ? 1 : 0 , flag_disk ? "*" : "" //, real_sid.c_str() , 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_response(buf, msg_req, TPE_FAILED); return; } ex_astr temp_host_ip = real_host_ip; ex_replace_all(temp_host_ip, ".", "-"); sprintf_s(sz_file_name, MAX_PATH, ("%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_response(buf, msg_req, 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 += 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_response(buf, msg_req, 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.application + _T("\" "); w_exe_path += g_cfg.ssh.cmdline; } else { w_exe_path = _T("\""); w_exe_path += g_cfg.sftp.application + _T("\" "); w_exe_path += g_cfg.sftp.cmdline; } } else if (pro_type == TP_PROTOCOL_TYPE_TELNET) { //============================================== // TELNET //============================================== w_exe_path = _T("\""); w_exe_path += g_cfg.telnet.application + _T("\" "); w_exe_path += g_cfg.telnet.cmdline; } //---- split s_arg and push to s_argv --- ex_wstr::size_type p1 = 0; ex_wstr::size_type p2 = 0; int i = 0; // 防止死循环,替换10个应该够了 for (i = 0; i < 10; ++i) { p1 = w_exe_path.find(L"{password:"); if (p1 != ex_wstr::npos) { p2 = w_exe_path.find(L'}', p1 + 10); if (p2 == ex_wstr::npos) { _create_response(buf, msg_req, TPE_PARAM); return; } if (is_interactive_mode) { // 如果需要用户自己输入密码,则客户端命令行就不能带密码字段,需要抹去这个参数 w_exe_path.erase(p1, p2 - p1 + 1); } else { w_exe_path.erase(p2, 1); w_exe_path.erase(p1, 10); } } else { break; } } for (i = 0; i < 10; ++i) { p1 = w_exe_path.find(L"{interactive:"); if (p1 != ex_wstr::npos) { p2 = w_exe_path.find('}', p1 + 13); if (p2 == ex_wstr::npos) { _create_response(buf, msg_req, TPE_PARAM); return; } if (!is_interactive_mode) { // 如果无需用户自己输入密码,则需要抹去这个参数 w_exe_path.erase(p1, p2 - p1 + 1); } else { w_exe_path.erase(p2, 1); w_exe_path.erase(p1, 13); } } else { break; } } ex_replace_all(w_exe_path, _T("{host_ip}"), w_teleport_ip.c_str()); ex_replace_all(w_exe_path, _T("{host_port}"), w_port); ex_replace_all(w_exe_path, _T("{user_name}"), w_sid.c_str()); ex_replace_all(w_exe_path, _T("{host_name}"), w_remote_host_name.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 js_data; ex_astr utf8_path; ex_wstr2astr(w_exe_path, utf8_path, EX_CODEPAGE_UTF8); js_data["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()); _create_response(buf, msg_req, TPE_START_CLIENT); return; } _create_response(buf, msg_req, TPE_OK, L"", js_data); }