mirror of https://github.com/tp4a/teleport
改进:
1. SSH按通道进行记录录像,避免一个会话多个通道时录像数据混杂导致播放混乱; 2. 无论是SSH-Shell还是SSH-SFTP,均能够根据实际建立连接并进行操作正确记录其类型,方便界面展示; 3. 核心模块能够处理连接信息的引用计数,因此SFTP上编辑、保存文件可以正常工作了; 4. 能够正确处理绝大部分断开连接后状态还在“使用中”的问题,但SecureCRT通过“连接SFTP标签页”后,有时仍然存在此问题。pull/105/head
parent
83b9ba01bc
commit
907cb1b9e1
|
@ -40,7 +40,7 @@
|
||||||
//=======================================================
|
//=======================================================
|
||||||
// 远程连接会话状态
|
// 远程连接会话状态
|
||||||
//=======================================================
|
//=======================================================
|
||||||
#define TP_SESS_STAT_RUNNING 0 // 会话开始了,尚未结束
|
#define TP_SESS_STAT_RUNNING 0 // 会话开始了,正在连接
|
||||||
#define TP_SESS_STAT_END 9999 // 会话成功结束
|
#define TP_SESS_STAT_END 9999 // 会话成功结束
|
||||||
#define TP_SESS_STAT_ERR_AUTH_DENIED 1 // 会话结束,因为认证失败
|
#define TP_SESS_STAT_ERR_AUTH_DENIED 1 // 会话结束,因为认证失败
|
||||||
#define TP_SESS_STAT_ERR_CONNECT 2 // 会话结束,因为无法连接到远程主机
|
#define TP_SESS_STAT_ERR_CONNECT 2 // 会话结束,因为无法连接到远程主机
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
//#include <sys/types.h>
|
|
||||||
//#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "base_record.h"
|
#include "base_record.h"
|
||||||
|
|
||||||
TppRecBase::TppRecBase()
|
TppRecBase::TppRecBase()
|
||||||
|
|
|
@ -85,8 +85,6 @@ public:
|
||||||
bool begin(const wchar_t* base_path, const wchar_t* base_fname, int record_id, const TPP_CONNECT_INFO* info);
|
bool begin(const wchar_t* base_path, const wchar_t* base_fname, int record_id, const TPP_CONNECT_INFO* info);
|
||||||
bool end();
|
bool end();
|
||||||
|
|
||||||
//virtual void record(ex_u8 type, const ex_u8* data, size_t size) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool _on_begin(const TPP_CONNECT_INFO* info) = 0;
|
virtual bool _on_begin(const TPP_CONNECT_INFO* info) = 0;
|
||||||
virtual bool _on_end() = 0;
|
virtual bool _on_end() = 0;
|
||||||
|
|
|
@ -44,7 +44,7 @@ typedef struct TPP_CONNECT_INFO
|
||||||
typedef TPP_CONNECT_INFO* (*TPP_GET_CONNNECT_INFO_FUNC)(const char* sid);
|
typedef TPP_CONNECT_INFO* (*TPP_GET_CONNNECT_INFO_FUNC)(const char* sid);
|
||||||
typedef void(*TPP_FREE_CONNECT_INFO_FUNC)(TPP_CONNECT_INFO* info);
|
typedef void(*TPP_FREE_CONNECT_INFO_FUNC)(TPP_CONNECT_INFO* info);
|
||||||
typedef bool(*TPP_SESSION_BEGIN_FUNC)(const TPP_CONNECT_INFO* info, int* db_id);
|
typedef bool(*TPP_SESSION_BEGIN_FUNC)(const TPP_CONNECT_INFO* info, int* db_id);
|
||||||
typedef bool(*TPP_SESSION_UPDATE_FUNC)(int db_id, int state);
|
typedef bool(*TPP_SESSION_UPDATE_FUNC)(int db_id, int protocol_sub_type, int state);
|
||||||
typedef bool(*TPP_SESSION_END_FUNC)(const char* sid, int db_id, int ret);
|
typedef bool(*TPP_SESSION_END_FUNC)(const char* sid, int db_id, int ret);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -359,9 +359,9 @@ void TsHttpRpc::_rpc_func_request_session(const Json::Value& json_param, ex_astr
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->ref_count = 0;
|
// info->ref_count = 0;
|
||||||
info->ticket_start = ex_get_tick_count();
|
// info->ticket_start = ex_get_tick_count();
|
||||||
|
//
|
||||||
// 生成一个session-id(内部会避免重复)
|
// 生成一个session-id(内部会避免重复)
|
||||||
ex_astr sid;
|
ex_astr sid;
|
||||||
if (!g_session_mgr.request_session(sid, info)) {
|
if (!g_session_mgr.request_session(sid, info)) {
|
||||||
|
|
|
@ -54,6 +54,8 @@ void tpp_free_connect_info(TPP_CONNECT_INFO* info)
|
||||||
if (NULL == info)
|
if (NULL == info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
g_session_mgr.free_connect_info(info->sid);
|
||||||
|
|
||||||
free(info->sid);
|
free(info->sid);
|
||||||
free(info->user_username);
|
free(info->user_username);
|
||||||
free(info->host_ip);
|
free(info->host_ip);
|
||||||
|
@ -90,8 +92,8 @@ bool tpp_session_begin(const TPP_CONNECT_INFO* info, int* db_id)
|
||||||
return ts_web_rpc_session_begin(sinfo, *db_id);
|
return ts_web_rpc_session_begin(sinfo, *db_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tpp_session_update(int db_id, int state) {
|
bool tpp_session_update(int db_id, int protocol_sub_type, int state) {
|
||||||
return ts_web_rpc_session_update(db_id, state);
|
return ts_web_rpc_session_update(db_id, protocol_sub_type, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tpp_session_end(const char* sid, int db_id, int ret)
|
bool tpp_session_end(const char* sid, int db_id, int ret)
|
||||||
|
|
|
@ -40,7 +40,7 @@ void TsSessionManager::_set_stop_flag(void)
|
||||||
|
|
||||||
void TsSessionManager::_remove_expired_connect_info(void)
|
void TsSessionManager::_remove_expired_connect_info(void)
|
||||||
{
|
{
|
||||||
// 超过30秒未进行连接的connect-info会被移除
|
// 超过15秒未进行连接的connect-info会被移除
|
||||||
|
|
||||||
ExThreadSmartLock locker(m_lock);
|
ExThreadSmartLock locker(m_lock);
|
||||||
|
|
||||||
|
@ -48,15 +48,13 @@ void TsSessionManager::_remove_expired_connect_info(void)
|
||||||
ts_connections::iterator it = m_connections.begin();
|
ts_connections::iterator it = m_connections.begin();
|
||||||
for (; it != m_connections.end(); )
|
for (; it != m_connections.end(); )
|
||||||
{
|
{
|
||||||
#ifdef EX_DEBUG
|
//EXLOGD("[core] check expired connect info: [%s] %d, %d %d %d\n", it->first.c_str(), it->second->ref_count, int(_now), int(it->second->ticket_start), int(_now - it->second->ticket_start));
|
||||||
if (it->second->ref_count == 0 && _now - it->second->ticket_start >= 60*1000*60)
|
if (it->second->ref_count == 0 && _now - it->second->ticket_start > 15000)
|
||||||
#else
|
|
||||||
if (it->second->ref_count == 0 && _now - it->second->ticket_start >= 30000)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
EXLOGV("[core] remove connection info: %s\n", it->first.c_str());
|
EXLOGD("[core] remove connection info, because timeout: %s\n", it->first.c_str());
|
||||||
delete it->second;
|
delete it->second;
|
||||||
m_connections.erase(it++);
|
m_connections.erase(it++);
|
||||||
|
EXLOGD("[core] there are %d connection info exists.\n", m_connections.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -96,6 +94,24 @@ bool TsSessionManager::get_connect_info(const ex_astr& sid, TS_CONNECT_INFO& inf
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TsSessionManager::free_connect_info(const ex_astr& sid) {
|
||||||
|
ExThreadSmartLock locker(m_lock);
|
||||||
|
|
||||||
|
ts_connections::iterator it = m_connections.find(sid);
|
||||||
|
if (it == m_connections.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
it->second->ref_count--;
|
||||||
|
if (it->second->ref_count <= 0) {
|
||||||
|
EXLOGD("[core] remove connection info, because all connections closed: %s\n", it->first.c_str());
|
||||||
|
delete it->second;
|
||||||
|
m_connections.erase(it);
|
||||||
|
EXLOGD("[core] there are %d connection info exists.\n", m_connections.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info)
|
bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info)
|
||||||
{
|
{
|
||||||
ExThreadSmartLock locker(m_lock);
|
ExThreadSmartLock locker(m_lock);
|
||||||
|
@ -118,6 +134,8 @@ bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info)
|
||||||
}
|
}
|
||||||
|
|
||||||
info->sid = _sid;
|
info->sid = _sid;
|
||||||
|
info->ref_count = 0;
|
||||||
|
info->ticket_start = ex_get_tick_count();
|
||||||
m_connections.insert(std::make_pair(_sid, info));
|
m_connections.insert(std::make_pair(_sid, info));
|
||||||
|
|
||||||
sid = _sid;
|
sid = _sid;
|
||||||
|
|
|
@ -50,20 +50,10 @@ public:
|
||||||
// generate a sid for connection info.
|
// generate a sid for connection info.
|
||||||
bool request_session(ex_astr& sid, TS_CONNECT_INFO* info);
|
bool request_session(ex_astr& sid, TS_CONNECT_INFO* info);
|
||||||
|
|
||||||
// +ref for connection-info.
|
// 根据sid得到连接信息(并增加引用计数)
|
||||||
bool session_connect(const ex_astr& sid, TPP_CONNECT_INFO** info);
|
|
||||||
|
|
||||||
// free connection-info created by session_connect().
|
|
||||||
bool free_connect_info(TPP_CONNECT_INFO* info);
|
|
||||||
|
|
||||||
// -ref for connecton-info, and release it when ref is 0.
|
|
||||||
bool session_end(const ex_astr& sid);
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
void timer();
|
|
||||||
|
|
||||||
// 根据sid得到session信息
|
|
||||||
bool get_connect_info(const ex_astr& sid, TS_CONNECT_INFO& info);
|
bool get_connect_info(const ex_astr& sid, TS_CONNECT_INFO& info);
|
||||||
|
// 减少引用计数,当引用计数为0时,删除之
|
||||||
|
bool free_connect_info(const ex_astr& sid);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Ïß³ÌÑ»·
|
// Ïß³ÌÑ»·
|
||||||
|
|
|
@ -263,11 +263,12 @@ bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ts_web_rpc_session_update(int record_id, int state) {
|
bool ts_web_rpc_session_update(int record_id, int protocol_sub_type, int state) {
|
||||||
Json::FastWriter json_writer;
|
Json::FastWriter json_writer;
|
||||||
Json::Value jreq;
|
Json::Value jreq;
|
||||||
jreq["method"] = "session_update";
|
jreq["method"] = "session_update";
|
||||||
jreq["param"]["rid"] = record_id;
|
jreq["param"]["rid"] = record_id;
|
||||||
|
jreq["param"]["protocol_sub_type"] = protocol_sub_type;
|
||||||
jreq["param"]["code"] = state;
|
jreq["param"]["code"] = state;
|
||||||
|
|
||||||
ex_astr json_param;
|
ex_astr json_param;
|
||||||
|
|
|
@ -14,7 +14,7 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info);
|
||||||
// 记录会话的开始
|
// 记录会话的开始
|
||||||
bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id);
|
bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id);
|
||||||
// update session state
|
// update session state
|
||||||
bool ts_web_rpc_session_update(int id, int state);
|
bool ts_web_rpc_session_update(int id, int protocol_sub_type, int state);
|
||||||
//session 结束
|
//session 结束
|
||||||
bool ts_web_rpc_session_end(const char* sid, int id, int ret_code);
|
bool ts_web_rpc_session_end(const char* sid, int id, int ret_code);
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,6 @@ SshProxy::~SshProxy()
|
||||||
ssh_bind_free(m_bind);
|
ssh_bind_free(m_bind);
|
||||||
|
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
|
|
||||||
ts_sftp_sessions::iterator it;
|
|
||||||
for (it = m_sftp_sessions.begin(); it != m_sftp_sessions.end(); ++it)
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
m_sftp_sessions.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SshProxy::init()
|
bool SshProxy::init()
|
||||||
|
@ -70,7 +63,7 @@ bool SshProxy::init()
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshProxy::timer() {
|
void SshProxy::timer() {
|
||||||
// be called per one second.
|
// timer() will be called per one second, and I will do my job per 5 seconds.
|
||||||
m_timer_counter++;
|
m_timer_counter++;
|
||||||
if(m_timer_counter < 5)
|
if(m_timer_counter < 5)
|
||||||
return;
|
return;
|
||||||
|
@ -88,36 +81,7 @@ void SshProxy::timer() {
|
||||||
void SshProxy::_thread_loop()
|
void SshProxy::_thread_loop()
|
||||||
{
|
{
|
||||||
EXLOGV("[ssh] TeleportServer-SSH ready on %s:%d\n", m_host_ip.c_str(), m_host_port);
|
EXLOGV("[ssh] TeleportServer-SSH ready on %s:%d\n", m_host_ip.c_str(), m_host_port);
|
||||||
_run();
|
|
||||||
EXLOGV("[ssh] main-loop end.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshProxy::_set_stop_flag()
|
|
||||||
{
|
|
||||||
m_stop_flag = true;
|
|
||||||
|
|
||||||
if (m_is_running)
|
|
||||||
{
|
|
||||||
// 用一个变通的方式来结束阻塞中的监听,就是连接一下它。
|
|
||||||
ex_astr host_ip = m_host_ip;
|
|
||||||
if (host_ip == "0.0.0.0")
|
|
||||||
host_ip = "127.0.0.1";
|
|
||||||
|
|
||||||
ssh_session _session = ssh_new();
|
|
||||||
ssh_options_set(_session, SSH_OPTIONS_HOST, host_ip.c_str());
|
|
||||||
ssh_options_set(_session, SSH_OPTIONS_PORT, &m_host_port);
|
|
||||||
|
|
||||||
int _timeout_us = 10;
|
|
||||||
ssh_options_set(_session, SSH_OPTIONS_TIMEOUT, &_timeout_us);
|
|
||||||
ssh_connect(_session);
|
|
||||||
ssh_free(_session);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_thread_mgr.stop_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshProxy::_run()
|
|
||||||
{
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
// 注意,ssh_new()出来的指针,如果遇到停止标志,本函数内部就释放了,否则这个指针交给了SshSession类实例管理,其析构时会释放。
|
// 注意,ssh_new()出来的指针,如果遇到停止标志,本函数内部就释放了,否则这个指针交给了SshSession类实例管理,其析构时会释放。
|
||||||
|
@ -169,92 +133,38 @@ void SshProxy::_run()
|
||||||
|
|
||||||
// 等待所有工作线程退出
|
// 等待所有工作线程退出
|
||||||
m_thread_mgr.stop_all();
|
m_thread_mgr.stop_all();
|
||||||
|
|
||||||
|
EXLOGV("[ssh] main-loop end.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshProxy::_dump_sftp_sessions()
|
void SshProxy::_set_stop_flag()
|
||||||
{
|
{
|
||||||
ts_sftp_sessions::iterator it = m_sftp_sessions.begin();
|
m_stop_flag = true;
|
||||||
for (; it != m_sftp_sessions.end(); ++it)
|
|
||||||
{
|
|
||||||
EXLOGD("[ssh] ssh-proxy session: sid: %s\n", it->first.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshProxy::add_sftp_session_info(const ex_astr& sid, const ex_astr& host_ip, int host_port, const ex_astr& user_name, const ex_astr& user_auth, int auth_mode)
|
if (m_is_running)
|
||||||
{
|
|
||||||
ExThreadSmartLock locker(m_lock);
|
|
||||||
EXLOGD("[ssh] add sftp session-id: %s\n", sid.c_str());
|
|
||||||
ts_sftp_sessions::iterator it = m_sftp_sessions.find(sid);
|
|
||||||
if (it != m_sftp_sessions.end())
|
|
||||||
{
|
{
|
||||||
EXLOGD("[ssh] sftp-session-id '%s' already exists.\n", sid.c_str());
|
// 用一个变通的方式来结束阻塞中的监听,就是连接一下它。
|
||||||
it->second->ref_count++;
|
ex_astr host_ip = m_host_ip;
|
||||||
return;
|
if (host_ip == "0.0.0.0")
|
||||||
|
host_ip = "127.0.0.1";
|
||||||
|
|
||||||
|
ssh_session _session = ssh_new();
|
||||||
|
ssh_options_set(_session, SSH_OPTIONS_HOST, host_ip.c_str());
|
||||||
|
ssh_options_set(_session, SSH_OPTIONS_PORT, &m_host_port);
|
||||||
|
|
||||||
|
int _timeout_us = 10;
|
||||||
|
ssh_options_set(_session, SSH_OPTIONS_TIMEOUT, &_timeout_us);
|
||||||
|
ssh_connect(_session);
|
||||||
|
ssh_free(_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
TS_SFTP_SESSION_INFO* info = new TS_SFTP_SESSION_INFO;
|
m_thread_mgr.stop_all();
|
||||||
info->host_ip = host_ip;
|
|
||||||
info->host_port = host_port;
|
|
||||||
info->user_name = user_name;
|
|
||||||
info->user_auth = user_auth;
|
|
||||||
info->auth_mode = auth_mode;
|
|
||||||
info->ref_count = 1;
|
|
||||||
|
|
||||||
if (!m_sftp_sessions.insert(std::make_pair(sid, info)).second)
|
|
||||||
{
|
|
||||||
EXLOGE("[ssh] ssh-proxy can not insert a sftp-session-id.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
_dump_sftp_sessions();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SshProxy::get_sftp_session_info(const ex_astr& sid, TS_SFTP_SESSION_INFO& info)
|
|
||||||
{
|
|
||||||
ExThreadSmartLock locker(m_lock);
|
|
||||||
EXLOGD("[ssh] try to get info by sftp session-id: %s\n", sid.c_str());
|
|
||||||
|
|
||||||
_dump_sftp_sessions();
|
|
||||||
|
|
||||||
ts_sftp_sessions::iterator it = m_sftp_sessions.find(sid);
|
|
||||||
if (it == m_sftp_sessions.end())
|
|
||||||
{
|
|
||||||
EXLOGD("[ssh] sftp-session '%s' not exists.\n", sid.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.host_ip = it->second->host_ip;
|
|
||||||
info.host_port = it->second->host_port;
|
|
||||||
info.user_name = it->second->user_name;
|
|
||||||
info.user_auth = it->second->user_auth;
|
|
||||||
info.auth_mode = it->second->auth_mode;
|
|
||||||
info.ref_count = it->second->ref_count;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshProxy::remove_sftp_sid(const ex_astr& sid)
|
|
||||||
{
|
|
||||||
EXLOGD("[ssh] try to remove sftp session-id: %s\n", sid.c_str());
|
|
||||||
|
|
||||||
ExThreadSmartLock locker(m_lock);
|
|
||||||
ts_sftp_sessions::iterator it = m_sftp_sessions.find(sid);
|
|
||||||
if (it == m_sftp_sessions.end())
|
|
||||||
{
|
|
||||||
EXLOGE("[ssh] ssh-proxy when remove sftp sid, it not in charge.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
it->second->ref_count--;
|
|
||||||
if (it->second->ref_count <= 0)
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
m_sftp_sessions.erase(it);
|
|
||||||
EXLOGD("[ssh] sftp session-id '%s' removed.\n", sid.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshProxy::session_finished(SshSession* sess)
|
void SshProxy::session_finished(SshSession* sess)
|
||||||
{
|
{
|
||||||
|
// TODO: 向核心模块汇报此会话终止,以减少对应连接信息的引用计数
|
||||||
|
|
||||||
ExThreadSmartLock locker(m_lock);
|
ExThreadSmartLock locker(m_lock);
|
||||||
ts_ssh_sessions::iterator it = m_sessions.find(sess);
|
ts_ssh_sessions::iterator it = m_sessions.find(sess);
|
||||||
if (it != m_sessions.end())
|
if (it != m_sessions.end())
|
||||||
|
|
|
@ -7,18 +7,6 @@
|
||||||
|
|
||||||
typedef std::map<SshSession*, unsigned char> ts_ssh_sessions;
|
typedef std::map<SshSession*, unsigned char> ts_ssh_sessions;
|
||||||
|
|
||||||
typedef struct TS_SFTP_SESSION_INFO
|
|
||||||
{
|
|
||||||
ex_astr host_ip;
|
|
||||||
int host_port;
|
|
||||||
ex_astr user_name;
|
|
||||||
ex_astr user_auth;
|
|
||||||
int auth_mode;
|
|
||||||
int ref_count; // 引用计数器,但所有引用本登录信息的ssh-sftp通道关闭,就销毁之
|
|
||||||
}TS_SFTP_SESSION_INFO;
|
|
||||||
|
|
||||||
typedef std::map<ex_astr, TS_SFTP_SESSION_INFO*> ts_sftp_sessions;
|
|
||||||
|
|
||||||
class SshProxy : public ExThreadBase
|
class SshProxy : public ExThreadBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -28,31 +16,14 @@ public:
|
||||||
bool init();
|
bool init();
|
||||||
void timer();
|
void timer();
|
||||||
|
|
||||||
void add_sftp_session_info(
|
|
||||||
const ex_astr& sid,
|
|
||||||
const ex_astr& host_ip,
|
|
||||||
int host_port,
|
|
||||||
const ex_astr& user_name,
|
|
||||||
const ex_astr& user_auth,
|
|
||||||
int auth_mode
|
|
||||||
);
|
|
||||||
bool get_sftp_session_info(const ex_astr& sid, TS_SFTP_SESSION_INFO& info);
|
|
||||||
void remove_sftp_sid(const ex_astr& sid);
|
|
||||||
|
|
||||||
void session_finished(SshSession* sess);
|
void session_finished(SshSession* sess);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _thread_loop();
|
void _thread_loop();
|
||||||
void _set_stop_flag();
|
void _set_stop_flag();
|
||||||
|
|
||||||
void _run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void _dump_sftp_sessions();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ssh_bind m_bind;
|
ssh_bind m_bind;
|
||||||
//bool m_stop_flag;
|
|
||||||
int m_timer_counter;
|
int m_timer_counter;
|
||||||
|
|
||||||
ExThreadLock m_lock;
|
ExThreadLock m_lock;
|
||||||
|
@ -61,7 +32,6 @@ private:
|
||||||
int m_host_port;
|
int m_host_port;
|
||||||
|
|
||||||
ts_ssh_sessions m_sessions;
|
ts_ssh_sessions m_sessions;
|
||||||
ts_sftp_sessions m_sftp_sessions;
|
|
||||||
|
|
||||||
ExThreadManager m_thread_mgr;
|
ExThreadManager m_thread_mgr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,19 +5,27 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <teleport_const.h>
|
#include <teleport_const.h>
|
||||||
|
|
||||||
|
TP_SSH_CHANNEL_PAIR::TP_SSH_CHANNEL_PAIR() {
|
||||||
|
type = TS_SSH_CHANNEL_TYPE_UNKNOWN;
|
||||||
|
|
||||||
|
cli_channel = NULL;
|
||||||
|
srv_channel = NULL;
|
||||||
|
|
||||||
|
retcode = TP_SESS_STAT_RUNNING;
|
||||||
|
db_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SshSession::SshSession(SshProxy *proxy, ssh_session sess_client) :
|
SshSession::SshSession(SshProxy *proxy, ssh_session sess_client) :
|
||||||
ExThreadBase("ssh-session-thread"),
|
ExThreadBase("ssh-session-thread"),
|
||||||
m_proxy(proxy),
|
m_proxy(proxy),
|
||||||
m_cli_session(sess_client),
|
m_cli_session(sess_client),
|
||||||
m_srv_session(NULL)
|
m_srv_session(NULL),
|
||||||
|
m_conn_info(NULL)
|
||||||
{
|
{
|
||||||
m_retcode = TP_SESS_STAT_RUNNING;
|
|
||||||
m_db_id = 0;
|
|
||||||
|
|
||||||
m_auth_type = TP_AUTH_TYPE_PASSWORD;
|
m_auth_type = TP_AUTH_TYPE_PASSWORD;
|
||||||
|
|
||||||
m_is_first_server_data = true;
|
m_is_first_server_data = true;
|
||||||
m_is_sftp = false;
|
|
||||||
|
|
||||||
m_is_logon = false;
|
m_is_logon = false;
|
||||||
m_have_error = false;
|
m_have_error = false;
|
||||||
|
@ -44,8 +52,8 @@ SshSession::~SshSession() {
|
||||||
|
|
||||||
_set_stop_flag();
|
_set_stop_flag();
|
||||||
|
|
||||||
if (m_is_sftp) {
|
if (NULL != m_conn_info) {
|
||||||
m_proxy->remove_sftp_sid(m_sid);
|
g_ssh_env.free_connect_info(m_conn_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXLOGD("[ssh] session destroy.\n");
|
EXLOGD("[ssh] session destroy.\n");
|
||||||
|
@ -53,7 +61,6 @@ SshSession::~SshSession() {
|
||||||
|
|
||||||
void SshSession::_thread_loop(void) {
|
void SshSession::_thread_loop(void) {
|
||||||
_run();
|
_run();
|
||||||
_on_session_end();
|
|
||||||
m_proxy->session_finished(this);
|
m_proxy->session_finished(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,71 +79,85 @@ void SshSession::_set_stop_flag(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SshSession::_on_session_begin(const TPP_CONNECT_INFO* info)
|
void SshSession::_session_error(int err_code) {
|
||||||
{
|
int db_id = 0;
|
||||||
if (!g_ssh_env.session_begin(info, &m_db_id))
|
if (!g_ssh_env.session_begin(m_conn_info, &db_id))
|
||||||
{
|
{
|
||||||
EXLOGD("[ssh] session_begin error. %d\n", m_db_id);
|
EXLOGE("[ssh] can not write session error to database.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ssh_env.session_end(m_sid.c_str(), db_id, err_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SshSession::_on_session_begin(TP_SSH_CHANNEL_PAIR* cp)
|
||||||
|
{
|
||||||
|
if (!g_ssh_env.session_begin(m_conn_info, &(cp->db_id)))
|
||||||
|
{
|
||||||
|
EXLOGD("[ssh] session_begin error. %d\n", cp->db_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rec.begin(g_ssh_env.replay_path.c_str(), L"tp-ssh", m_db_id, info);
|
if (!g_ssh_env.session_update(cp->db_id, m_conn_info->protocol_sub_type, TP_SESS_STAT_STARTED))
|
||||||
|
{
|
||||||
|
EXLOGD("[ssh] session_update error. %d\n", cp->db_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cp->rec.begin(g_ssh_env.replay_path.c_str(), L"tp-ssh", cp->db_id, m_conn_info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SshSession::_on_session_end(void)
|
void SshSession::_on_session_end(TP_SSH_CHANNEL_PAIR* cp)
|
||||||
{
|
{
|
||||||
if (m_db_id > 0)
|
if (cp->db_id > 0)
|
||||||
{
|
{
|
||||||
EXLOGD("[ssh] session ret-code: %d\n", m_retcode);
|
EXLOGD("[ssh] session ret-code: %d\n", cp->retcode);
|
||||||
|
|
||||||
// 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值
|
// 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值
|
||||||
if (m_retcode == TP_SESS_STAT_RUNNING)
|
if (cp->retcode == TP_SESS_STAT_RUNNING || cp->retcode == TP_SESS_STAT_STARTED)
|
||||||
m_retcode = TP_SESS_STAT_END;
|
cp->retcode = TP_SESS_STAT_END;
|
||||||
|
|
||||||
g_ssh_env.session_end(m_sid.c_str(), m_db_id, m_retcode);
|
g_ssh_env.session_end(m_sid.c_str(), cp->db_id, cp->retcode);
|
||||||
|
|
||||||
|
cp->db_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshSession::_close_channels(void) {
|
void SshSession::_close_channels(void) {
|
||||||
ExThreadSmartLock locker(m_lock);
|
ExThreadSmartLock locker(m_lock);
|
||||||
|
|
||||||
if (m_channel_cli_srv.size() > 0)
|
tp_channels::iterator it = m_channels.begin();
|
||||||
EXLOGW("[ssh] when close all channels, %d client channel need close.\n", m_channel_cli_srv.size());
|
for (; it != m_channels.end(); ++it) {
|
||||||
if (m_channel_srv_cli.size() > 0)
|
ssh_channel ch = (*it)->srv_channel;
|
||||||
EXLOGW("[ssh] when close all channels, %d server channel need close.\n", m_channel_srv_cli.size());
|
if (ch != NULL) {
|
||||||
|
if (!ssh_channel_is_closed(ch)) {
|
||||||
ts_ssh_channel_map::iterator it = m_channel_cli_srv.begin();
|
if (!ssh_channel_is_eof(ch))
|
||||||
for (; it != m_channel_cli_srv.end(); ++it) {
|
ssh_channel_send_eof(ch);
|
||||||
if (!ssh_channel_is_eof(it->first))
|
ssh_channel_close(ch);
|
||||||
ssh_channel_send_eof(it->first);
|
}
|
||||||
if (!ssh_channel_is_closed(it->first))
|
ssh_channel_free(ch);
|
||||||
ssh_channel_close(it->first);
|
|
||||||
ssh_channel_free(it->first);
|
|
||||||
|
|
||||||
if (NULL != it->second) {
|
|
||||||
if (!ssh_channel_is_eof(it->second->channel))
|
|
||||||
ssh_channel_send_eof(it->second->channel);
|
|
||||||
if (!ssh_channel_is_closed(it->second->channel))
|
|
||||||
ssh_channel_close(it->second->channel);
|
|
||||||
ssh_channel_free(it->second->channel);
|
|
||||||
|
|
||||||
delete it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ch = (*it)->cli_channel;
|
||||||
|
if (ch != NULL) {
|
||||||
|
if (!ssh_channel_is_closed(ch)) {
|
||||||
|
if (!ssh_channel_is_eof(ch))
|
||||||
|
ssh_channel_send_eof(ch);
|
||||||
|
ssh_channel_close(ch);
|
||||||
|
}
|
||||||
|
ssh_channel_free(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
_on_session_end(*it);
|
||||||
|
|
||||||
|
delete (*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
it = m_channel_srv_cli.begin();
|
m_channels.clear();
|
||||||
for (; it != m_channel_srv_cli.end(); ++it) {
|
|
||||||
if (NULL != it->second) {
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_channel_cli_srv.clear();
|
|
||||||
m_channel_srv_cli.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshSession::_run(void) {
|
void SshSession::_run(void) {
|
||||||
|
@ -175,7 +196,7 @@ void SshSession::_run(void) {
|
||||||
|
|
||||||
// 认证,并打开一个通道
|
// 认证,并打开一个通道
|
||||||
int r = 0;
|
int r = 0;
|
||||||
while (!(m_is_logon && m_channel_cli_srv.size() > 0)) {
|
while (!(m_is_logon && m_channels.size() > 0)) {
|
||||||
if (m_have_error)
|
if (m_have_error)
|
||||||
break;
|
break;
|
||||||
r = ssh_event_dopoll(event_loop, -1);
|
r = ssh_event_dopoll(event_loop, -1);
|
||||||
|
@ -211,7 +232,7 @@ void SshSession::_run(void) {
|
||||||
|
|
||||||
_close_channels();
|
_close_channels();
|
||||||
}
|
}
|
||||||
} while (m_channel_cli_srv.size() > 0);
|
} while (m_channels.size() > 0);
|
||||||
|
|
||||||
EXLOGV("[ssh] [%s:%d] all channel in this session are closed.\n", m_client_ip.c_str(), m_client_port);
|
EXLOGV("[ssh] [%s:%d] all channel in this session are closed.\n", m_client_ip.c_str(), m_client_port);
|
||||||
|
|
||||||
|
@ -221,7 +242,12 @@ void SshSession::_run(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshSession::save_record() {
|
void SshSession::save_record() {
|
||||||
m_rec.save_record();
|
ExThreadSmartLock locker(m_lock);
|
||||||
|
|
||||||
|
tp_channels::iterator it = m_channels.begin();
|
||||||
|
for (; it != m_channels.end(); ++it) {
|
||||||
|
(*it)->rec.save_record();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -232,57 +258,31 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
EXLOGV("[ssh] authenticating, session-id: %s\n", _this->m_sid.c_str());
|
EXLOGV("[ssh] authenticating, session-id: %s\n", _this->m_sid.c_str());
|
||||||
|
|
||||||
int protocol = 0;
|
int protocol = 0;
|
||||||
TPP_CONNECT_INFO* sess_info = g_ssh_env.get_connect_info(_this->m_sid.c_str());
|
//TPP_CONNECT_INFO* sess_info = g_ssh_env.get_connect_info(_this->m_sid.c_str());
|
||||||
|
_this->m_conn_info = g_ssh_env.get_connect_info(_this->m_sid.c_str());
|
||||||
|
|
||||||
if (NULL == sess_info) {
|
if (NULL == _this->m_conn_info) {
|
||||||
// EXLOGW("[ssh] try to get login-info from ssh-sftp-session.\n");
|
EXLOGE("[ssh] no such session: %s\n", _this->m_sid.c_str());
|
||||||
// 尝试从sftp连接记录中获取连接信息(一个ssh会话如果成为sftp会话,内部会将连接信息记录下来备用)
|
_this->m_have_error = true;
|
||||||
// TS_SFTP_SESSION_INFO sftp_info;
|
_this->_session_error(TP_SESS_STAT_ERR_SESSION);
|
||||||
// if (!_this->m_proxy->get_sftp_session_info(_this->m_sid, sftp_info)) {
|
return SSH_AUTH_DENIED;
|
||||||
EXLOGE("[ssh] no such session: %s\n", _this->m_sid.c_str());
|
|
||||||
_this->m_have_error = true;
|
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED;
|
|
||||||
return SSH_AUTH_DENIED;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// _this->m_conn_ip = sftp_info.host_ip;
|
|
||||||
// _this->m_conn_port = sftp_info.host_port;
|
|
||||||
// _this->m_auth_type = sftp_info.auth_mode;
|
|
||||||
// _this->m_acc_name = sftp_info.user_name;
|
|
||||||
// _this->m_acc_secret = sftp_info.user_auth;
|
|
||||||
// protocol = TP_PROTOCOL_TYPE_SSH;
|
|
||||||
//
|
|
||||||
// // 因为是从sftp会话得来的登录数据,因此限制本会话只能用于sftp,不允许再使用shell了。
|
|
||||||
// _this->_enter_sftp_mode();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_this->m_conn_ip = sess_info->conn_ip;
|
_this->m_conn_ip = _this->m_conn_info->conn_ip;
|
||||||
_this->m_conn_port = sess_info->conn_port;
|
_this->m_conn_port = _this->m_conn_info->conn_port;
|
||||||
_this->m_auth_type = sess_info->auth_type;
|
_this->m_auth_type = _this->m_conn_info->auth_type;
|
||||||
_this->m_acc_name = sess_info->acc_username;
|
_this->m_acc_name = _this->m_conn_info->acc_username;
|
||||||
_this->m_acc_secret = sess_info->acc_secret;
|
_this->m_acc_secret = _this->m_conn_info->acc_secret;
|
||||||
protocol = sess_info->protocol_type;
|
protocol = _this->m_conn_info->protocol_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocol != TP_PROTOCOL_TYPE_SSH) {
|
if (protocol != TP_PROTOCOL_TYPE_SSH) {
|
||||||
g_ssh_env.free_connect_info(sess_info);
|
|
||||||
EXLOGE("[ssh] session '%s' is not for SSH.\n", _this->m_sid.c_str());
|
EXLOGE("[ssh] session '%s' is not for SSH.\n", _this->m_sid.c_str());
|
||||||
_this->m_have_error = true;
|
_this->m_have_error = true;
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED;
|
_this->_session_error(TP_SESS_STAT_ERR_INTERNAL);
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_this->_on_session_begin(sess_info))
|
|
||||||
{
|
|
||||||
g_ssh_env.free_connect_info(sess_info);
|
|
||||||
_this->m_have_error = true;
|
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED;
|
|
||||||
return SSH_AUTH_DENIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_ssh_env.free_connect_info(sess_info);
|
|
||||||
sess_info = NULL;
|
|
||||||
|
|
||||||
// 现在尝试根据session-id获取得到的信息,连接并登录真正的SSH服务器
|
// 现在尝试根据session-id获取得到的信息,连接并登录真正的SSH服务器
|
||||||
EXLOGV("[ssh] try to connect to real SSH server %s:%d\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
EXLOGV("[ssh] try to connect to real SSH server %s:%d\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
||||||
_this->m_srv_session = ssh_new();
|
_this->m_srv_session = ssh_new();
|
||||||
|
@ -306,30 +306,24 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
EXLOGE("[ssh] can not connect to real SSH server %s:%d. [%d]%s\n", _this->m_conn_ip.c_str(), _this->m_conn_port, rc, ssh_get_error(_this->m_srv_session));
|
EXLOGE("[ssh] can not connect to real SSH server %s:%d. [%d]%s\n", _this->m_conn_ip.c_str(), _this->m_conn_port, rc, ssh_get_error(_this->m_srv_session));
|
||||||
_this->m_have_error = true;
|
_this->m_have_error = true;
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_CONNECT;
|
_this->_session_error(TP_SESS_STAT_ERR_CONNECT);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_ssh_env.session_update(_this->m_db_id, TP_SESS_STAT_STARTED))
|
// // 检查服务端支持的认证协议
|
||||||
{
|
|
||||||
EXLOGD("[ssh] session_update error. %d\n", _this->m_db_id);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// // 检查服务端支持的认证协议
|
|
||||||
ssh_userauth_none(_this->m_srv_session, NULL);
|
ssh_userauth_none(_this->m_srv_session, NULL);
|
||||||
// rc = ssh_userauth_none(_this->m_srv_session, NULL);
|
// rc = ssh_userauth_none(_this->m_srv_session, NULL);
|
||||||
// if (rc == SSH_AUTH_ERROR) {
|
// if (rc == SSH_AUTH_ERROR) {
|
||||||
// EXLOGE("[ssh] invalid password for password mode to login to real SSH server %s:%d.\n", _this->m_server_ip.c_str(), _this->m_server_port);
|
// EXLOGE("[ssh] invalid password for password mode to login to real SSH server %s:%d.\n", _this->m_server_ip.c_str(), _this->m_server_port);
|
||||||
// _this->m_have_error = true;
|
// _this->m_have_error = true;
|
||||||
// _this->m_retcode = SESS_STAT_ERR_AUTH_DENIED;
|
// _this->m_retcode = SESS_STAT_ERR_AUTH_DENIED;
|
||||||
// return SSH_AUTH_ERROR;
|
// return SSH_AUTH_ERROR;
|
||||||
// }
|
// }
|
||||||
// // int auth_methods = ssh_userauth_list(_this->m_srv_session, NULL);
|
// // int auth_methods = ssh_userauth_list(_this->m_srv_session, NULL);
|
||||||
// const char* banner = ssh_get_issue_banner(_this->m_srv_session);
|
// const char* banner = ssh_get_issue_banner(_this->m_srv_session);
|
||||||
// if (NULL != banner) {
|
// if (NULL != banner) {
|
||||||
// EXLOGE("[ssh] issue banner: %s\n", banner);
|
// EXLOGE("[ssh] issue banner: %s\n", banner);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
if (_this->m_auth_type == TP_AUTH_TYPE_PASSWORD) {
|
if (_this->m_auth_type == TP_AUTH_TYPE_PASSWORD) {
|
||||||
|
@ -350,7 +344,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int nprompts = ssh_userauth_kbdint_getnprompts(_this->m_srv_session);
|
int nprompts = ssh_userauth_kbdint_getnprompts(_this->m_srv_session);
|
||||||
if(0 == nprompts) {
|
if (0 == nprompts) {
|
||||||
rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL);
|
rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -364,7 +358,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
EXLOGE("[ssh] invalid password for interactive mode to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
EXLOGE("[ssh] invalid password for interactive mode to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
||||||
_this->m_have_error = true;
|
_this->m_have_error = true;
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED;
|
_this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +388,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
|
|
||||||
EXLOGE("[ssh] can not use password mode or interactive mode to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
EXLOGE("[ssh] can not use password mode or interactive mode to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
||||||
_this->m_have_error = true;
|
_this->m_have_error = true;
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED;
|
_this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
else if (_this->m_auth_type == TP_AUTH_TYPE_PRIVATE_KEY) {
|
else if (_this->m_auth_type == TP_AUTH_TYPE_PRIVATE_KEY) {
|
||||||
|
@ -402,7 +396,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
if (SSH_OK != ssh_pki_import_privkey_base64(_this->m_acc_secret.c_str(), NULL, NULL, NULL, &key)) {
|
if (SSH_OK != ssh_pki_import_privkey_base64(_this->m_acc_secret.c_str(), NULL, NULL, NULL, &key)) {
|
||||||
EXLOGE("[ssh] can not import private-key for auth.\n");
|
EXLOGE("[ssh] can not import private-key for auth.\n");
|
||||||
_this->m_have_error = true;
|
_this->m_have_error = true;
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_BAD_SSH_KEY;
|
_this->_session_error(TP_SESS_STAT_ERR_BAD_SSH_KEY);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,17 +411,18 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
else {
|
else {
|
||||||
EXLOGE("[ssh] failed to use private-key to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
EXLOGE("[ssh] failed to use private-key to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
||||||
_this->m_have_error = true;
|
_this->m_have_error = true;
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED;
|
_this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_this->m_auth_type == TP_AUTH_TYPE_NONE) {
|
else if (_this->m_auth_type == TP_AUTH_TYPE_NONE) {
|
||||||
|
_this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
EXLOGE("[ssh] invalid auth mode.\n");
|
EXLOGE("[ssh] invalid auth mode.\n");
|
||||||
_this->m_have_error = true;
|
_this->m_have_error = true;
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED;
|
_this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -436,14 +431,10 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd
|
||||||
// 客户端尝试打开一个通道(然后才能通过这个通道发控制命令或者收发数据)
|
// 客户端尝试打开一个通道(然后才能通过这个通道发控制命令或者收发数据)
|
||||||
EXLOGV("[ssh] client open channel\n");
|
EXLOGV("[ssh] client open channel\n");
|
||||||
|
|
||||||
// TODO: 记录会话开始,应该在这里进行,这样可以为每一个通道记录不同的日志,避免类似SecureCRT多标签页使用“复制会话”这样的功能将多个标签页中的记录混杂在一起。
|
|
||||||
// TODO: 每个通道应该记录单独的录像文件
|
|
||||||
|
|
||||||
|
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
ssh_channel cli_channel = ssh_channel_new(session);
|
ssh_channel cli_channel = ssh_channel_new(session);
|
||||||
if(cli_channel == NULL) {
|
if (cli_channel == NULL) {
|
||||||
EXLOGE("[ssh] can not create channel for client.\n");
|
EXLOGE("[ssh] can not create channel for client.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -451,7 +442,7 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd
|
||||||
|
|
||||||
// 我们也要向真正的服务器申请打开一个通道,来进行转发
|
// 我们也要向真正的服务器申请打开一个通道,来进行转发
|
||||||
ssh_channel srv_channel = ssh_channel_new(_this->m_srv_session);
|
ssh_channel srv_channel = ssh_channel_new(_this->m_srv_session);
|
||||||
if(srv_channel == NULL) {
|
if (srv_channel == NULL) {
|
||||||
EXLOGE("[ssh] can not create channel for server.\n");
|
EXLOGE("[ssh] can not create channel for server.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -462,46 +453,51 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd
|
||||||
}
|
}
|
||||||
ssh_set_channel_callbacks(srv_channel, &_this->m_srv_channel_cb);
|
ssh_set_channel_callbacks(srv_channel, &_this->m_srv_channel_cb);
|
||||||
|
|
||||||
|
TP_SSH_CHANNEL_PAIR* cp = new TP_SSH_CHANNEL_PAIR;
|
||||||
|
cp->type = TS_SSH_CHANNEL_TYPE_UNKNOWN;
|
||||||
|
cp->cli_channel = cli_channel;
|
||||||
|
cp->srv_channel = srv_channel;
|
||||||
|
|
||||||
|
if (!_this->_on_session_begin(cp)) {
|
||||||
|
ssh_channel_close(cli_channel);
|
||||||
|
ssh_channel_free(cli_channel);
|
||||||
|
ssh_channel_close(srv_channel);
|
||||||
|
ssh_channel_free(srv_channel);
|
||||||
|
delete cp;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// 将客户端和服务端的通道关联起来
|
// 将客户端和服务端的通道关联起来
|
||||||
{
|
{
|
||||||
ExThreadSmartLock locker(_this->m_lock);
|
ExThreadSmartLock locker(_this->m_lock);
|
||||||
|
_this->m_channels.push_back(cp);
|
||||||
TS_SSH_CHANNEL_INFO *srv_info = new TS_SSH_CHANNEL_INFO;
|
|
||||||
srv_info->channel = srv_channel;
|
|
||||||
srv_info->type = TS_SSH_CHANNEL_TYPE_UNKNOWN;
|
|
||||||
_this->m_channel_cli_srv.insert(std::make_pair(cli_channel, srv_info));
|
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *cli_info = new TS_SSH_CHANNEL_INFO;
|
|
||||||
cli_info->channel = cli_channel;
|
|
||||||
cli_info->type = TS_SSH_CHANNEL_TYPE_UNKNOWN;
|
|
||||||
_this->m_channel_srv_cli.insert(std::make_pair(srv_channel, cli_info));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXLOGD("[ssh] channel for client and server created.\n");
|
EXLOGD("[ssh] channel for client and server created.\n");
|
||||||
return cli_channel;
|
return cli_channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *SshSession::_get_cli_channel(ssh_channel srv_channel) {
|
TP_SSH_CHANNEL_PAIR* SshSession::_get_channel_pair(int channel_side, ssh_channel channel) {
|
||||||
ExThreadSmartLock locker(m_lock);
|
ExThreadSmartLock locker(m_lock);
|
||||||
ts_ssh_channel_map::iterator it = m_channel_srv_cli.find(srv_channel);
|
|
||||||
if (it == m_channel_srv_cli.end())
|
|
||||||
return NULL;
|
|
||||||
else
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *SshSession::_get_srv_channel(ssh_channel cli_channel) {
|
tp_channels::iterator it = m_channels.begin();
|
||||||
ExThreadSmartLock locker(m_lock);
|
for (; it != m_channels.end(); ++it) {
|
||||||
ts_ssh_channel_map::iterator it = m_channel_cli_srv.find(cli_channel);
|
if (channel_side == TP_SSH_CLIENT_SIDE) {
|
||||||
if (it == m_channel_cli_srv.end())
|
if ((*it)->cli_channel == channel)
|
||||||
return NULL;
|
return (*it);
|
||||||
else
|
}
|
||||||
return it->second;
|
else {
|
||||||
}
|
if ((*it)->srv_channel == channel)
|
||||||
|
return (*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SshSession::_process_ssh_command(int from, const ex_u8* data, int len)
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshSession::_process_ssh_command(TppSshRec* rec, int from, const ex_u8* data, int len)
|
||||||
{
|
{
|
||||||
if (TS_SSH_DATA_FROM_CLIENT == from)
|
if (TP_SSH_CLIENT_SIDE == from)
|
||||||
{
|
{
|
||||||
m_command_flag = 0;
|
m_command_flag = 0;
|
||||||
|
|
||||||
|
@ -593,7 +589,7 @@ void SshSession::_process_ssh_command(int from, const ex_u8* data, int len)
|
||||||
ex_replace_all(str, "\n", "");
|
ex_replace_all(str, "\n", "");
|
||||||
//EXLOGD("[ssh] save cmd: [%s]", str.c_str());
|
//EXLOGD("[ssh] save cmd: [%s]", str.c_str());
|
||||||
str += "\r\n";
|
str += "\r\n";
|
||||||
m_rec.record_command(str);
|
rec->record_command(str);
|
||||||
}
|
}
|
||||||
m_cmd_char_list.clear();
|
m_cmd_char_list.clear();
|
||||||
m_cmd_char_pos = m_cmd_char_list.begin();
|
m_cmd_char_pos = m_cmd_char_list.begin();
|
||||||
|
@ -611,7 +607,7 @@ void SshSession::_process_ssh_command(int from, const ex_u8* data, int len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TS_SSH_DATA_FROM_SERVER == from)
|
else if (TP_SSH_SERVER_SIDE == from)
|
||||||
{
|
{
|
||||||
if (m_command_flag == 0)
|
if (m_command_flag == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -774,7 +770,7 @@ void SshSession::_process_ssh_command(int from, const ex_u8* data, int len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshSession::_process_sftp_command(const ex_u8* data, int len) {
|
void SshSession::_process_sftp_command(TppSshRec* rec, const ex_u8* data, int len) {
|
||||||
// SFTP protocol: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13
|
// SFTP protocol: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13
|
||||||
//EXLOG_BIN(data, len, "[sftp] client channel data");
|
//EXLOG_BIN(data, len, "[sftp] client channel data");
|
||||||
|
|
||||||
|
@ -789,7 +785,7 @@ void SshSession::_process_sftp_command(const ex_u8* data, int len) {
|
||||||
|
|
||||||
if (sftp_cmd == 0x01) {
|
if (sftp_cmd == 0x01) {
|
||||||
// 0x01 = 1 = SSH_FXP_INIT
|
// 0x01 = 1 = SSH_FXP_INIT
|
||||||
m_rec.record_command("SFTP INITIALIZE\r\n");
|
rec->record_command("SFTP INITIALIZE\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,101 +860,90 @@ void SshSession::_process_sftp_command(const ex_u8* data, int len) {
|
||||||
ex_strformat(msg, 2048, "%d:%s:%s:%s\r\n", sftp_cmd, act, str1.c_str(), str2.c_str());
|
ex_strformat(msg, 2048, "%d:%s:%s:%s\r\n", sftp_cmd, act, str1.c_str(), str2.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rec.record_command(msg);
|
rec->record_command(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SshSession::_on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata) {
|
int SshSession::_on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata) {
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
if (_this->m_is_sftp) {
|
|
||||||
EXLOGE("[ssh] try to request pty on a sftp-session.\n");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXLOGD("[ssh] client request terminal: %s, (%d, %d) / (%d, %d)\n", term, x, y, px, py);
|
EXLOGD("[ssh] client request terminal: %s, (%d, %d) / (%d, %d)\n", term, x, y, px, py);
|
||||||
_this->m_rec.record_win_size_startup(x, y);
|
|
||||||
TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
||||||
if (NULL == info || NULL == info->channel) {
|
if (NULL == cp) {
|
||||||
EXLOGE("[ssh] when client request pty, not found server channel.\n");
|
EXLOGE("[ssh] when client request pty, not found channel pair.\n");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ssh_channel_request_pty_size(info->channel, term, x, y);
|
cp->rec.record_win_size_startup(x, y);
|
||||||
|
|
||||||
|
return ssh_channel_request_pty_size(cp->srv_channel, term, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channel, void *userdata) {
|
int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channel, void *userdata) {
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
if (_this->m_is_sftp) {
|
|
||||||
EXLOGE("[ssh] request shell on a sftp-session is denied.\n");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXLOGD("[ssh] client request shell\n");
|
EXLOGD("[ssh] client request shell\n");
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *srv_info = _this->_get_srv_channel(channel);
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
||||||
if (NULL == srv_info || NULL == srv_info->channel) {
|
if (NULL == cp) {
|
||||||
EXLOGE("[ssh] when client request shell, not found server channel.\n");
|
EXLOGE("[ssh] when client request shell, not found channel pair.\n");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
srv_info->type = TS_SSH_CHANNEL_TYPE_SHELL;
|
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel);
|
cp->type = TS_SSH_CHANNEL_TYPE_SHELL;
|
||||||
if (NULL == cli_info || NULL == cli_info->channel) {
|
g_ssh_env.session_update(cp->db_id, TP_PROTOCOL_TYPE_SSH_SHELL, TP_SESS_STAT_STARTED);
|
||||||
EXLOGE("[ssh] when client request shell, not found client channel.\n");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
cli_info->type = TS_SSH_CHANNEL_TYPE_SHELL;
|
|
||||||
|
|
||||||
// FIXME: if client is putty, it will block here. the following function will never return.
|
// FIXME: if client is putty, it will block here. the following function will never return.
|
||||||
// at this time, can not write data to this channel. read from this channel with timeout, got 0 byte.
|
// at this time, can not write data to this channel. read from this channel with timeout, got 0 byte.
|
||||||
// I have no idea how to fix it... :(
|
// I have no idea how to fix it... :(
|
||||||
return ssh_channel_request_shell(srv_info->channel);
|
return ssh_channel_request_shell(cp->srv_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshSession::_on_client_channel_close(ssh_session session, ssh_channel channel, void *userdata) {
|
void SshSession::_on_client_channel_close(ssh_session session, ssh_channel channel, void *userdata) {
|
||||||
EXLOGD("[ssh] on_client_channel_close().\n");
|
EXLOGD("[ssh] on_client_channel_close().\n");
|
||||||
|
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
|
||||||
if (NULL == info || NULL == info->channel) {
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
||||||
EXLOGW("[ssh] when close client channel, not found server channel, maybe it already closed.\n");
|
if (NULL == cp) {
|
||||||
|
EXLOGE("[ssh] when client channel close, not found channel pair.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!ssh_channel_is_eof(channel))
|
|
||||||
ssh_channel_send_eof(channel);
|
|
||||||
if (!ssh_channel_is_closed(channel))
|
|
||||||
ssh_channel_close(channel);
|
|
||||||
//ssh_channel_free(channel);
|
|
||||||
|
|
||||||
if (!ssh_channel_is_eof(info->channel))
|
if (cp->srv_channel == NULL) {
|
||||||
ssh_channel_send_eof(info->channel);
|
EXLOGW("[ssh] when client channel close, server-channel not exists.\n");
|
||||||
if (!ssh_channel_is_closed(info->channel))
|
}
|
||||||
ssh_channel_close(info->channel);
|
else {
|
||||||
//ssh_channel_free(info->channel);
|
if (!ssh_channel_is_closed(cp->srv_channel)) {
|
||||||
|
if (!ssh_channel_is_eof(cp->srv_channel)) {
|
||||||
|
//EXLOGD("[ssh] when client channel close, send eof to server-channel.\n");
|
||||||
|
ssh_channel_send_eof(cp->cli_channel);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
//EXLOGD("[ssh] when client channel close, close server-channel.\n");
|
||||||
ExThreadSmartLock locker(_this->m_lock);
|
ssh_channel_close(cp->srv_channel);
|
||||||
|
|
||||||
ts_ssh_channel_map::iterator it = _this->m_channel_cli_srv.find(channel);
|
ssh_channel_free(cp->srv_channel);
|
||||||
if (it != _this->m_channel_cli_srv.end()) {
|
cp->srv_channel = NULL;
|
||||||
delete it->second;
|
|
||||||
_this->m_channel_cli_srv.erase(it);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EXLOGW("[ssh] when remove client channel, it not in charge.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
it = _this->m_channel_srv_cli.find(info->channel);
|
|
||||||
if (it != _this->m_channel_srv_cli.end()) {
|
|
||||||
delete it->second;
|
|
||||||
_this->m_channel_srv_cli.erase(it);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EXLOGW("[ssh] when remove client channel, not found server channel.\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ssh_channel_is_closed(cp->cli_channel)) {
|
||||||
|
if (!ssh_channel_is_eof(cp->cli_channel)) {
|
||||||
|
//EXLOGD("[ssh] when client channel close, send eof to client-channel.\n");
|
||||||
|
ssh_channel_send_eof(cp->cli_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
//EXLOGD("[ssh] when client channel close, close client-channel.\n");
|
||||||
|
ssh_channel_close(cp->cli_channel);
|
||||||
|
|
||||||
|
ssh_channel_free(cp->cli_channel);
|
||||||
|
cp->cli_channel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_this->_on_session_end(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata)
|
int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata)
|
||||||
|
@ -973,19 +958,25 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel
|
||||||
if (_this->m_recving_from_cli)
|
if (_this->m_recving_from_cli)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
||||||
if (NULL == info || NULL == info->channel) {
|
if (NULL == cp) {
|
||||||
EXLOGE("[ssh] when receive client channel data, not found server channel.\n");
|
EXLOGE("[ssh] when receive client channel data, not found channel pair.\n");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
||||||
|
// if (NULL == info || NULL == info->channel) {
|
||||||
|
// EXLOGE("[ssh] when receive client channel data, not found server channel.\n");
|
||||||
|
// return SSH_ERROR;
|
||||||
|
// }
|
||||||
|
|
||||||
_this->m_recving_from_cli = true;
|
_this->m_recving_from_cli = true;
|
||||||
|
|
||||||
if (info->type == TS_SSH_CHANNEL_TYPE_SHELL)
|
if (cp->type == TS_SSH_CHANNEL_TYPE_SHELL)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_this->_process_ssh_command(TS_SSH_DATA_FROM_CLIENT, (ex_u8*)data, len);
|
_this->_process_ssh_command(&cp->rec, TP_SSH_CLIENT_SIDE, (ex_u8*)data, len);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -993,72 +984,84 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_this->_process_sftp_command((ex_u8*)data, len);
|
_this->_process_sftp_command(&cp->rec, (ex_u8*)data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if (is_stderr)
|
if (is_stderr)
|
||||||
ret = ssh_channel_write_stderr(info->channel, data, len);
|
ret = ssh_channel_write_stderr(cp->srv_channel, data, len);
|
||||||
else
|
else
|
||||||
ret = ssh_channel_write(info->channel, data, len);
|
ret = ssh_channel_write(cp->srv_channel, data, len);
|
||||||
if (ret <= 0)
|
|
||||||
EXLOGE("[ssh] send to server failed.\n");
|
if (ret == SSH_ERROR) {
|
||||||
|
EXLOGE("[ssh] send data(%dB) to server failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session));
|
||||||
|
}
|
||||||
|
|
||||||
_this->m_recving_from_cli = false;
|
_this->m_recving_from_cli = false;
|
||||||
|
|
||||||
return len;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshSession::_on_client_pty_win_change(ssh_session session, ssh_channel channel, int width, int height, int pxwidth, int pwheight, void *userdata) {
|
int SshSession::_on_client_pty_win_change(ssh_session session, ssh_channel channel, int width, int height, int pxwidth, int pwheight, void *userdata) {
|
||||||
EXLOGD("[ssh] client pty win size change to: (%d, %d)\n", width, height);
|
EXLOGD("[ssh] client pty win size change to: (%d, %d)\n", width, height);
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
|
||||||
if (NULL == info || NULL == info->channel) {
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
||||||
EXLOGE("[ssh] when client pty win change, not found server channel.\n");
|
if (NULL == cp) {
|
||||||
|
EXLOGE("[ssh] when client pty win change, not found channel pair.\n");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
_this->m_rec.record_win_size_change(width, height);
|
// TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
||||||
|
// if (NULL == info || NULL == info->channel) {
|
||||||
|
// EXLOGE("[ssh] when client pty win change, not found server channel.\n");
|
||||||
|
// return SSH_ERROR;
|
||||||
|
// }
|
||||||
|
|
||||||
return ssh_channel_change_pty_size(info->channel, width, height);
|
cp->rec.record_win_size_change(width, height);
|
||||||
|
|
||||||
|
return ssh_channel_change_pty_size(cp->srv_channel, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshSession::_on_client_channel_subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata) {
|
int SshSession::_on_client_channel_subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata) {
|
||||||
EXLOGD("[ssh] on_client_channel_subsystem_request(): %s\n", subsystem);
|
EXLOGD("[ssh] on_client_channel_subsystem_request(): %s\n", subsystem);
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
||||||
|
if (NULL == cp) {
|
||||||
|
EXLOGE("[ssh] when request channel subsystem, not found channel pair.\n");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// 目前只支持SFTP子系统
|
// 目前只支持SFTP子系统
|
||||||
if (strcmp(subsystem, "sftp") != 0) {
|
if (strcmp(subsystem, "sftp") != 0) {
|
||||||
EXLOGE("[ssh] support `sftp` subsystem only, but got `%s`.\n", subsystem);
|
EXLOGE("[ssh] support `sftp` subsystem only, but got `%s`.\n", subsystem);
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_UNSUPPORT_PROTOCOL;
|
cp->retcode = TP_SESS_STAT_ERR_UNSUPPORT_PROTOCOL;
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *srv_info = _this->_get_srv_channel(channel);
|
// TS_SSH_CHANNEL_INFO *srv_info = _this->_get_srv_channel(channel);
|
||||||
if (NULL == srv_info || NULL == srv_info->channel) {
|
// if (NULL == srv_info || NULL == srv_info->channel) {
|
||||||
EXLOGE("[ssh] when receive client channel subsystem request, not found server channel.\n");
|
// EXLOGE("[ssh] when receive client channel subsystem request, not found server channel.\n");
|
||||||
return SSH_ERROR;
|
// return SSH_ERROR;
|
||||||
}
|
// }
|
||||||
srv_info->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
// srv_info->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
||||||
|
//
|
||||||
|
// TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel);
|
||||||
|
// if (NULL == cli_info || NULL == cli_info->channel) {
|
||||||
|
// EXLOGE("[ssh] when client request shell, not found client channel.\n");
|
||||||
|
// return SSH_ERROR;
|
||||||
|
// }
|
||||||
|
// cli_info->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
||||||
|
cp->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
||||||
|
|
||||||
|
g_ssh_env.session_update(cp->db_id, TP_PROTOCOL_TYPE_SSH_SFTP, TP_SESS_STAT_STARTED);
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel);
|
|
||||||
if (NULL == cli_info || NULL == cli_info->channel) {
|
|
||||||
EXLOGE("[ssh] when client request shell, not found client channel.\n");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
cli_info->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
|
||||||
|
|
||||||
// 一个ssh会话打开了sftp通道,就将连接信息记录下来备用,随后这个session-id再次尝试连接时,我们允许其连接。
|
// 一个ssh会话打开了sftp通道,就将连接信息记录下来备用,随后这个session-id再次尝试连接时,我们允许其连接。
|
||||||
_this->_enter_sftp_mode();
|
//_this->_enter_sftp_mode();
|
||||||
|
|
||||||
return ssh_channel_request_subsystem(srv_info->channel, subsystem);
|
return ssh_channel_request_subsystem(cp->srv_channel, subsystem);
|
||||||
}
|
|
||||||
|
|
||||||
void SshSession::_enter_sftp_mode(void) {
|
|
||||||
if (!m_is_sftp) {
|
|
||||||
m_is_sftp = true;
|
|
||||||
m_proxy->add_sftp_session_info(m_sid, m_conn_ip, m_conn_port, m_acc_name, m_acc_secret, m_auth_type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshSession::_on_client_channel_exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata) {
|
int SshSession::_on_client_channel_exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata) {
|
||||||
|
@ -1071,15 +1074,21 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
//EXLOG_BIN((ex_u8*)data, len, "on_server_channel_data [is_stderr=%d]:", is_stderr);
|
//EXLOG_BIN((ex_u8*)data, len, "on_server_channel_data [is_stderr=%d]:", is_stderr);
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
|
// return 0 means data not processed, so this function will be called with this data again.
|
||||||
if (_this->m_recving_from_cli)
|
if (_this->m_recving_from_cli)
|
||||||
return 0;
|
return 0;
|
||||||
if (_this->m_recving_from_srv)
|
if (_this->m_recving_from_srv)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO *info = _this->_get_cli_channel(channel);
|
// TS_SSH_CHANNEL_INFO *info = _this->_get_cli_channel(channel);
|
||||||
if (NULL == info || NULL == info->channel) {
|
// if (NULL == info || NULL == info->channel) {
|
||||||
EXLOGE("[ssh] when receive server channel data, not found client channel.\n");
|
// EXLOGE("[ssh] when receive server channel data, not found client channel.\n");
|
||||||
_this->m_retcode = TP_SESS_STAT_ERR_INTERNAL;
|
// _this->m_retcode = TP_SESS_STAT_ERR_INTERNAL;
|
||||||
|
// return SSH_ERROR;
|
||||||
|
// }
|
||||||
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_SERVER_SIDE, channel);
|
||||||
|
if (NULL == cp) {
|
||||||
|
EXLOGE("[ssh] when receive server channel data, not found channel pair.\n");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,7 +1096,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
// TODO: hard code not good... :(
|
// TODO: hard code not good... :(
|
||||||
// 偶尔,某次操作会导致ssh_session->session_state为SSH_SESSION_STATE_ERROR
|
// 偶尔,某次操作会导致ssh_session->session_state为SSH_SESSION_STATE_ERROR
|
||||||
// 但是将其强制改为SSH_SESSION_STATE_AUTHENTICATED,后续操作仍然能成功(主要在向客户端发送第一包数据时)
|
// 但是将其强制改为SSH_SESSION_STATE_AUTHENTICATED,后续操作仍然能成功(主要在向客户端发送第一包数据时)
|
||||||
ex_u8* _t = (ex_u8*)(ssh_channel_get_session(info->channel));
|
ex_u8* _t = (ex_u8*)(ssh_channel_get_session(cp->cli_channel));
|
||||||
if (_t[1116] == 9) // SSH_SESSION_STATE_AUTHENTICATED = 8, SSH_SESSION_STATE_ERROR = 9
|
if (_t[1116] == 9) // SSH_SESSION_STATE_AUTHENTICATED = 8, SSH_SESSION_STATE_ERROR = 9
|
||||||
{
|
{
|
||||||
EXLOGW(" --- [ssh] hard code to fix client connect session error state.\n");
|
EXLOGW(" --- [ssh] hard code to fix client connect session error state.\n");
|
||||||
|
@ -1097,12 +1106,13 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
|
|
||||||
_this->m_recving_from_srv = true;
|
_this->m_recving_from_srv = true;
|
||||||
|
|
||||||
if (info->type == TS_SSH_CHANNEL_TYPE_SHELL && !is_stderr)
|
if (cp->type == TS_SSH_CHANNEL_TYPE_SHELL && !is_stderr)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_this->_process_ssh_command(TS_SSH_DATA_FROM_SERVER, (ex_u8*)data, len);
|
_this->_process_ssh_command(&cp->rec, TP_SSH_SERVER_SIDE, (ex_u8*)data, len);
|
||||||
_this->m_rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len);
|
//_this->m_rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len);
|
||||||
|
cp->rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -1118,7 +1128,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
{
|
{
|
||||||
_this->m_is_first_server_data = false;
|
_this->m_is_first_server_data = false;
|
||||||
|
|
||||||
if (info->type != TS_SSH_CHANNEL_TYPE_SFTP)
|
if (cp->type != TS_SSH_CHANNEL_TYPE_SFTP)
|
||||||
{
|
{
|
||||||
char buf[256] = { 0 };
|
char buf[256] = { 0 };
|
||||||
|
|
||||||
|
@ -1140,7 +1150,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
"\r\n",
|
"\r\n",
|
||||||
_this->m_conn_ip.c_str(),
|
_this->m_conn_ip.c_str(),
|
||||||
_this->m_conn_port, auth_mode
|
_this->m_conn_port, auth_mode
|
||||||
);
|
);
|
||||||
|
|
||||||
int buf_len = strlen(buf);
|
int buf_len = strlen(buf);
|
||||||
ex_bin _data;
|
ex_bin _data;
|
||||||
|
@ -1148,7 +1158,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
memcpy(&_data[0], buf, buf_len);
|
memcpy(&_data[0], buf, buf_len);
|
||||||
memcpy(&_data[buf_len], data, len);
|
memcpy(&_data[buf_len], data, len);
|
||||||
|
|
||||||
ret = ssh_channel_write(info->channel, &_data[0], _data.size());
|
ret = ssh_channel_write(cp->cli_channel, &_data[0], _data.size());
|
||||||
|
|
||||||
_this->m_recving_from_srv = false;
|
_this->m_recving_from_srv = false;
|
||||||
return len;
|
return len;
|
||||||
|
@ -1157,11 +1167,12 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (is_stderr)
|
if (is_stderr)
|
||||||
ret = ssh_channel_write_stderr(info->channel, data, len);
|
ret = ssh_channel_write_stderr(cp->cli_channel, data, len);
|
||||||
else
|
else
|
||||||
ret = ssh_channel_write(info->channel, data, len);
|
ret = ssh_channel_write(cp->cli_channel, data, len);
|
||||||
|
|
||||||
if (ret == SSH_ERROR) {
|
if (ret == SSH_ERROR) {
|
||||||
EXLOGE("[ssh] send data(%dB) to client failed (2). [%d][%s][%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_cli_session));
|
EXLOGE("[ssh] send data(%dB) to client failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session));
|
||||||
}
|
}
|
||||||
|
|
||||||
_this->m_recving_from_srv = false;
|
_this->m_recving_from_srv = false;
|
||||||
|
@ -1172,43 +1183,44 @@ void SshSession::_on_server_channel_close(ssh_session session, ssh_channel chann
|
||||||
EXLOGD("[ssh] on_server_channel_close().\n");
|
EXLOGD("[ssh] on_server_channel_close().\n");
|
||||||
|
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
TS_SSH_CHANNEL_INFO *info = _this->_get_cli_channel(channel);
|
|
||||||
if (NULL == info || NULL == info->channel) {
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_SERVER_SIDE, channel);
|
||||||
EXLOGW("[ssh] when server channel close, not found client channel, maybe it already closed.\n");
|
if (NULL == cp) {
|
||||||
|
EXLOGE("[ssh] when server channel close, not found channel pair.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ssh_channel_is_eof(channel))
|
// will the server-channel exist, the client-channel must exist too.
|
||||||
ssh_channel_send_eof(channel);
|
if (cp->cli_channel == NULL) {
|
||||||
if (!ssh_channel_is_closed(channel))
|
EXLOGE("[ssh] when server channel close, client-channel not exists.\n");
|
||||||
ssh_channel_close(channel);
|
}
|
||||||
//ssh_channel_free(channel);
|
else {
|
||||||
|
if (!ssh_channel_is_closed(cp->cli_channel)) {
|
||||||
|
if (!ssh_channel_is_eof(cp->cli_channel)) {
|
||||||
|
//EXLOGD("[ssh] when server channel close, send eof to client-channel.\n");
|
||||||
|
ssh_channel_send_eof(cp->cli_channel);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ssh_channel_is_eof(info->channel))
|
//EXLOGD("[ssh] when server channel close, close client-channel.\n");
|
||||||
ssh_channel_send_eof(info->channel);
|
ssh_channel_close(cp->cli_channel);
|
||||||
if (!ssh_channel_is_closed(info->channel))
|
|
||||||
ssh_channel_close(info->channel);
|
|
||||||
//ssh_channel_free(info->channel);
|
|
||||||
|
|
||||||
{
|
ssh_channel_free(cp->cli_channel);
|
||||||
ExThreadSmartLock locker(_this->m_lock);
|
cp->cli_channel = NULL;
|
||||||
|
|
||||||
ts_ssh_channel_map::iterator it = _this->m_channel_srv_cli.find(channel);
|
|
||||||
if (it != _this->m_channel_srv_cli.end()) {
|
|
||||||
delete it->second;
|
|
||||||
_this->m_channel_srv_cli.erase(it);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EXLOGW("[ssh] when remove server channel, it not in charge..\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
it = _this->m_channel_cli_srv.find(info->channel);
|
|
||||||
if (it != _this->m_channel_cli_srv.end()) {
|
|
||||||
delete it->second;
|
|
||||||
_this->m_channel_cli_srv.erase(it);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EXLOGW("[ssh] when remove server channel, not found client channel.\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ssh_channel_is_closed(cp->srv_channel)) {
|
||||||
|
if (!ssh_channel_is_eof(cp->srv_channel)) {
|
||||||
|
//EXLOGD("[ssh] when server channel close, send eof to server-channel.\n");
|
||||||
|
ssh_channel_send_eof(cp->srv_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
//EXLOGD("[ssh] when server channel close, close server-channel.\n");
|
||||||
|
ssh_channel_close(cp->srv_channel);
|
||||||
|
|
||||||
|
ssh_channel_free(cp->srv_channel);
|
||||||
|
cp->srv_channel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_this->_on_session_end(cp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,24 +17,33 @@
|
||||||
#define TS_SSH_CHANNEL_TYPE_SHELL 1
|
#define TS_SSH_CHANNEL_TYPE_SHELL 1
|
||||||
#define TS_SSH_CHANNEL_TYPE_SFTP 2
|
#define TS_SSH_CHANNEL_TYPE_SFTP 2
|
||||||
|
|
||||||
#define TS_SSH_DATA_FROM_CLIENT 1
|
#define TP_SSH_CLIENT_SIDE 1
|
||||||
#define TS_SSH_DATA_FROM_SERVER 2
|
#define TP_SSH_SERVER_SIDE 2
|
||||||
|
|
||||||
typedef struct TS_SSH_CHANNEL_INFO
|
|
||||||
{
|
|
||||||
int type; // TS_SSH_CHANNEL_TYPE_SHELL or TS_SSH_CHANNEL_TYPE_SFTP
|
|
||||||
ssh_channel channel;
|
|
||||||
|
|
||||||
TS_SSH_CHANNEL_INFO()
|
|
||||||
{
|
|
||||||
type = TS_SSH_CHANNEL_TYPE_UNKNOWN;
|
|
||||||
channel = NULL;
|
|
||||||
}
|
|
||||||
}TS_SSH_CHANNEL_INFO;
|
|
||||||
|
|
||||||
typedef std::map<ssh_channel, TS_SSH_CHANNEL_INFO*> ts_ssh_channel_map;
|
|
||||||
|
|
||||||
class SshProxy;
|
class SshProxy;
|
||||||
|
class SshSession;
|
||||||
|
|
||||||
|
class TP_SSH_CHANNEL_PAIR {
|
||||||
|
|
||||||
|
friend class SshSession;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TP_SSH_CHANNEL_PAIR();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int type; // TS_SSH_CHANNEL_TYPE_SHELL or TS_SSH_CHANNEL_TYPE_SFTP
|
||||||
|
ssh_channel cli_channel;
|
||||||
|
ssh_channel srv_channel;
|
||||||
|
|
||||||
|
TppSshRec rec;
|
||||||
|
|
||||||
|
int retcode;
|
||||||
|
int db_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<TP_SSH_CHANNEL_PAIR*> tp_channels;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SshSession : public ExThreadBase
|
class SshSession : public ExThreadBase
|
||||||
{
|
{
|
||||||
|
@ -44,9 +53,7 @@ public:
|
||||||
|
|
||||||
SshProxy* get_proxy(void) { return m_proxy; }
|
SshProxy* get_proxy(void) { return m_proxy; }
|
||||||
|
|
||||||
|
TP_SSH_CHANNEL_PAIR* _get_channel_pair(int channel_side, ssh_channel channel);
|
||||||
TS_SSH_CHANNEL_INFO* _get_cli_channel(ssh_channel srv_channel);
|
|
||||||
TS_SSH_CHANNEL_INFO* _get_srv_channel(ssh_channel cli_channel);
|
|
||||||
|
|
||||||
void client_ip(const char* ip) { m_client_ip = ip; }
|
void client_ip(const char* ip) { m_client_ip = ip; }
|
||||||
const char* client_ip(void) const { return m_client_ip.c_str(); }
|
const char* client_ip(void) const { return m_client_ip.c_str(); }
|
||||||
|
@ -56,24 +63,22 @@ public:
|
||||||
void save_record();
|
void save_record();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// 继承自 TppSessionBase
|
|
||||||
bool _on_session_begin(const TPP_CONNECT_INFO* info);
|
|
||||||
bool _on_session_end(void);
|
|
||||||
|
|
||||||
|
|
||||||
void _thread_loop(void);
|
void _thread_loop(void);
|
||||||
void _set_stop_flag(void);
|
void _set_stop_flag(void);
|
||||||
|
|
||||||
void _process_ssh_command(int from, const ex_u8* data, int len);
|
void _session_error(int err_code);
|
||||||
void _process_sftp_command(const ex_u8* data, int len);
|
bool _on_session_begin(TP_SSH_CHANNEL_PAIR* cp);
|
||||||
|
void _on_session_end(TP_SSH_CHANNEL_PAIR* cp);
|
||||||
|
|
||||||
|
|
||||||
|
void _process_ssh_command(TppSshRec* rec, int from, const ex_u8* data, int len);
|
||||||
|
void _process_sftp_command(TppSshRec* rec, const ex_u8* data, int len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _run(void);
|
void _run(void);
|
||||||
|
|
||||||
void _close_channels(void);
|
void _close_channels(void);
|
||||||
|
|
||||||
void _enter_sftp_mode(void);
|
|
||||||
|
|
||||||
static int _on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata);
|
static int _on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata);
|
||||||
static ssh_channel _on_new_channel_request(ssh_session session, void *userdata);
|
static ssh_channel _on_new_channel_request(ssh_session session, void *userdata);
|
||||||
static int _on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata);
|
static int _on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata);
|
||||||
|
@ -89,10 +94,6 @@ private:
|
||||||
static void _on_server_channel_close(ssh_session session, ssh_channel channel, void* userdata);
|
static void _on_server_channel_close(ssh_session session, ssh_channel channel, void* userdata);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_retcode;
|
|
||||||
int m_db_id;
|
|
||||||
|
|
||||||
TppSshRec m_rec;
|
|
||||||
|
|
||||||
SshProxy* m_proxy;
|
SshProxy* m_proxy;
|
||||||
ssh_session m_cli_session;
|
ssh_session m_cli_session;
|
||||||
|
@ -103,6 +104,8 @@ private:
|
||||||
ex_astr m_client_ip;
|
ex_astr m_client_ip;
|
||||||
ex_u16 m_client_port;
|
ex_u16 m_client_port;
|
||||||
|
|
||||||
|
TPP_CONNECT_INFO* m_conn_info;
|
||||||
|
|
||||||
ex_astr m_sid;
|
ex_astr m_sid;
|
||||||
ex_astr m_conn_ip;
|
ex_astr m_conn_ip;
|
||||||
ex_u16 m_conn_port;
|
ex_u16 m_conn_port;
|
||||||
|
@ -111,12 +114,10 @@ private:
|
||||||
int m_auth_type;
|
int m_auth_type;
|
||||||
|
|
||||||
bool m_is_first_server_data;
|
bool m_is_first_server_data;
|
||||||
bool m_is_sftp;
|
|
||||||
|
|
||||||
bool m_is_logon;
|
bool m_is_logon;
|
||||||
// Ò»¸össh_sessionÖпÉÒÔ´ò¿ª¶à¸össh_channel
|
// Ò»¸össh_sessionÖпÉÒÔ´ò¿ª¶à¸össh_channel
|
||||||
ts_ssh_channel_map m_channel_cli_srv; // 通过客户端通道查找服务端通道
|
tp_channels m_channels;
|
||||||
ts_ssh_channel_map m_channel_srv_cli; // 通过服务端通道查找客户端通道
|
|
||||||
|
|
||||||
bool m_have_error;
|
bool m_have_error;
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ $app.create_controls = function (cb_stack) {
|
||||||
var table_record_options = {
|
var table_record_options = {
|
||||||
dom_id: 'table-record',
|
dom_id: 'table-record',
|
||||||
data_source: {
|
data_source: {
|
||||||
type: 'ajax-post',
|
type: 'ajax-post'
|
||||||
url: '/audit/get-records',
|
,url: '/audit/get-records'
|
||||||
//exclude: {'state': [TP_SESS_STAT_RUNNING, TP_SESS_STAT_STARTED]}
|
//exclude: {'state': [TP_SESS_STAT_RUNNING, TP_SESS_STAT_STARTED]}
|
||||||
},
|
},
|
||||||
column_default: {sort: false, align: 'left'},
|
column_default: {sort: false, align: 'left'},
|
||||||
|
@ -42,15 +42,13 @@ $app.create_controls = function (cb_stack) {
|
||||||
{
|
{
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
// sort: true,
|
sort: true,
|
||||||
// sort_asc: false,
|
sort_asc: false,
|
||||||
fields: {id: 'id'}
|
fields: {id: 'id'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '会话ID',
|
title: '会话ID',
|
||||||
key: 'sid',
|
key: 'sid',
|
||||||
// sort: true,
|
|
||||||
// sort_asc: false,
|
|
||||||
render: 'sid',
|
render: 'sid',
|
||||||
width: 60,
|
width: 60,
|
||||||
fields: {sid: 'sid'}
|
fields: {sid: 'sid'}
|
||||||
|
@ -94,8 +92,8 @@ $app.create_controls = function (cb_stack) {
|
||||||
{
|
{
|
||||||
title: '开始时间',
|
title: '开始时间',
|
||||||
key: 'time_begin',
|
key: 'time_begin',
|
||||||
sort: true,
|
// sort: true,
|
||||||
sort_asc: false,
|
// sort_asc: false,
|
||||||
render: 'time_begin',
|
render: 'time_begin',
|
||||||
fields: {time_begin: 'time_begin'}
|
fields: {time_begin: 'time_begin'}
|
||||||
},
|
},
|
||||||
|
@ -162,19 +160,6 @@ $app.create_controls = function (cb_stack) {
|
||||||
$app.dom.btn_refresh_record.click(function () {
|
$app.dom.btn_refresh_record.click(function () {
|
||||||
$app.table_record.load_data();
|
$app.table_record.load_data();
|
||||||
});
|
});
|
||||||
// $app.dom.chkbox_host_select_all.click(function () {
|
|
||||||
// var _objects = $('#' + $app.table_record.dom_id + ' tbody').find('[data-check-box]');
|
|
||||||
// if ($(this).is(':checked')) {
|
|
||||||
// $.each(_objects, function (i, _obj) {
|
|
||||||
// $(_obj).prop('checked', true);
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// $.each(_objects, function (i, _obj) {
|
|
||||||
// $(_obj).prop('checked', false);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//$app.dom.btn_remove_record.click($app.on_btn_remove_record_click);
|
|
||||||
|
|
||||||
cb_stack.exec();
|
cb_stack.exec();
|
||||||
};
|
};
|
||||||
|
@ -273,9 +258,9 @@ $app.on_table_host_render_created = function (render) {
|
||||||
case 200:
|
case 200:
|
||||||
return '<span class="label label-success">SSH</span>';
|
return '<span class="label label-success">SSH</span>';
|
||||||
case 201:
|
case 201:
|
||||||
return '<span class="label label-success">SFTP</span>';
|
return '<span class="label label-info">SFTP</span>';
|
||||||
case 300:
|
case 300:
|
||||||
return '<span class="label label-success">TELNET</span>';
|
return '<span class="label label-warning">TELNET</span>';
|
||||||
default:
|
default:
|
||||||
return '<span class="label label-danger">未知</span>';
|
return '<span class="label label-danger">未知</span>';
|
||||||
}
|
}
|
||||||
|
@ -371,9 +356,9 @@ $app.on_table_host_render_created = function (render) {
|
||||||
|
|
||||||
if (fields.state >= TP_SESS_STAT_STARTED || fields.state === TP_SESS_STAT_ERR_RESET) {
|
if (fields.state >= TP_SESS_STAT_STARTED || fields.state === TP_SESS_STAT_ERR_RESET) {
|
||||||
if (fields.state === TP_SESS_STAT_STARTED) {
|
if (fields.state === TP_SESS_STAT_STARTED) {
|
||||||
ret.push('<a href="javascript:;" class="btn btn-sm btn-warning" data-action="sync" data-record-id="' + fields.id + '"><i class="fa fa-clone fa-fw"></i> 同步</a> ');
|
//ret.push('<a href="javascript:;" class="btn btn-sm btn-warning" data-action="sync" data-record-id="' + fields.id + '"><i class="fa fa-clone fa-fw"></i> 同步</a> ');
|
||||||
} else {
|
} else {
|
||||||
// if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_SSH_SFTP)
|
if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_SSH_SFTP)
|
||||||
ret.push('<a href="javascript:;" class="btn btn-sm btn-primary" data-action="replay" data-record-id="' + fields.id + '"><i class="fa fa-caret-square-o-right fa-fw"></i> 回放</a> ');
|
ret.push('<a href="javascript:;" class="btn btn-sm btn-primary" data-action="replay" data-record-id="' + fields.id + '"><i class="fa fa-caret-square-o-right fa-fw"></i> 回放</a> ');
|
||||||
}
|
}
|
||||||
if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_RDP_DESKTOP) {
|
if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_RDP_DESKTOP) {
|
||||||
|
@ -395,8 +380,6 @@ $app.on_table_host_header_created = function (header) {
|
||||||
|
|
||||||
// 表格内嵌过滤器的事件绑定在这时进行(也可以延期到整个表格创建完成时进行)
|
// 表格内嵌过滤器的事件绑定在这时进行(也可以延期到整个表格创建完成时进行)
|
||||||
header._table_ctrl.get_filter_ctrl('search').on_created();
|
header._table_ctrl.get_filter_ctrl('search').on_created();
|
||||||
// header._table_ctrl.get_filter_ctrl('role').on_created();
|
|
||||||
// header._table_ctrl.get_filter_ctrl('state').on_created();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$app.get_selected_record = function (tbl) {
|
$app.get_selected_record = function (tbl) {
|
||||||
|
|
|
@ -40,6 +40,8 @@ $app.req_record_data = function (record_id, offset) {
|
||||||
$app.req_record_data(record_id, g_data_offset);
|
$app.req_record_data(record_id, g_data_offset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
$app.dom.status.text("读取录像数据失败:" + tp_error_msg(ret.code));
|
||||||
|
$tp.notify_error('读取录像数据失败:' + tp_error_msg(ret.code, ret.message));
|
||||||
console.log('req_record_info error ', ret.code);
|
console.log('req_record_info error ', ret.code);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -76,16 +78,17 @@ $app.on_init = function (cb_stack) {
|
||||||
function (ret) {
|
function (ret) {
|
||||||
if (ret.code === TPE_OK) {
|
if (ret.code === TPE_OK) {
|
||||||
g_header = ret.data;
|
g_header = ret.data;
|
||||||
// console.log('header', g_header);
|
console.log('header', g_header);
|
||||||
|
|
||||||
$('#recorder-info').html(tp_format_datetime(g_header.start) + ': ' + g_header.user_name + '@' + g_header.client_ip + ' 访问 ' + g_header.account + '@' + g_header.conn_ip + ':' + g_header.conn_port);
|
$('#recorder-info').html(tp_format_datetime(g_header.start) + ': ' + g_header.user_name + '@' + g_header.client_ip + ' 访问 ' + g_header.account + '@' + g_header.conn_ip + ':' + g_header.conn_port);
|
||||||
|
|
||||||
$app.req_record_data(record_id, 0);
|
$app.req_record_data(record_id, 0);
|
||||||
|
|
||||||
g_current_time = 0;
|
g_current_time = 0;
|
||||||
setTimeout(init, 1000);
|
//setTimeout(init, 500);
|
||||||
|
init_and_play();
|
||||||
} else {
|
} else {
|
||||||
$tp.notify_error('请求录像数据失败:' + tp_error_msg(ret.code, ret.message));
|
$tp.notify_error('读取录像信息失败:' + tp_error_msg(ret.code, ret.message));
|
||||||
console.error('load init info error ', ret.code);
|
console.error('load init info error ', ret.code);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -161,9 +164,9 @@ $app.on_init = function (cb_stack) {
|
||||||
pause();
|
pause();
|
||||||
});
|
});
|
||||||
$app.dom.progress.mouseup(function () {
|
$app.dom.progress.mouseup(function () {
|
||||||
// console.log(g_current_time);
|
g_current_time = parseInt(g_header.time_used * $app.dom.progress.val() / 100);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
init();
|
init_and_play();
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
$app.dom.progress.mousemove(function () {
|
$app.dom.progress.mousemove(function () {
|
||||||
|
@ -178,7 +181,7 @@ $app.on_init = function (cb_stack) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function init() {
|
function init_and_play() {
|
||||||
if (_.isNull(g_console_term)) {
|
if (_.isNull(g_console_term)) {
|
||||||
g_console_term = new Terminal({
|
g_console_term = new Terminal({
|
||||||
cols: g_header.width,
|
cols: g_header.width,
|
||||||
|
@ -198,18 +201,22 @@ $app.on_init = function (cb_stack) {
|
||||||
g_console_term.reset(g_header.width, g_header.height);
|
g_console_term.reset(g_header.width, g_header.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(g_header.pkg_count === 0)
|
||||||
|
return;
|
||||||
|
|
||||||
$app.dom.progress.val(0);
|
$app.dom.progress.val(0);
|
||||||
$app.dom.status.text("正在播放");
|
// $app.dom.status.text("正在播放");
|
||||||
$app.dom.btn_play.children().removeClass().addClass('fa fa-pause').text(' 暂停');
|
$app.dom.btn_play.children().removeClass().addClass('fa fa-pause').text(' 暂停');
|
||||||
|
|
||||||
g_need_stop = false;
|
g_need_stop = false;
|
||||||
g_playing = true;
|
g_playing = true;
|
||||||
g_finish = false;
|
g_finish = false;
|
||||||
g_played_pkg_count = 0;
|
g_played_pkg_count = 0;
|
||||||
setTimeout(done, g_record_tick);
|
//setTimeout(do_play, g_record_tick);
|
||||||
|
do_play();
|
||||||
}
|
}
|
||||||
|
|
||||||
function done() {
|
function do_play() {
|
||||||
if (g_need_stop) {
|
if (g_need_stop) {
|
||||||
g_playing = false;
|
g_playing = false;
|
||||||
return;
|
return;
|
||||||
|
@ -217,7 +224,7 @@ $app.on_init = function (cb_stack) {
|
||||||
|
|
||||||
if (g_data.length <= g_played_pkg_count) {
|
if (g_data.length <= g_played_pkg_count) {
|
||||||
$app.dom.status.text("正在缓存数据...");
|
$app.dom.status.text("正在缓存数据...");
|
||||||
g_timer = setTimeout(done, g_record_tick);
|
g_timer = setTimeout(do_play, g_record_tick);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +293,7 @@ $app.on_init = function (cb_stack) {
|
||||||
$app.dom.btn_play.children().removeClass().addClass('fa fa-play').text(' 播放');
|
$app.dom.btn_play.children().removeClass().addClass('fa fa-play').text(' 播放');
|
||||||
} else {
|
} else {
|
||||||
if (!g_need_stop)
|
if (!g_need_stop)
|
||||||
g_timer = setTimeout(done, _record_tick);
|
g_timer = setTimeout(do_play, _record_tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +311,7 @@ $app.on_init = function (cb_stack) {
|
||||||
|
|
||||||
g_need_stop = false;
|
g_need_stop = false;
|
||||||
g_playing = true;
|
g_playing = true;
|
||||||
g_timer = setTimeout(done, g_record_tick);
|
g_timer = setTimeout(do_play, g_record_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pause() {
|
function pause() {
|
||||||
|
@ -320,7 +327,7 @@ $app.on_init = function (cb_stack) {
|
||||||
if (!_.isNull(g_timer))
|
if (!_.isNull(g_timer))
|
||||||
clearTimeout(g_timer);
|
clearTimeout(g_timer);
|
||||||
g_current_time = 0;
|
g_current_time = 0;
|
||||||
init();
|
init_and_play();
|
||||||
}
|
}
|
||||||
|
|
||||||
cb_stack.exec();
|
cb_stack.exec();
|
||||||
|
|
|
@ -32,7 +32,7 @@ $app.create_controls = function (cb_stack) {
|
||||||
// title: '<input type="checkbox" id="user-list-select-all" value="">',
|
// title: '<input type="checkbox" id="user-list-select-all" value="">',
|
||||||
title: '',
|
title: '',
|
||||||
key: 'chkbox',
|
key: 'chkbox',
|
||||||
sort: false,
|
//sort: false,
|
||||||
width: 36,
|
width: 36,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: 'make_check_box',
|
render: 'make_check_box',
|
||||||
|
@ -41,6 +41,8 @@ $app.create_controls = function (cb_stack) {
|
||||||
{
|
{
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
|
sort: true,
|
||||||
|
sort_asc: false,
|
||||||
fields: {id: 'id'}
|
fields: {id: 'id'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,10 +90,16 @@ class RpcHandler(TPBaseJsonHandler):
|
||||||
return self.write_json(TPE_OK, data={'rid': record_id})
|
return self.write_json(TPE_OK, data={'rid': record_id})
|
||||||
|
|
||||||
def _session_update(self, param):
|
def _session_update(self, param):
|
||||||
if 'rid' not in param or 'code' not in param:
|
try:
|
||||||
|
rid = param['rid']
|
||||||
|
protocol_sub_type = param['protocol_sub_type']
|
||||||
|
code = param['code']
|
||||||
|
except:
|
||||||
|
return self.write_json(TPE_PARAM)
|
||||||
|
if 'rid' not in param or 'code' not in param :
|
||||||
return self.write_json(TPE_PARAM)
|
return self.write_json(TPE_PARAM)
|
||||||
|
|
||||||
if not record.session_update(param['rid'], param['code']):
|
if not record.session_update(rid, protocol_sub_type, code):
|
||||||
return self.write_json(TPE_DATABASE, 'can not write database.')
|
return self.write_json(TPE_DATABASE, 'can not write database.')
|
||||||
else:
|
else:
|
||||||
return self.write_json(TPE_OK)
|
return self.write_json(TPE_OK)
|
||||||
|
|
|
@ -293,9 +293,9 @@ def session_begin(sid, user_id, host_id, acc_id, user_username, acc_username, ho
|
||||||
return TPE_OK, record_id
|
return TPE_OK, record_id
|
||||||
|
|
||||||
|
|
||||||
def session_update(record_id, state):
|
def session_update(record_id, protocol_sub_type, state):
|
||||||
db = get_db()
|
db = get_db()
|
||||||
sql = 'UPDATE `{}record` SET state={} WHERE id={};'.format(db.table_prefix, int(state), int(record_id))
|
sql = 'UPDATE `{}record` SET protocol_sub_type={}, state={} WHERE id={};'.format(db.table_prefix, protocol_sub_type, int(state), int(record_id))
|
||||||
return db.exec(sql)
|
return db.exec(sql)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue