Merge remote-tracking branch 'remotes/origin/dev'

pull/32/merge
Apex Liu 2017-06-07 17:34:35 +08:00
commit a91abb3f02
17 changed files with 522 additions and 205 deletions

View File

@ -1,8 +1,7 @@
#!/bin/bash #!/bin/bash
PATH_ROOT=$(cd "$(dirname "$0")"; pwd) PATH_ROOT=$(cd "$(dirname "$0")"; pwd)
PYEXEC=${PATH_ROOT}/external/linux/release/bin/python3.4
PYSTATIC=${PATH_ROOT}/external/linux/release/lib/libpython3.4m.a
function on_error() function on_error()
{ {
@ -14,6 +13,11 @@ function on_error()
exit 1 exit 1
} }
function build_linux
{
PYEXEC=${PATH_ROOT}/external/linux/release/bin/python3.4
PYSTATIC=${PATH_ROOT}/external/linux/release/lib/libpython3.4m.a
if [ ! -f "${PYSTATIC}" ]; then if [ ! -f "${PYSTATIC}" ]; then
echo "python static not found, now build it..." echo "python static not found, now build it..."
"${PATH_ROOT}/build/build-py-static.sh" "${PATH_ROOT}/build/build-py-static.sh"
@ -25,3 +29,18 @@ fi
${PYEXEC} -B "${PATH_ROOT}/build/build.py" $@ ${PYEXEC} -B "${PATH_ROOT}/build/build.py" $@
}
function build_macos
{
python3 -B "${PATH_ROOT}/build/build.py" $@
}
SYSTEM=`uname -s`
if [ $SYSTEM = "Linux" ] ; then
build_linux
elif [ $SYSTEM = "Darwin" ] ; then
build_macos
else
echo "Unsupported platform."
fi

View File

