teleport/client/tp_assist_win/ts_http_rpc.cpp

1186 lines
29 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "stdafx.h"
#pragma warning(disable:4091)
#include <commdlg.h>
#include <ShlObj.h>
#include <WinCrypt.h>
#pragma comment(lib, "Crypt32.lib")
#include <teleport_const.h>
#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"<html lang=\"zh_CN\"><head><meta charset=\"utf-8\"/><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><title>Teleport助手</title>\n<style type=\"text/css\">\n.box{padding:20px;margin:40px;border:1px solid #78b17c;background-color:#e4ffe5;}\n</style>\n</head><body><div class=\"box\">Teleport助手工作正常</div></body></html>";
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"<html lang=\"zh_CN\"><html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>404 Not Found</h1></center><hr><center><p>Teleport Assistor configuration page not found.</p></center></body></html>";
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;
}