@ -514,11 +514,276 @@ class BuilderLinux(BuilderBase):
utils.remove(_path) utils.remove(_path)
class BuilderMacOS(BuilderBase):
def __init__(self):
super().__init__()
def _init_path(self):
self.PATH_TMP = os.path.join(PATH_EXTERNAL, 'macos', 'tmp')
self.PATH_RELEASE = os.path.join(PATH_EXTERNAL, 'macos', 'release')
self.OPENSSL_PATH_SRC = os.path.join(self.PATH_TMP, 'openssl-{}'.format(env.ver_openssl))
self.LIBUV_PATH_SRC = os.path.join(self.PATH_TMP, 'libuv-{}'.format(env.ver_libuv))
self.MBEDTLS_PATH_SRC = os.path.join(self.PATH_TMP, 'mbedtls-mbedtls-{}'.format(env.ver_mbedtls))
self.LIBSSH_PATH_SRC = os.path.join(self.PATH_TMP, 'libssh-{}'.format(env.ver_libssh))
self.SQLITE_PATH_SRC = os.path.join(self.PATH_TMP, 'sqlite-autoconf-{}'.format(env.ver_sqlite))
self.JSONCPP_PATH_SRC = os.path.join(PATH_EXTERNAL, 'jsoncpp')
self.MONGOOSE_PATH_SRC = os.path.join(PATH_EXTERNAL, 'mongoose')
if not os.path.exists(self.PATH_TMP):
utils.makedirs(self.PATH_TMP)
def _build_jsoncpp(self, file_name):
cc.n('prepare jsoncpp source code...', end='')
if not os.path.exists(self.JSONCPP_PATH_SRC):
cc.v('')
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, PATH_EXTERNAL))
os.rename(os.path.join(PATH_EXTERNAL, 'jsoncpp-{}'.format(env.ver_jsoncpp)), self.JSONCPP_PATH_SRC)
else:
cc.w('already exists, skip.')
def _build_mongoose(self, file_name):
cc.n('prepare mongoose source code...', end='')
if not os.path.exists(self.MONGOOSE_PATH_SRC):
cc.v('')
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, PATH_EXTERNAL))
os.rename(os.path.join(PATH_EXTERNAL, 'mongoose-{}'.format(env.ver_mongoose)), self.MONGOOSE_PATH_SRC)
else:
cc.w('already exists, skip.')
def _build_openssl(self, file_name):
pass # we do not need build openssl anymore, because first time run build.sh we built Python, it include openssl.
# if not os.path.exists(self.OPENSSL_PATH_SRC):
# os.system('tar -zxvf "{}/{}" -C "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
#
# cc.n('build openssl static...')
# if os.path.exists(os.path.join(self.PATH_RELEASE, 'lib', 'libssl.a')):
# cc.w('already exists, skip.')
# return
#
# old_p = os.getcwd()
# os.chdir(self.OPENSSL_PATH_SRC)
# #os.system('./config --prefix={} --openssldir={}/openssl no-zlib no-shared'.format(self.PATH_RELEASE, self.PATH_RELEASE))
# os.system('./config --prefix={} --openssldir={}/openssl -fPIC no-zlib no-shared'.format(self.PATH_RELEASE, self.PATH_RELEASE))
# os.system('make')
# os.system('make install')
# os.chdir(old_p)
def _build_libuv(self, file_name):
cc.w('build libuv...skip')
return
if not os.path.exists(self.LIBUV_PATH_SRC):
# os.system('tar -zxvf "{}/{}" -C "{}"'.format(PATH_DOWNLOAD, file_name, PATH_TMP))
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
cc.n('build libuv...', end='')
if os.path.exists(os.path.join(self.PATH_RELEASE, 'lib', 'libuv.a')):
cc.w('already exists, skip.')
return
cc.v('')
# we need following...
# apt-get install autoconf aptitude libtool gcc-c++
old_p = os.getcwd()
os.chdir(self.LIBUV_PATH_SRC)
os.system('sh autogen.sh')
os.system('./configure --prefix={} --with-pic'.format(self.PATH_RELEASE))
os.system('make')
os.system('make install')
os.chdir(old_p)
def _build_mbedtls(self, file_name):
if not os.path.exists(self.MBEDTLS_PATH_SRC):
# os.system('tar -zxvf "{}/{}" -C "{}"'.format(PATH_DOWNLOAD, file_name, PATH_TMP))
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
cc.n('build mbedtls...', end='')
if os.path.exists(os.path.join(self.PATH_RELEASE, 'lib', 'libmbedtls.a')):
cc.w('already exists, skip.')
return
cc.v('')
# fix the Makefile
mkfile = os.path.join(self.MBEDTLS_PATH_SRC, 'Makefile')
f = open(mkfile)
fl = f.readlines()
f.close()
fixed = False
for i in range(len(fl)):
x = fl[i].split('=')
if x[0] == 'DESTDIR':
fl[i] = 'DESTDIR={}\n'.format(self.PATH_RELEASE)
fixed = True
break
if not fixed:
cc.e('can not fix Makefile of mbedtls.')
return
f = open(mkfile, 'w')
f.writelines(fl)
f.close()
# # fix config.h
# mkfile = os.path.join(self.MBEDTLS_PATH_SRC, 'include', 'mbedtls', 'config.h')
# f = open(mkfile)
# fl = f.readlines()
# f.close()
#
# for i in range(len(fl)):
# if fl[i].find('#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED') >= 0:
# fl[i] = '//#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED\n'
# elif fl[i].find('#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED') >= 0:
# fl[i] = '//#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED\n'
# elif fl[i].find('#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED') >= 0:
# fl[i] = '//#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED\n'
# elif fl[i].find('#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED') >= 0:
# fl[i] = '//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED\n'
# elif fl[i].find('#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED') >= 0:
# fl[i] = '//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED\n'
# elif fl[i].find('#define MBEDTLS_SELF_TEST') >= 0:
# fl[i] = '//#define MBEDTLS_SELF_TEST\n'
# elif fl[i].find('#define MBEDTLS_SSL_RENEGOTIATION') >= 0:
# fl[i] = '//#define MBEDTLS_SSL_RENEGOTIATION\n'
# elif fl[i].find('#define MBEDTLS_ECDH_C') >= 0:
# fl[i] = '//#define MBEDTLS_ECDH_C\n'
# elif fl[i].find('#define MBEDTLS_ECDSA_C') >= 0:
# fl[i] = '//#define MBEDTLS_ECDSA_C\n'
# elif fl[i].find('#define MBEDTLS_ECP_C') >= 0:
# fl[i] = '//#define MBEDTLS_ECP_C\n'
# elif fl[i].find('#define MBEDTLS_NET_C') >= 0:
# fl[i] = '//#define MBEDTLS_NET_C\n'
#
# elif fl[i].find('#define MBEDTLS_RSA_NO_CRT') >= 0:
# fl[i] = '#define MBEDTLS_RSA_NO_CRT\n'
# elif fl[i].find('#define MBEDTLS_SSL_PROTO_SSL3') >= 0:
# fl[i] = '#define MBEDTLS_SSL_PROTO_SSL3\n'
#
# f = open(mkfile, 'w')
# f.writelines(fl)
# f.close()
# fix source file
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'include', 'mbedtls', 'config.h'))
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'include', 'mbedtls'), os.path.join(self.MBEDTLS_PATH_SRC, 'include', 'mbedtls'), 'config.h')
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'library', 'rsa.c'))
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'library'), os.path.join(self.MBEDTLS_PATH_SRC, 'library'), 'rsa.c')
old_p = os.getcwd()
os.chdir(self.MBEDTLS_PATH_SRC)
os.system('make CFLAGS="-fPIC" lib')
os.system('make install')
os.chdir(old_p)
def _build_libssh(self, file_name):
if not os.path.exists(self.LIBSSH_PATH_SRC):
# os.system('tar -zxvf "{}/{}" -C "{}"'.format(PATH_DOWNLOAD, file_name, PATH_TMP))
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
# os.rename(os.path.join(self.PATH_TMP, 'master'), os.path.join(self.PATH_TMP, 'libssh-{}'.format(LIBSSH_VER)))
cc.n('build libssh...', end='')
if os.path.exists(os.path.join(self.PATH_RELEASE, 'lib', 'libssh.a')) and os.path.exists(os.path.join(self.PATH_RELEASE, 'lib', 'libssh_threads.a')):
cc.w('already exists, skip.')
return
cc.v('')
build_path = os.path.join(self.LIBSSH_PATH_SRC, 'build')
# utils.makedirs(build_path)
# here is a bug in cmake v2.8.11 (default on ubuntu14), in FindOpenSSL.cmake,
# it parse opensslv.h, use regex like this:
# REGEX "^#define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
# but in openssl-1.0.2h, the version define line is:
# # define OPENSSL_VERSION_NUMBER 0x1000208fL
# notice there is a space char between # and define, so find openssl always fail.
# old_p = os.getcwd()
# os.chdir(build_path)
# cmd = 'cmake' \
# ' -DCMAKE_INSTALL_PREFIX={}' \
# ' -D_OPENSSL_VERSION={}' \
# ' -DOPENSSL_INCLUDE_DIR={}/include' \
# ' -DOPENSSL_LIBRARIES={}/lib' \
# ' -DCMAKE_BUILD_TYPE=Release' \
# ' -DWITH_GSSAPI=OFF' \
# ' -DWITH_ZLIB=OFF' \
# ' -DWITH_STATIC_LIB=ON' \
# ' -DWITH_PCAP=OFF' \
# ' -DWITH_EXAMPLES=OFF' \
# ' -DWITH_NACL=OFF' \
# ' ..'.format(self.PATH_RELEASE, OPENSSL_VER, self.PATH_RELEASE, self.PATH_RELEASE)
# cc.n(cmd)
# os.system(cmd)
# # os.system('make ssh_static ssh_threads_static')
# os.system('make ssh_static')
# # os.system('make install')
# os.chdir(old_p)
cmake_define = ' -DCMAKE_INSTALL_PREFIX={}' \
' -D_OPENSSL_VERSION={}' \
' -DOPENSSL_INCLUDE_DIR={}/include' \
' -DOPENSSL_LIBRARIES={}/lib' \
' -DWITH_GSSAPI=OFF' \
' -DWITH_ZLIB=OFF' \
' -DWITH_STATIC_LIB=ON' \
' -DWITH_PCAP=OFF' \
' -DWITH_TESTING=OFF' \
' -DWITH_CLIENT_TESTING=OFF' \
' -DWITH_EXAMPLES=OFF' \
' -DWITH_BENCHMARKS=OFF' \
' -DWITH_NACL=OFF' \
' ..'.format(self.PATH_RELEASE, env.ver_openssl_number, self.PATH_RELEASE, self.PATH_RELEASE)
try:
utils.cmake(build_path, 'Release', False, cmake_define)
except:
pass
# because make install will fail because we can not disable ssh_shared target,
# so we copy necessary files ourselves.
utils.ensure_file_exists(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src', 'libssh.a'))
utils.ensure_file_exists(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src', 'threads', 'libssh_threads.a'))
utils.copy_file(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src'), os.path.join(self.PATH_RELEASE, 'lib'), 'libssh.a')
utils.copy_file(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src', 'threads'), os.path.join(self.PATH_RELEASE, 'lib'), 'libssh_threads.a')
utils.copy_ex(os.path.join(self.LIBSSH_PATH_SRC, 'include'), os.path.join(self.PATH_RELEASE, 'include'), 'libssh')
def _build_sqlite(self, file_name):
if not os.path.exists(self.SQLITE_PATH_SRC):
os.system('tar -zxvf "{}/{}" -C "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
cc.n('build sqlite static...', end='')
if os.path.exists(os.path.join(self.PATH_RELEASE, 'lib', 'libsqlite3.a')):
cc.w('already exists, skip.')
return
cc.v('')
old_p = os.getcwd()
os.chdir(self.SQLITE_PATH_SRC)
os.system('./configure --prefix={}'.format(self.PATH_RELEASE))
os.system('make')
os.system('make install')
os.chdir(old_p)
def fix_output(self):
# remove .so files, otherwise will link to .so but not .a in default.
# rm = ['libsqlite3.la', 'libsqlite3.so.0', 'libsqlite3.so', 'libsqlite3.so.0.8.6', 'libuv.la', 'libuv.so.1', 'libuv.so', 'libuv.so.1.0.0']
rm = ['libuv.la', 'libuv.so.1', 'libuv.so', 'libuv.so.1.0.0']
for i in rm:
_path = os.path.join(self.PATH_RELEASE, 'lib', i)
if os.path.exists(_path):
utils.remove(_path)
def gen_builder(dist): def gen_builder(dist):
if dist == 'windows': if dist == 'windows':
builder = BuilderWin() builder = BuilderWin()
elif dist == 'linux': elif dist == 'linux':
builder = BuilderLinux() builder = BuilderLinux()
elif dist == 'macos':
builder = BuilderMacOS()
else: else:
raise RuntimeError('unsupported platform.') raise RuntimeError('unsupported platform.')

View File

@ -1,3 +1,3 @@
# -*- coding: utf8 -*- # -*- coding: utf8 -*-
VER_TELEPORT_SERVER = "2.2.9.3" VER_TELEPORT_SERVER = "2.2.10.1"
VER_TELEPORT_ASSIST = "2.2.6.1" VER_TELEPORT_ASSIST = "2.2.6.1"

Binary file not shown.

View File

@ -1,6 +1,6 @@
#ifndef __TS_SERVER_VER_H__ #ifndef __TS_SERVER_VER_H__
#define __TS_SERVER_VER_H__ #define __TS_SERVER_VER_H__
#define TP_SERVER_VER L"2.2.9.3" #define TP_SERVER_VER L"2.2.10.1"
#endif // __TS_SERVER_VER_H__ #endif // __TS_SERVER_VER_H__

View File

@ -249,7 +249,8 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
// 因为是从sftp会话得来的登录数据因此限制本会话只能用于sftp不允许再使用shell了。 // 因为是从sftp会话得来的登录数据因此限制本会话只能用于sftp不允许再使用shell了。
_this->_enter_sftp_mode(); _this->_enter_sftp_mode();
} else { }
else {
_this->m_server_ip = sess_info->host_ip; _this->m_server_ip = sess_info->host_ip;
_this->m_server_port = sess_info->host_port; _this->m_server_port = sess_info->host_port;
_this->m_auth_mode = sess_info->auth_mode; _this->m_auth_mode = sess_info->auth_mode;
@ -291,13 +292,13 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
if (_this->m_auth_mode != TS_AUTH_MODE_NONE) if (_this->m_auth_mode != TS_AUTH_MODE_NONE)
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_USER, _this->m_user_name.c_str()); ssh_options_set(_this->m_srv_session, SSH_OPTIONS_USER, _this->m_user_name.c_str());
#ifdef EX_DEBUG //#ifdef EX_DEBUG
// int _timeout_us = 500000000; // 5 sec. // // int _timeout_us = 500000000; // 5 sec.
// // ssh_options_set(_this->m_srv_session, SSH_OPTIONS_TIMEOUT_USEC, &_timeout_us);
//#else
// int _timeout_us = 10000000; // 10 sec.
// ssh_options_set(_this->m_srv_session, SSH_OPTIONS_TIMEOUT_USEC, &_timeout_us); // ssh_options_set(_this->m_srv_session, SSH_OPTIONS_TIMEOUT_USEC, &_timeout_us);
#else //#endif
int _timeout_us = 10000000; // 10 sec.
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_TIMEOUT_USEC, &_timeout_us);
#endif
int rc = 0; int rc = 0;
rc = ssh_connect(_this->m_srv_session); rc = ssh_connect(_this->m_srv_session);
@ -308,119 +309,127 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
return SSH_AUTH_ERROR; return SSH_AUTH_ERROR;
} }
// 检查服务端支持的认证协议 // // 检查服务端支持的认证协议
ssh_userauth_none(_this->m_srv_session, NULL); // rc = ssh_userauth_none(_this->m_srv_session, NULL);
int auth_methods = ssh_userauth_list(_this->m_srv_session, NULL); // 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);
// _this->m_have_error = true;
// _this->m_retcode = SESS_STAT_ERR_AUTH_DENIED;
// return SSH_AUTH_ERROR;
// }
// // int auth_methods = ssh_userauth_list(_this->m_srv_session, NULL);
// const char* banner = ssh_get_issue_banner(_this->m_srv_session);
// if (NULL != banner) {
// EXLOGE("[ssh] issue banner: %s\n", banner);
// }
if (_this->m_auth_mode == TS_AUTH_MODE_PASSWORD) { if (_this->m_auth_mode == TS_AUTH_MODE_PASSWORD) {
if (auth_methods & SSH_AUTH_METHOD_PASSWORD) { // 优先尝试交互式登录SSHv2推荐
rc = ssh_userauth_password(_this->m_srv_session, NULL, _this->m_user_auth.c_str()); rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL);
if (rc != SSH_AUTH_SUCCESS) { while(rc == SSH_AUTH_INFO) {
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); int nprompts = ssh_userauth_kbdint_getnprompts(_this->m_srv_session);
if(0 == nprompts) {
rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL);
continue;
}
for (int iprompt = 0; iprompt < nprompts; ++iprompt) {
char echo = 0;
const char* prompt = ssh_userauth_kbdint_getprompt(_this->m_srv_session, iprompt, &echo);
EXLOGV("[ssh] interactive login prompt: %s\n", prompt);
rc = ssh_userauth_kbdint_setanswer(_this->m_srv_session, iprompt, _this->m_user_auth.c_str());
if (rc < 0) {
EXLOGE("[ssh] invalid password for interactive 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_DENIED; return SSH_AUTH_ERROR;
} }
} }
else if (auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
bool is_login = false;
for (;;) {
rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL); rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL);
if (rc != SSH_AUTH_INFO)
break;
if(ssh_userauth_kbdint_getnprompts(_this->m_srv_session) != 1)
break;
rc = ssh_userauth_kbdint_setanswer(_this->m_srv_session, 0, _this->m_user_auth.c_str());
if (rc < 0)
break;
// 有时候服务端会再发一个空的提示来完成交互
rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL);
if (rc == SSH_AUTH_INFO) {
if (ssh_userauth_kbdint_getnprompts(_this->m_srv_session) != 0)
break;
rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL);
if (rc < 0)
break;
} }
if(rc == SSH_AUTH_SUCCESS) if (rc == SSH_AUTH_SUCCESS) {
is_login = true; EXLOGW("[ssh] logon with keyboard interactive mode.\n");
break; _this->m_is_logon = true;
} return SSH_AUTH_SUCCESS;
if (!is_login) {
EXLOGE("[ssh] invalid password for keyboard-interactive 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_retcode = SESS_STAT_ERR_AUTH_DENIED;
return SSH_AUTH_DENIED;
}
} }
else { else {
EXLOGE("[ssh] real SSH server [%s:%d] does not support password or keyboard-interactive login.\n", _this->m_server_ip.c_str(), _this->m_server_port); EXLOGD("[ssh] failed to login with keyboard interactive mode, got %d, try password mode.\n", rc);
}
// 不支持交互式登录,则尝试密码方式
rc = ssh_userauth_password(_this->m_srv_session, NULL, _this->m_user_auth.c_str());
if (rc == SSH_AUTH_SUCCESS) {
EXLOGW("[ssh] logon with password mode.\n");
_this->m_is_logon = true;
return SSH_AUTH_SUCCESS;
}
else {
EXLOGD("[ssh] failed to login with password mode, got %d.\n", rc);
}
EXLOGE("[ssh] can not use password mode or interactive mode ot 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_DENIED; return SSH_AUTH_ERROR;
}
} }
else if (_this->m_auth_mode == TS_AUTH_MODE_PRIVATE_KEY) { else if (_this->m_auth_mode == TS_AUTH_MODE_PRIVATE_KEY) {
if (auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
ssh_key key = NULL; ssh_key key = NULL;
if (SSH_OK != ssh_pki_import_privkey_base64(_this->m_user_auth.c_str(), NULL, NULL, NULL, &key)) { if (SSH_OK != ssh_pki_import_privkey_base64(_this->m_user_auth.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 = SESS_STAT_ERR_BAD_SSH_KEY; _this->m_retcode = SESS_STAT_ERR_BAD_SSH_KEY;
return SSH_AUTH_DENIED; return SSH_AUTH_ERROR;
} }
rc = ssh_userauth_publickey(_this->m_srv_session, NULL, key); rc = ssh_userauth_publickey(_this->m_srv_session, NULL, key);
if (rc != SSH_OK) {
ssh_key_free(key); ssh_key_free(key);
EXLOGE("[ssh] invalid private-key for 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_retcode = SESS_STAT_ERR_AUTH_DENIED;
return SSH_AUTH_DENIED;
}
ssh_key_free(key); if (rc == SSH_AUTH_SUCCESS) {
EXLOGW("[ssh] logon with public-key mode.\n");
_this->m_is_logon = true;
return SSH_AUTH_SUCCESS;
} }
else { else {
EXLOGE("[ssh] real SSH server [%s:%d] does not support public key login.\n", _this->m_server_ip.c_str(), _this->m_server_port); EXLOGE("[ssh] failed to use private-key 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_DENIED; return SSH_AUTH_ERROR;
} }
} }
else if (_this->m_auth_mode == TS_AUTH_MODE_NONE) else if (_this->m_auth_mode == TS_AUTH_MODE_NONE) {
{ return SSH_AUTH_ERROR;
// do nothing.
return SSH_AUTH_DENIED;
} }
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 = SESS_STAT_ERR_AUTH_DENIED; _this->m_retcode = SESS_STAT_ERR_AUTH_DENIED;
return SSH_AUTH_DENIED; return SSH_AUTH_ERROR;
} }
_this->m_is_logon = true;
return SSH_AUTH_SUCCESS;
} }
ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userdata) { ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userdata) {
// 客户端尝试打开一个通道(然后才能通过这个通道发控制命令或者收发数据) // 客户端尝试打开一个通道(然后才能通过这个通道发控制命令或者收发数据)
EXLOGV("[ssh] allocated session channel\n"); EXLOGV("[ssh] client open channel\n");
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) {
EXLOGE("[ssh] can not create channel for client.\n");
return NULL;
}
ssh_set_channel_callbacks(cli_channel, &_this->m_cli_channel_cb); ssh_set_channel_callbacks(cli_channel, &_this->m_cli_channel_cb);
// 我们也要向真正的服务器申请打开一个通道,来进行转发 // 我们也要向真正的服务器申请打开一个通道,来进行转发
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) {
EXLOGE("[ssh] can not create channel for server.\n");
return NULL;
}
if (ssh_channel_open_session(srv_channel)) { if (ssh_channel_open_session(srv_channel)) {
EXLOGE("[ssh] error opening channel to real server: %s\n", ssh_get_error(session)); EXLOGE("[ssh] error opening channel to real server: %s\n", ssh_get_error(session));
ssh_channel_free(cli_channel); ssh_channel_free(cli_channel);
@ -443,6 +452,7 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd
_this->m_channel_srv_cli.insert(std::make_pair(srv_channel, cli_info)); _this->m_channel_srv_cli.insert(std::make_pair(srv_channel, cli_info));
} }
EXLOGD("[ssh] channel for client and server created.\n");
return cli_channel; return cli_channel;
} }
@ -856,17 +866,8 @@ int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channe
SshSession *_this = (SshSession *)userdata; SshSession *_this = (SshSession *)userdata;
if (_this->m_is_sftp) { if (_this->m_is_sftp) {
EXLOGE("[ssh] try to request shell on a sftp-session.\n"); EXLOGE("[ssh] request shell on a sftp-session is denied.\n");
// char buf[2048] = { 0 }; return SSH_ERROR;
// snprintf(buf, sizeof(buf),
// "\r\n\r\n"\
// "!! ERROR !!\r\n"\
// "Session-ID '%s' has been used for SFTP.\r\n"\
// "\r\n", _this->m_sid.c_str()
// );
// ssh_channel_write(channel, buf, strlen(buf));
//
return 1;
} }
EXLOGD("[ssh] client request shell\n"); EXLOGD("[ssh] client request shell\n");
@ -874,17 +875,20 @@ int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channe
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 client request shell, not found server channel.\n"); EXLOGE("[ssh] when client request shell, not found server channel.\n");
return 1; return SSH_ERROR;
} }
srv_info->type = TS_SSH_CHANNEL_TYPE_SHELL; srv_info->type = TS_SSH_CHANNEL_TYPE_SHELL;
TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel); TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel);
if (NULL == cli_info || NULL == cli_info->channel) { if (NULL == cli_info || NULL == cli_info->channel) {
EXLOGE("[ssh] when client request shell, not found client channel.\n"); EXLOGE("[ssh] when client request shell, not found client channel.\n");
return 1; return SSH_ERROR;
} }
cli_info->type = TS_SSH_CHANNEL_TYPE_SHELL; cli_info->type = TS_SSH_CHANNEL_TYPE_SHELL;
// 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.
// I have no idea how to fix it... :(
return ssh_channel_request_shell(srv_info->channel); return ssh_channel_request_shell(srv_info->channel);
} }
@ -1109,12 +1113,8 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
" - authroized by %s\r\n"\ " - authroized by %s\r\n"\
"=============================================\r\n"\ "=============================================\r\n"\
"\r\n", "\r\n",
// \
// "\033]0;tpssh://%s\007\r\n",
_this->m_server_ip.c_str(), _this->m_server_ip.c_str(),
_this->m_server_port, auth_mode _this->m_server_port, auth_mode
// ,
// _this->m_server_ip.c_str()
); );
int buf_len = strlen(buf); int buf_len = strlen(buf);
@ -1123,11 +1123,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);
// 注意,这里虽然可以改变窗口(或者标签页)的标题,但是因为这是服务端发回的第一个包,后面服务端可能还会发类似的包(仅一次)来改变标题
// 导致窗口标题又被改变,因此理论上应该解析服务端发回的包,如果包含上述格式的,需要替换一次。
//_write(info->channel, buf, strlen(buf));
ret = ssh_channel_write(info->channel, &_data[0], _data.size()); ret = ssh_channel_write(info->channel, &_data[0], _data.size());
//EXLOGD("--- first send to client : %d %d %d\n", _data.size(), ret, len);
_this->m_recving_from_srv = false; _this->m_recving_from_srv = false;
return len; return len;
@ -1143,8 +1139,6 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
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 (2). [%d][%s][%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_cli_session));
} }
//EXLOGD("--- send to client: %d %d\n", ret, len);
_this->m_recving_from_srv = false; _this->m_recving_from_srv = false;
return ret; return ret;
} }

Binary file not shown.

View File

@ -1,6 +1,6 @@
#ifndef __TS_SERVER_VER_H__ #ifndef __TS_SERVER_VER_H__
#define __TS_SERVER_VER_H__ #define __TS_SERVER_VER_H__
#define TP_SERVER_VER L"2.2.9.3" #define TP_SERVER_VER L"2.2.10.1"
#endif // __TS_SERVER_VER_H__ #endif // __TS_SERVER_VER_H__

View File

@ -119,12 +119,9 @@ class WebServerCore:
# 启动session超时管理 # 启动session超时管理
web_session().start() web_session().start()
# 启动数据库定时事务例如MySQL防丢失连接
get_db().start_keep_alive()
tornado.ioloop.IOLoop.instance().start() tornado.ioloop.IOLoop.instance().start()
get_db().stop_keep_alive()
web_session().stop() web_session().stop()
return 0 return 0

View File

@ -25,7 +25,7 @@ def create_and_init(db, step_begin, step_end):
`account_status` int(11) DEFAULT 0, `account_status` int(11) DEFAULT 0,
`account_lock` int(11) DEFAULT 0, `account_lock` int(11) DEFAULT 0,
`account_desc` varchar(255), `account_desc` varchar(255),
`oath_secret` varchar(64), `oath_secret` varchar(64)
);""".format(db.table_prefix, db.auto_increment)) );""".format(db.table_prefix, db.auto_increment))
_db_exec(db, step_begin, step_end, '创建表 auth', """CREATE TABLE `{}auth`( _db_exec(db, step_begin, step_end, '创建表 auth', """CREATE TABLE `{}auth`(

View File

@ -46,10 +46,6 @@ class TPDatabase:
self._table_prefix = '' self._table_prefix = ''
self._conn_pool = None self._conn_pool = None
self._stop_flag = False
self._thread_keep_alive_handle = None
self._thread_keep_alive_cond = threading.Condition()
@property @property
def table_prefix(self): def table_prefix(self):
return self._table_prefix return self._table_prefix
@ -95,30 +91,6 @@ class TPDatabase:
return True return True
def start_keep_alive(self):
self._thread_keep_alive_handle = threading.Thread(target=self._thread_keep_alive)
self._thread_keep_alive_handle.start()
def stop_keep_alive(self):
self._stop_flag = True
self._thread_keep_alive_cond.acquire()
self._thread_keep_alive_cond.notify()
self._thread_keep_alive_cond.release()
if self._thread_keep_alive_handle is not None:
self._thread_keep_alive_handle.join()
log.v('database-keep-alive-thread stopped.\n')
def _thread_keep_alive(self):
while True:
self._thread_keep_alive_cond.acquire()
# 每一小时醒来执行一次查询,避免连接丢失
self._thread_keep_alive_cond.wait(3600)
self._thread_keep_alive_cond.release()
if self._stop_flag:
break
self.query('SELECT `value` FROM `{}config` WHERE `name`="db_ver";'.format(self._table_prefix))
def _init_sqlite(self, db_file): def _init_sqlite(self, db_file):
self.db_type = self.DB_TYPE_SQLITE self.db_type = self.DB_TYPE_SQLITE
self.auto_increment = 'AUTOINCREMENT' self.auto_increment = 'AUTOINCREMENT'
@ -179,13 +151,15 @@ class TPDatabase:
def is_field_exists(self, table_name, field_name): def is_field_exists(self, table_name, field_name):
if self.db_type == self.DB_TYPE_SQLITE: if self.db_type == self.DB_TYPE_SQLITE:
ret = self.query('PRAGMA table_info(`{}`);'.format(table_name)) ret = self.query('PRAGMA table_info(`{}`);'.format(table_name))
print(ret)
if ret is None: if ret is None:
return None return None
if len(ret) == 0: if len(ret) == 0:
return False return False
else: else:
for f in ret:
if f[1] == field_name:
return True return True
return False
elif self.db_type == self.DB_TYPE_MYSQL: elif self.db_type == self.DB_TYPE_MYSQL:
ret = self.query('DESC `{}` `{}`;'.format(table_name, field_name)) ret = self.query('DESC `{}` `{}`;'.format(table_name, field_name))
print(ret) print(ret)
@ -460,17 +434,42 @@ class TPMysqlPool(TPDatabasePool):
autocommit=False, autocommit=False,
connect_timeout=3.0, connect_timeout=3.0,
charset='utf8') charset='utf8')
except pymysql.err.OperationalError as e:
errno, _ = e.args
if 2003 == errno:
log.e('[mysql] connect [{}:{}] failed: {}\n'.format(self._host, self._port, e.__str__()))
return None
except Exception as e: except Exception as e:
log.e('[mysql] connect [{}:{}] failed: {}\n'.format(self._host, self._port, e.__str__())) log.e('[mysql] connect [{}:{}] failed: {}\n'.format(self._host, self._port, e.__str__()))
return None return None
def _do_query(self, conn, sql): def _do_query(self, conn, sql):
for retry in range(2):
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute(sql) cursor.execute(sql)
db_ret = cursor.fetchall() db_ret = cursor.fetchall()
conn.commit() conn.commit()
return db_ret return db_ret
except pymysql.err.OperationalError as e:
errno, _ = e.args
if retry == 1 or errno not in [2006, 2013]:
log.v('[mysql] SQL={}\n'.format(sql))
log.e('[mysql] _do_query() failed: {}\n'.format(e.__str__()))
return None
log.w('[mysql] lost connection, reconnect.\n')
with self._locker:
thread_id = threading.get_ident()
if thread_id not in self._connections:
log.e('[mysql] database pool internal error.\n')
return None
_conn = self._do_connect()
if _conn is not None:
self._connections[thread_id] = _conn
conn = _conn
else:
return None
except Exception as e: except Exception as e:
log.v('[mysql] SQL={}\n'.format(sql)) log.v('[mysql] SQL={}\n'.format(sql))
log.e('[mysql] _do_query() failed: {}\n'.format(e.__str__())) log.e('[mysql] _do_query() failed: {}\n'.format(e.__str__()))
@ -479,11 +478,32 @@ class TPMysqlPool(TPDatabasePool):
cursor.close() cursor.close()
def _do_exec(self, conn, sql): def _do_exec(self, conn, sql):
for retry in range(2):
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute(sql) cursor.execute(sql)
conn.commit() conn.commit()
return True return True
except pymysql.err.OperationalError as e:
errno, _ = e.args
if retry == 1 or errno not in [2006, 2013]:
log.v('[mysql] SQL={}\n'.format(sql))
log.e('[mysql] _do_exec() failed: {}\n'.format(e.__str__()))
return None
log.w('[mysql] lost connection, reconnect.\n')
with self._locker:
thread_id = threading.get_ident()
if thread_id not in self._connections:
log.e('[mysql] database pool internal error.\n')
return None
_conn = self._do_connect()
if _conn is not None:
self._connections[thread_id] = _conn
conn = _conn
else:
return None
except Exception as e: except Exception as e:
log.e('[mysql] _do_exec() failed: {}\n'.format(e.__str__())) log.e('[mysql] _do_exec() failed: {}\n'.format(e.__str__()))
log.e('[mysql] SQL={}'.format(sql)) log.e('[mysql] SQL={}'.format(sql))
@ -492,6 +512,7 @@ class TPMysqlPool(TPDatabasePool):
cursor.close() cursor.close()
def _do_transaction(self, conn, sql_list): def _do_transaction(self, conn, sql_list):
for retry in range(2):
cursor = conn.cursor() cursor = conn.cursor()
try: try:
conn.begin() conn.begin()
@ -499,6 +520,26 @@ class TPMysqlPool(TPDatabasePool):
cursor.execute(sql) cursor.execute(sql)
conn.commit() conn.commit()
return True return True
except pymysql.err.OperationalError as e:
errno, _ = e.args
if retry == 1 or errno not in [2006, 2013]:
log.v('[mysql] SQL={}\n'.format(sql))
log.e('[mysql] _do_transaction() failed: {}\n'.format(e.__str__()))
return False
log.w('[mysql] lost connection, reconnect.\n')
with self._locker:
thread_id = threading.get_ident()
if thread_id not in self._connections:
log.e('[mysql] database pool internal error.\n')
return False
_conn = self._do_connect()
if _conn is not None:
self._connections[thread_id] = _conn
conn = _conn
else:
return False
except Exception as e: except Exception as e:
conn.rollback() conn.rollback()
log.e('[mysql] _do_transaction() failed: {}\n'.format(e.__str__())) log.e('[mysql] _do_transaction() failed: {}\n'.format(e.__str__()))

View File

@ -193,7 +193,6 @@ class OathVerifyHandler(TPBaseUserAuthJsonHandler):
class OathSecretQrCodeHandler(TPBaseUserAuthJsonHandler): class OathSecretQrCodeHandler(TPBaseUserAuthJsonHandler):
def get(self): def get(self):
secret = self.get_session('tmp_oath_secret', None) secret = self.get_session('tmp_oath_secret', None)
print('tmp-oath-secret:', secret)
user_info = self.get_current_user() user_info = self.get_current_user()
img_data = gen_oath_qrcode(user_info['name'], secret) img_data = gen_oath_qrcode(user_info['name'], secret)

View File

@ -6,7 +6,7 @@ from eom_app.app.configs import app_cfg
from eom_app.module import host from eom_app.module import host
from eom_app.module import user from eom_app.module import user
from eom_common.eomcore.logger import * from eom_common.eomcore.logger import *
from .base import TPBaseUserAuthJsonHandler, TPBaseAdminAuthHandler, TPBaseAdminAuthJsonHandler from .base import TPBaseUserAuthHandler, TPBaseUserAuthJsonHandler, TPBaseAdminAuthHandler, TPBaseAdminAuthJsonHandler
cfg = app_cfg() cfg = app_cfg()
@ -16,7 +16,7 @@ class IndexHandler(TPBaseAdminAuthHandler):
self.render('user/index.mako') self.render('user/index.mako')
class PersonalHandler(TPBaseAdminAuthHandler): class PersonalHandler(TPBaseUserAuthHandler):
def get(self): def get(self):
user_info = self.get_current_user() user_info = self.get_current_user()
self.render('user/personal.mako', user=user_info) self.render('user/personal.mako', user=user_info)

View File

@ -61,7 +61,9 @@ def verify_oath(user_id, oath_code):
if len(db_ret) != 1: if len(db_ret) != 1:
return False return False
oath_secret = db_ret[0][0] oath_secret = str(db_ret[0][0]).strip()
if 0 == len(oath_secret):
return False
return verify_oath_code(oath_secret, oath_code) return verify_oath_code(oath_secret, oath_code)

View File

@ -1,4 +1,4 @@
# -*- coding: utf8 -*- # -*- coding: utf8 -*-
TS_VER = "2.2.9.3" TS_VER = "2.2.10.1"
TP_ASSIST_LAST_VER = "2.2.6.1" TP_ASSIST_LAST_VER = "2.2.6.1"
TP_ASSIST_REQUIRE = "2.0.0.1" TP_ASSIST_REQUIRE = "2.0.0.1"

View File

@ -14,6 +14,6 @@ Build 构建号。构建号用于表明此版本发布之前进行了多少
TELEPORT_SERVER 2.2.9.3 TELEPORT_SERVER 2.2.10.1
TELEPORT_ASSIST 2.2.6.1 TELEPORT_ASSIST 2.2.6.1
TELEPORT_ASSIST_REQUIRE 2.0.0.1 TELEPORT_ASSIST_REQUIRE 2.0.0.1