add hot-fix builder script files.

feature/assist-websocket
Apex Liu 2022-08-17 02:06:23 +08:00
parent 6ddba8e005
commit 8bb05a0d2a
15 changed files with 1639 additions and 1 deletions

3
.gitignore vendored
View File

@ -94,7 +94,8 @@ __pycache__
/client/cfg/tp-assist.linux.json
/client/tp-player/res/cursor1.png
/server/tp_core/protocol/rdp
/server/hot-fix
# /server/hot-fix
/server/hot-fix/*/tp-hotfix-*
/server/tools/tpr2mp4
# for MacOS.

View File

@ -0,0 +1,42 @@
#!/bin/sh
set -e
HOTFIX=tp-hotfix-20210813-3.5.6-rc6
PATH_ROOT=$(cd "$(dirname "$0")/../../.."; pwd)
PATH_THIS=$(cd "$(dirname "$0")"; pwd)
PATH_DATA=${PATH_THIS}/${HOTFIX}
PATH_FILES=${PATH_DATA}/files
NOW_DT_STR=`date "+%Y-%m-%d %H:%M:%S"`
echo $PATH_ROOT
echo $PATH_THIS
echo $PATH_DATA
echo $PATH_FILES
if [ -d "${PATH_FILES}" ]; then
rm -rf "${PATH_FILES}"
fi
mkdir -p "${PATH_FILES}/controller"
mkdir -p "${PATH_FILES}/model"
cp "${PATH_ROOT}/server/www/teleport/webroot/app/controller/auth.py" "${PATH_FILES}/controller/."
cp "${PATH_ROOT}/server/www/teleport/webroot/app/model/user.py" "${PATH_FILES}/model/."
# cp "${PATH_THIS}/tp-hotfix.sh" "${PATH_DATA}/."
# 将脚本文件第4行替换掉
CREATE_DT=`date "+%Y-%m-%d %H:%M:%S"`
# CREATE_DT=date
echo ${CREATE_DT}
#echo "sed -i '4s/.*/CREATE_DT\=${CREATE_DT}/' '${PATH_DATA}/tp-hotfix.sh'"
sed -i ".bak" "4s/.*/CREATE_DT='${CREATE_DT}'/" "${PATH_DATA}/tp-hotfix.sh"
#sed -i "'4s/.*/CREATE_DT=${CREATE_DT}/'" "${PATH_DATA}/tp-hotfix.sh"
rm -rf "${PATH_DATA}/tp-hotfix.sh.bak"
chmod +x "${PATH_DATA}/tp-hotfix.sh"
tar zcvf "${HOTFIX}.tar.gz" ./${HOTFIX}

View File

@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-
import json
from urllib.parse import quote
from app.base.configs import tp_cfg
from app.base.controller import TPBaseHandler, TPBaseJsonHandler
from app.const import *
from app.logic.auth.captcha import tp_captcha_generate_image
from app.model import syslog
from app.model import user
class LoginHandler(TPBaseHandler):
def get(self):
from app.base.db import get_db
if tp_cfg().app_mode == APP_MODE_MAINTENANCE and get_db().need_create:
_user = {
'id': 0,
'username': 'maintainer',
'surname': '系统维护-安装',
'role_id': 0,
'role': '',
'privilege': TP_PRIVILEGE_SYS_CONFIG,
'_is_login': True
}
self.set_session('user', _user)
self.redirect('/maintenance/install')
return
if tp_cfg().app_mode == APP_MODE_MAINTENANCE and get_db().need_upgrade:
_user = {
'id': 0,
'username': 'maintainer',
'surname': '系统维护-升级',
'role_id': 0,
'role': '',
'privilege': TP_PRIVILEGE_SYS_CONFIG,
'_is_login': True
}
self.set_session('user', _user)
self.redirect('/maintenance/upgrade')
return
_user = self.get_current_user()
_ref = quote(self.get_argument('ref', '/'))
if _user['_is_login']:
self.redirect(_ref)
return
if _user['id'] == 0:
username = self.get_cookie('username')
if username is None:
username = ''
else:
username = _user['username']
default_auth_type = tp_cfg().sys.login.auth
param = {
'ref': _ref,
'username': username,
'default_auth': default_auth_type
}
self.render('auth/login.mako', page_param=json.dumps(param))
class DoLoginHandler(TPBaseJsonHandler):
def post(self):
sys_cfg = tp_cfg().sys
args = self.get_argument('args', None)
if args is None:
return self.write_json(TPE_PARAM)
try:
args = json.loads(args)
except:
return self.write_json(TPE_JSON_FORMAT, '参数错误')
try:
login_type = args['type']
captcha = args['captcha'].strip()
username = args['username'].strip().lower()
password = args['password']
oath = args['oath'].strip()
remember = args['remember']
except:
return self.write_json(TPE_PARAM)
if login_type not in [TP_LOGIN_AUTH_USERNAME_PASSWORD,
TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA,
TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH,
TP_LOGIN_AUTH_USERNAME_OATH
]:
return self.write_json(TPE_PARAM, '未知的认证方式')
if login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA:
oath = None
code = self.get_session('captcha')
if code is None:
return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效')
if code.lower() != captcha.lower():
return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误')
elif login_type in [TP_LOGIN_AUTH_USERNAME_OATH, TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH]:
if len(oath) == 0:
return self.write_json(TPE_OATH_MISMATCH, '未提供身份验证器动态验证码')
self.del_session('captcha')
if len(username) == 0:
return self.write_json(TPE_PARAM, '未提供登录用户名')
if login_type not in [TP_LOGIN_AUTH_USERNAME_PASSWORD,
TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA,
TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH
]:
password = None
if login_type not in [TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH,
TP_LOGIN_AUTH_USERNAME_OATH
]:
oath = None
# 检查用户名合法性防止SQL注入攻击
if '<' in username or '>' in username:
username = username.replace('<', '&lt;')
username = username.replace('>', '&gt;')
err = TPE_USER_AUTH
syslog.sys_log({'username': '???', 'surname': '???'}, self.request.remote_ip, TPE_NOT_EXISTS, '登录失败,可能是攻击行为。试图使用用户名 {} 进行登录。'.format(username))
return self.write_json(err)
# 验证
err, user_info, msg = user.login(self, username, login_type=login_type, password=password, oath_code=oath)
if err != TPE_OK:
if err == TPE_NOT_EXISTS:
err = TPE_USER_AUTH
msg = '用户名或密码错误'
syslog.sys_log({'username': '???', 'surname': '???'}, self.request.remote_ip, TPE_NOT_EXISTS, '登录失败,用户`{}`不存在'.format(username))
return self.write_json(err, msg)
self._user = user_info
self._user['_is_login'] = True
if remember:
self.set_session('user', self._user, 12 * 60 * 60)
else:
self.set_session('user', self._user)
user.update_login_info(self, user_info['id'])
# 记录登录日志
syslog.sys_log(self._user, self.request.remote_ip, TPE_OK, "登录成功")
self.set_cookie('username', username)
return self.write_json(TPE_OK)
class LogoutHandler(TPBaseHandler):
def get(self):
self._user['_is_login'] = False
self.set_session('user', self._user)
self.redirect('/auth/login')
class DoLogoutHandler(TPBaseJsonHandler):
def post(self):
self._user['_is_login'] = False
self.set_session('user', self._user)
return self.write_json(TPE_OK)
class CaptchaHandler(TPBaseHandler):
def get(self):
h = int(self.get_argument('h', 36))
code, img_data = tp_captcha_generate_image(h)
self.set_session('captcha', code, expire=10 * 60) # 验证码有效期为10分钟
self.set_header('Content-Type', 'image/jpeg')
self.write(img_data)
class VerifyCaptchaHandler(TPBaseJsonHandler):
def post(self):
code = self.get_session('captcha')
if code is None:
return self.write_json(TPE_CAPTCHA_EXPIRED)
args = self.get_argument('args', None)
if args is not None:
try:
args = json.loads(args)
except:
return self.write_json(TPE_JSON_FORMAT)
try:
captcha = args['captcha']
except:
return self.write_json(TPE_PARAM)
else:
return self.write_json(TPE_PARAM)
if code.lower() != captcha.lower():
return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误')
return self.write_json(TPE_OK)
# class ModifyPwd(TPBaseUserAuthJsonHandler):
# def post(self):
# args = self.get_argument('args', None)
# if args is not None:
# args = json.loads(args)
# else:
# return self.write_json(-1, '参数错误')
# _old_pwd = args['o_pwd']
# _new_pwd = args['n_pwd']
#
# if _old_pwd is None or _new_pwd is None:
# return self.write_json(-2, '参数错误')
#
# user_info = self.get_current_user()
# try:
# ret = user.modify_pwd(_old_pwd, _new_pwd, user_info['id'])
# if 0 == ret:
# return self.write_json(0)
# else:
# return self.write_json(ret)
# except:
# log.e('modify password failed.')
# return self.write_json(-4, '发生异常')
#
#

View File

@ -0,0 +1,859 @@
# -*- coding: utf-8 -*-
import time, datetime
from app.base.configs import tp_cfg
from app.base.db import get_db, SQL
from app.base.logger import log
from app.base.utils import tp_timestamp_sec, tp_generate_random
from app.const import *
from app.model import syslog
from app.base.stats import tp_stats
from app.logic.auth.password import tp_password_verify, tp_password_generate_secret
from app.logic.auth.oath import tp_oath_verify_code
from app.logic.auth.ldap import Ldap
def get_user_info(user_id):
"""
获取一个指定的用户的详细信息包括关联的角色的详细信息所属组的详细信息等等
"""
s = SQL(get_db())
s.select_from('user',
['id', 'type', 'auth_type', 'username', 'surname', 'ldap_dn', 'password', 'oath_secret', 'role_id',
'state', 'fail_count', 'lock_time', 'email', 'create_time', 'last_login', 'last_ip', 'last_chpass',
'mobile', 'qq', 'wechat', 'desc'], alt_name='u')
s.left_join('role', ['name', 'privilege'], join_on='r.id=u.role_id', alt_name='r', out_map={'name': 'role'})
s.where('u.id="{}"'.format(user_id))
err = s.query()
if err != TPE_OK:
return err, {}
if len(s.recorder) == 0:
return TPE_NOT_EXISTS, {}
return TPE_OK, s.recorder[0]
def get_by_username(username):
db = get_db()
s = SQL(db)
s.select_from('user',
['id', 'type', 'auth_type', 'username', 'surname', 'ldap_dn', 'password', 'oath_secret', 'role_id',
'state', 'fail_count', 'lock_time', 'email', 'create_time', 'last_login', 'last_ip', 'last_chpass',
'mobile', 'qq', 'wechat', 'valid_from', 'valid_to', 'desc'], alt_name='u')
s.left_join('role', ['name', 'privilege'], join_on='r.id=u.role_id', alt_name='r', out_map={'name': 'role'})
s.where('u.username={ph}'.format(ph=db.place_holder))
err = s.query((username,))
if err != TPE_OK:
return err, None
if len(s.recorder) == 0:
return TPE_NOT_EXISTS, None
if s.recorder[0]['privilege'] is None:
s.recorder[0]['privilege'] = 0
return TPE_OK, s.recorder[0]
def login(handler, username, login_type=None, password=None, oath_code=None, check_bind_oath=False):
sys_cfg = tp_cfg().sys
msg = ''
current_unix_time = int(time.mktime(datetime.datetime.now().timetuple()))
# log.e('current:',current_unix_time,'validfrom:', user_info['valid_from'])
err, user_info = get_by_username(username)
if err != TPE_OK:
return err, None, msg
if user_info.privilege == 0:
# 尚未为此用户设置角色
return TPE_PRIVILEGE, None, '登录失败,用户尚未分配权限'
# 判断此用户是否被允许使用当前登录认证方式
if login_type is not None:
auth_type = sys_cfg.login.auth if user_info.auth_type == TP_LOGIN_AUTH_SYS_DEFAULT else user_info.auth_type
if (auth_type & login_type) != login_type:
return TPE_USER_AUTH, None, '不允许使用此身份认证方式'
password_db = user_info['password']
oath_db = user_info['oath_secret']
del user_info['password']
del user_info['oath_secret']
if check_bind_oath and len(oath_db) != 0:
return TPE_OATH_ALREADY_BIND, None, msg
if user_info['state'] == TP_STATE_LOCKED:
# 用户已经被锁定,如果系统配置为一定时间后自动解锁,则更新一下用户信息
if sys_cfg.login.lock_timeout != 0:
if tp_timestamp_sec() - user_info.lock_time > sys_cfg.login.lock_timeout * 60:
user_info.fail_count = 0
user_info.state = TP_STATE_NORMAL
update_fail_count(handler, user_info)
if user_info['state'] == TP_STATE_LOCKED:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_LOCKED, msg)
return TPE_USER_LOCKED, None, '登录失败,用户已被临时锁定'
elif user_info['state'] == TP_STATE_DISABLED:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_DISABLED, msg)
return TPE_USER_DISABLED, None, '登录失败,用户已被禁用'
elif user_info['state'] != TP_STATE_NORMAL:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_FAILED, msg)
return TPE_FAILED, None, '登录失败,用户状态异常'
elif current_unix_time < user_info['valid_from'] or (current_unix_time > user_info['valid_to'] and user_info['valid_to'] != 0):
syslog.sys_log(user_info, handler.request.remote_ip, TPE_FAILED, msg)
return TPE_FAILED, None, '登录失败,用户已过期'
err_msg = ''
if password is not None:
if user_info['type'] == TpUserType.LOCAL:
# 如果系统配置了密码有效期,则检查用户的密码是否失效
if sys_cfg.password.timeout != 0:
_time_now = tp_timestamp_sec()
if user_info['last_chpass'] + (sys_cfg.password.timeout * 60 * 60 * 24) < _time_now:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_EXPIRED, None, '登录失败,用户密码已过期'
if not tp_password_verify(password, password_db):
err, is_locked = update_fail_count(handler, user_info)
if is_locked:
err_msg = ',用户已被临时锁定'
msg = '登录失败,密码错误{}'.format(err_msg)
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_USER_AUTH, None, msg
elif user_info['type'] == TP_USER_TYPE_LDAP:
try:
if len(tp_cfg().sys_ldap_password) == 0:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_USER_AUTH, None, 'LDAP尚未配置'
else:
_ldap_password = tp_cfg().sys_ldap_password
_ldap_server = tp_cfg().sys.ldap.server
_ldap_port = tp_cfg().sys.ldap.port
_ldap_base_dn = tp_cfg().sys.ldap.base_dn
_ldap_use_ssl = tp_cfg().sys.ldap.use_ssl
except:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_USER_AUTH, None, 'LDAP尚未正确配置'
try:
ldap = Ldap(_ldap_server, _ldap_port, _ldap_base_dn, _ldap_use_ssl)
ret, err_msg = ldap.valid_user(user_info['ldap_dn'], password)
if ret != TPE_OK:
if ret == TPE_USER_AUTH:
err, is_locked = update_fail_count(handler, user_info)
if is_locked:
err_msg = ',用户已被临时锁定'
msg = 'LDAP用户验证失败{}'.format(err_msg)
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_USER_AUTH, None, msg
else:
msg = 'LDAP用户登录失败{}'.format(err_msg)
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_USER_AUTH, None, msg
except:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_USER_AUTH, None, 'LDAP用户登录失败发生内部错误'
else:
syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, msg)
return TPE_USER_AUTH, None, '登录失败,系统内部错误'
if oath_code is not None:
# use oath
if len(oath_db) == 0:
return TPE_OATH_MISMATCH, None, msg
if not tp_oath_verify_code(oath_db, oath_code):
err, is_locked = update_fail_count(handler, user_info)
if is_locked:
err_msg = ',用户已被临时锁定!'
msg = '登录失败,身份验证器动态验证码错误{}'.format(err_msg)
syslog.sys_log(user_info, handler.request.remote_ip, TPE_OATH_MISMATCH, msg)
return TPE_OATH_MISMATCH, None, msg
if len(user_info['surname']) == 0:
user_info['surname'] = user_info['username']
return TPE_OK, user_info, msg
def get_users(sql_filter, sql_order, sql_limit, sql_restrict, sql_exclude):
dbtp = get_db().table_prefix
s = SQL(get_db())
s.select_from('user', ['id', 'type', 'auth_type', 'username', 'surname', 'role_id', 'state', 'email', 'last_login', 'valid_from', 'valid_to'],
alt_name='u')
s.left_join('role', ['name', 'privilege'], join_on='r.id=u.role_id', alt_name='r', out_map={'name': 'role'})
_where = list()
if len(sql_restrict) > 0:
for k in sql_restrict:
if k == 'group_id':
_sql = 'u.id IN (SELECT mid FROM {dbtp}group_map WHERE type={gtype} AND gid={gid})'
_where.append(_sql.format(dbtp=dbtp, gtype=TP_GROUP_USER, gid=sql_restrict[k]))
else:
log.w('unknown restrict field: {}\n'.format(k))
if len(sql_exclude) > 0:
for k in sql_exclude:
if k == 'group_id':
_where.append(
'u.id NOT IN ('
'SELECT mid FROM {dbtp}group_map WHERE type={gtype} AND gid={gid})'
''.format(dbtp=dbtp, gtype=TP_GROUP_USER, gid=sql_exclude[k]))
elif k == 'ops_policy_id':
_where.append(
'u.id NOT IN (SELECT rid FROM {dbtp}ops_auz WHERE policy_id={pid} AND rtype={rtype})'
''.format(dbtp=dbtp, pid=sql_exclude[k], rtype=TP_USER))
elif k == 'auditor_policy_id':
_where.append(
'u.id NOT IN ('
'SELECT rid FROM {dbtp}audit_auz WHERE policy_id={pid} '
'AND `type`={ptype} AND rtype={rtype}'
')'.format(dbtp=dbtp, pid=sql_exclude[k], ptype=TP_POLICY_OPERATOR, rtype=TP_USER))
elif k == 'auditee_policy_id':
_where.append(
'u.id NOT IN ('
'SELECT rid FROM {dbtp}audit_auz WHERE policy_id={pid} '
'AND `type`={ptype} AND rtype={rtype}'
')'.format(dbtp=dbtp, pid=sql_exclude[k], ptype=TP_POLICY_ASSET, rtype=TP_USER))
else:
log.w('unknown exclude field: {}\n'.format(k))
if len(sql_filter) > 0:
for k in sql_filter:
if k == 'role':
_where.append('u.role_id={filter}'.format(filter=sql_filter[k]))
elif k == 'type':
_where.append('u.type={filter}'.format(filter=sql_filter[k]))
elif k == 'state':
_where.append('u.state={filter}'.format(filter=sql_filter[k]))
elif k == 'search':
_where.append('('
'u.username LIKE "%{filter}%" '
'OR u.surname LIKE "%{filter}%" '
'OR u.email LIKE "%{filter}%" '
'OR u.desc LIKE "%{filter}%"'
')'.format(filter=sql_filter[k]))
if len(_where) > 0:
s.where('( {} )'.format(' AND '.join(_where)))
if sql_order is not None:
_sort = False if not sql_order['asc'] else True
if 'username' == sql_order['name']:
s.order_by('u.username', _sort)
elif 'surname' == sql_order['name']:
s.order_by('u.surname', _sort)
elif 'role_id' == sql_order['name']:
s.order_by('u.role_id', _sort)
elif 'state' == sql_order['name']:
s.order_by('u.state', _sort)
elif 'type' == sql_order['name']:
s.order_by('u.type', _sort)
else:
log.e('unknown order field: {}\n'.format(sql_order['name']))
return TPE_PARAM, 0, 0, {}
if len(sql_limit) > 0:
s.limit(sql_limit['page_index'], sql_limit['per_page'])
err = s.query()
return err, s.total_count, s.page_index, s.recorder
def get_users_by_type(_type):
s = SQL(get_db())
err = s.select_from('user', ['id', 'type', 'ldap_dn'], alt_name='u').where('u.type={}'.format(_type)).query()
if err != TPE_OK:
return None
if len(s.recorder) == 0:
return None
return s.recorder
def create_users(handler, user_list, success, failed):
"""
批量创建用户
"""
db = get_db()
_time_now = tp_timestamp_sec()
operator = handler.get_current_user()
name_list = list()
s = SQL(db)
for i in range(len(user_list)):
user = user_list[i]
if 'type' not in user:
user['type'] = TP_USER_TYPE_LOCAL
if 'ldap_dn' not in user:
user['ldap_dn'] = ''
err = s.reset().select_from('user', ['id']).where('user.username="{}"'.format(user['username'])).query()
if err != TPE_OK:
failed.append({'line': user['_line'], 'error': '数据库查询失败'})
if len(s.recorder) > 0:
failed.append({'line': user['_line'], 'error': '账号 `{}` 已经存在'.format(user['username'])})
continue
if user['type'] == TP_USER_TYPE_LOCAL:
_password = tp_password_generate_secret(user['password'])
else:
_password = ''
sql = 'INSERT INTO `{}user` (' \
'`role_id`, `username`, `surname`, `type`, `ldap_dn`, `auth_type`, `password`, ' \
'`state`, `email`, `creator_id`, `create_time`, `last_login`, `last_chpass`, `desc`' \
') VALUES (' \
'0, "{username}", "{surname}", {user_type}, "{ldap_dn}", 0, "{password}", ' \
'{state}, "{email}", {creator_id}, {create_time}, {last_login}, {last_chpass}, "{desc}");' \
''.format(db.table_prefix, username=user['username'], surname=user['surname'], user_type=user['type'],
ldap_dn=user['ldap_dn'], password=_password, state=TP_STATE_NORMAL, email=user['email'],
creator_id=operator['id'], create_time=_time_now, last_login=0, last_chpass=_time_now,
desc=user['desc'])
db_ret = db.exec(sql)
if not db_ret:
failed.append({'line': user['_line'], 'error': '写入数据库时发生错误'})
continue
success.append(user['username'])
name_list.append(user['username'])
user['_id'] = db.last_insert_id()
if len(name_list) > 0:
syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "批量导入方式创建用户:{}".format(''.join(name_list)))
# tp_stats().user_counter_change(len(name_list))
# calc count of users.
err, cnt = s.reset().count('user')
if err == TPE_OK:
tp_stats().user_counter_change(cnt)
def create_user(handler, user):
"""
创建一个用户账号
"""
db = get_db()
_time_now = tp_timestamp_sec()
operator = handler.get_current_user()
if 'type' not in user:
user['type'] = TP_USER_TYPE_LOCAL
if 'ldap_dn' not in user:
user['ldap_dn'] = ''
# 1. 判断此账号是否已经存在了
s = SQL(db)
err = s.reset().select_from('user', ['id']).where('user.username="{}"'.format(user['username'])).query()
if err != TPE_OK:
return err, 0
if len(s.recorder) > 0:
return TPE_EXISTS, 0
# _password = tp_password_generate_secret(user['password'])
if user['type'] == TP_USER_TYPE_LOCAL:
_password = tp_password_generate_secret(user['password'])
else:
_password = ''
sql = 'INSERT INTO `{}user` (' \
'`role_id`, `username`, `surname`, `type`, `ldap_dn`, `auth_type`, `password`, `state`, ' \
'`email`, `creator_id`, `create_time`, `last_login`, `last_chpass`, `valid_from`, `valid_to`, `desc`' \
') VALUES (' \
'{role}, "{username}", "{surname}", {user_type}, "{ldap_dn}", {auth_type}, "{password}", {state}, ' \
'"{email}", {creator_id}, {create_time}, {last_login}, {last_chpass}, {valid_from}, ' \
'{valid_to}, "{desc}");' \
''.format(db.table_prefix, role=user['role'], username=user['username'], surname=user['surname'],
user_type=user['type'], ldap_dn=user['ldap_dn'], auth_type=user['auth_type'], password=_password,
state=TP_STATE_NORMAL, email=user['email'], creator_id=operator['id'], create_time=_time_now,
last_login=0, last_chpass=_time_now, valid_from=user['valid_from'], valid_to=user['valid_to'], desc=user['desc'])
db_ret = db.exec(sql)
if not db_ret:
return TPE_DATABASE, 0
_id = db.last_insert_id()
syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "创建用户:{}".format(user['username']))
# calc count of users.
err, cnt = s.reset().count('user')
if err == TPE_OK:
tp_stats().user_counter_change(cnt)
return TPE_OK, _id
def update_user(handler, args):
"""
更新一个用户账号
"""
db = get_db()
# 1. 判断此账号是否已经存在
sql = 'SELECT `username` FROM {dbtp}user WHERE `id`={dbph};'.format(dbtp=db.table_prefix, dbph=db.place_holder)
db_ret = db.query(sql, (args['id'],))
if db_ret is None or len(db_ret) == 0:
return TPE_NOT_EXISTS
old_username = db_ret[0][0]
if old_username != args['username']:
# 如果要更新用户登录名,则需要判断是否已经存在了
sql = 'SELECT `id` FROM {dbtp}user WHERE `username`={dbph};'.format(dbtp=db.table_prefix, dbph=db.place_holder)
db_ret = db.query(sql, (args['username'],))
if db_ret is not None and len(db_ret) > 0:
return TPE_EXISTS
sql = 'UPDATE `{}user` SET ' \
'`username`="{username}", `surname`="{surname}", `auth_type`={auth_type}, ' \
'`role_id`={role}, `email`="{email}", `mobile`="{mobile}", `qq`="{qq}", ' \
'`wechat`="{wechat}", `valid_from`={valid_from}, `valid_to`={valid_to}, ' \
'`desc`="{desc}" WHERE `id`={user_id};' \
''.format(db.table_prefix,
username=args['username'], surname=args['surname'], auth_type=args['auth_type'], role=args['role'],
email=args['email'], mobile=args['mobile'], qq=args['qq'], wechat=args['wechat'],
valid_from=args['valid_from'], valid_to=args['valid_to'], desc=args['desc'], user_id=args['id']
)
db_ret = db.exec(sql)
if not db_ret:
return TPE_DATABASE
# 同步更新授权表和权限映射表
_uname = args['username']
if len(args['surname']) > 0:
_uname += '' + args['surname'] + ''
sql_list = []
# 运维授权
sql_s = 'UPDATE `{tp}ops_auz` SET `name`={ph} WHERE (`rtype`={ph} AND `rid`={ph});' \
''.format(tp=db.table_prefix, ph=db.place_holder)
sql_v = (_uname, TP_USER, args['id'])
sql_list.append({'s': sql_s, 'v': sql_v})
sql_s = 'UPDATE `{tp}ops_map` SET `u_name`={ph}, `u_surname`={ph} WHERE (u_id={ph});' \
''.format(tp=db.table_prefix, ph=db.place_holder)
sql_v = (args['username'], args['surname'], args['id'])
sql_list.append({'s': sql_s, 'v': sql_v})
# 审计授权
sql_s = 'UPDATE `{tp}audit_auz` SET `name`={ph} WHERE (`rtype`={ph} AND `rid`={ph});' \
''.format(tp=db.table_prefix, ph=db.place_holder)
sql_v = (_uname, TP_USER, args['id'])
sql_list.append({'s': sql_s, 'v': sql_v})
sql_s = 'UPDATE `{tp}audit_map` SET `u_name`={ph}, `u_surname`={ph} WHERE (u_id={ph});' \
''.format(tp=db.table_prefix, ph=db.place_holder)
sql_v = (args['username'], args['surname'], args['id'])
sql_list.append({'s': sql_s, 'v': sql_v})
if not db.transaction(sql_list):
return TPE_DATABASE
operator = handler.get_current_user()
syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "更新用户信息:{}".format(args['username']))
return TPE_OK
def set_role_for_users(handler, users, role_id):
db = get_db()
ids = [str(uid) for uid in users]
where = 'id IN ({})'.format(','.join(ids))
sql = 'UPDATE `{}user` SET role_id={role_id} WHERE {where};' \
''.format(db.table_prefix,
role_id=role_id, where=where
)
db_ret = db.exec(sql)
if not db_ret:
return TPE_DATABASE
return TPE_OK
def set_password(handler, mode, user_id, password):
db = get_db()
operator = handler.get_current_user()
# print('----------', operator)
# 1. get user info (user name)
s = SQL(db)
err = s.reset().select_from('user', ['username', 'surname']).where('user.id={}'.format(user_id)).query()
if err != TPE_OK:
return err
if len(s.recorder) == 0:
return TPE_NOT_EXISTS
name = s.recorder[0]['username']
surname = s.recorder[0]['surname']
if len(surname) == 0:
surname = name
_time_now = tp_timestamp_sec()
sql = 'UPDATE `{}user` SET `password`="{password}", `last_chpass`={last_chpass} WHERE `id`={user_id};' \
''.format(db.table_prefix, password=password, last_chpass=_time_now, user_id=user_id)
db_ret = db.exec(sql)
if not db_ret:
return TPE_DATABASE
if mode in [3, 4, 5, 6]:
if mode == 6:
syslog.sys_log({'username': name, 'surname': surname}, handler.request.remote_ip, TPE_OK, "用户 {} 修改了过期的密码".format(name))
else:
syslog.sys_log({'username': name, 'surname': surname}, handler.request.remote_ip, TPE_OK, "用户 {} 通过邮件方式重置了密码".format(name))
else:
syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "为用户 {} 手动重置了密码".format(name))
return TPE_OK
def generate_reset_password_token(handler, user_id):
db = get_db()
operator = handler.get_current_user()
s = SQL(db)
_time_now = tp_timestamp_sec()
# 0. query user's email by user_id
err = s.select_from('user', ['email'], alt_name='u').where('u.id={user_id}'.format(user_id=user_id)).query()
if err != TPE_OK:
return err, None, None
if len(s.recorder) == 0:
return TPE_DATABASE, None, None
email = s.recorder[0].email
# 1. clean all timed out tokens.
s.reset().delete_from('user_rpt').where('create_time<{}'.format(_time_now - 24 * 60 * 60)).exec()
# 2. find out if this user already have a token.
err = s.reset().select_from('user_rpt', ['id'], alt_name='u').where('u.user_id={}'.format(user_id)).query()
if err != TPE_OK:
return err, None, None
token = tp_generate_random(16)
if len(s.recorder) == 0:
sql = 'INSERT INTO `{dbtp}user_rpt` (user_id, token, create_time) VALUES ' \
'({user_id}, "{token}", {create_time});' \
''.format(dbtp=db.table_prefix, user_id=user_id, token=token, create_time=_time_now)
db_ret = db.exec(sql)
if not db_ret:
return TPE_DATABASE, None, None
else:
sql = 'UPDATE `{dbtp}user_rpt` SET token="{token}", create_time={create_time} WHERE user_id={user_id};' \
''.format(dbtp=db.table_prefix, token=token, create_time=_time_now, user_id=user_id)
db_ret = db.exec(sql)
if not db_ret:
return TPE_DATABASE, None, None
# syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "为用户 {} 手动重置了密码".format(name))
return TPE_OK, email, token
def check_reset_token(token):
db = get_db()
# s = SQL(db)
_time_now = tp_timestamp_sec()
# 0. remove expired token (after 3 days)
sql = 'DELETE FROM `{dbtp}user_rpt` WHERE create_time<{dbph};'.format(dbtp=db.table_prefix, dbph=db.place_holder)
db.exec(sql, (_time_now - 3 * 24 * 60 * 60,))
# 1. query user's id
sql = 'SELECT user_id, create_time FROM `{dbtp}user_rpt` WHERE token={dbph};'.format(dbtp=db.table_prefix,
dbph=db.place_holder)
db_ret = db.query(sql, (token,))
if db_ret is None or len(db_ret) == 0:
return TPE_NOT_EXISTS, 0
user_id = db_ret[0][0]
create_time = db_ret[0][1]
if _time_now - create_time > 24 * 60 * 60:
return TPE_EXPIRED, user_id
else:
return TPE_OK, user_id
def remove_reset_token(token):
db = get_db()
sql = 'DELETE FROM `{dbtp}user_rpt` WHERE token={dbph};'.format(dbtp=db.table_prefix, dbph=db.place_holder)
err = db.exec(sql, (token,))
return TPE_OK if err else TPE_DATABASE
def update_login_info(handler, user_id):
db = get_db()
_time_now = tp_timestamp_sec()
sql = 'UPDATE `{}user` SET ' \
'fail_count=0, last_login=login_time, last_ip=login_ip, login_time={login_time},' \
' login_ip="{ip}" WHERE id={user_id};' \
''.format(db.table_prefix,
login_time=_time_now, ip=handler.request.remote_ip, user_id=user_id
)
if db.exec(sql):
return TPE_OK
else:
return TPE_DATABASE
def update_oath_secret(handler, user_id, oath_secret):
db = get_db()
s = SQL(db)
err = s.select_from('user', ['username', 'surname'], alt_name='u').where(
'u.id={user_id}'.format(user_id=user_id)).query()
if err != TPE_OK:
return err
if len(s.recorder) == 0:
return TPE_NOT_EXISTS
username = s.recorder[0].username
surname = s.recorder[0].surname
sql = 'UPDATE `{dbtp}user` SET oath_secret="{secret}" WHERE id={user_id}' \
''.format(dbtp=db.table_prefix, secret=oath_secret, user_id=user_id)
if db.exec(sql):
if len(oath_secret) > 0:
syslog.sys_log({'username': username, 'surname': surname}, handler.request.remote_ip, TPE_OK,
"用户 {} 更新了身份认证器绑定信息".format(username))
else:
syslog.sys_log({'username': username, 'surname': surname}, handler.request.remote_ip, TPE_OK,
"用户 {} 清除了身份认证器绑定信息".format(username))
return TPE_OK
else:
return TPE_DATABASE
def update_users_state(handler, user_ids, state):
db = get_db()
user_ids = ','.join([str(i) for i in user_ids])
sql_list = []
sql_s = 'UPDATE `{tp}user` SET `state`={ph} WHERE `id` IN ({ids});' \
''.format(tp=db.table_prefix, ph=db.place_holder, ids=user_ids)
sql_v = (state,)
sql_list.append({'s': sql_s, 'v': sql_v})
# 如果是解锁/解禁,同时要重置失败尝试次数
if state == TP_STATE_NORMAL:
sql_s = 'UPDATE `{tp}user` SET `fail_count`=0 WHERE `id` IN ({ids});' \
''.format(tp=db.table_prefix, ids=user_ids)
sql_list.append({'s': sql_s, 'v': None})
sql_s = 'UPDATE `{tp}ops_auz` SET `state`={ph} WHERE `rtype`={ph} AND `rid` IN ({ids});' \
''.format(tp=db.table_prefix, ph=db.place_holder, ids=user_ids)
sql_v = (state, TP_USER)
sql_list.append({'s': sql_s, 'v': sql_v})
sql_s = 'UPDATE `{tp}ops_map` SET `u_state`={ph} WHERE `u_id` IN ({ids});' \
''.format(tp=db.table_prefix, ph=db.place_holder, ids=user_ids)
sql_v = (state,)
sql_list.append({'s': sql_s, 'v': sql_v})
sql_s = 'UPDATE `{tp}audit_auz` SET `state`={ph} WHERE `rtype`={ph} AND `rid` IN ({rid});' \
''.format(tp=db.table_prefix, ph=db.place_holder, rid=user_ids)
sql_v = (state, TP_USER)
sql_list.append({'s': sql_s, 'v': sql_v})
sql_s = 'UPDATE `{tp}audit_map` SET `u_state`={ph} WHERE `u_id` IN ({ids});' \
''.format(tp=db.table_prefix, ph=db.place_holder, ids=user_ids)
sql_v = (state,)
sql_list.append({'s': sql_s, 'v': sql_v})
if db.transaction(sql_list):
return TPE_OK
else:
return TPE_DATABASE
def update_fail_count(handler, user_info):
db = get_db()
sys_cfg = tp_cfg().sys
sql_list = []
is_locked = False
fail_count = user_info.fail_count + 1
sql_s = 'UPDATE `{tp}user` SET `fail_count`={ph} WHERE `id`={ph};' \
''.format(tp=db.table_prefix, ph=db.place_holder)
sql_v = (fail_count, user_info.id)
sql_list.append({'s': sql_s, 'v': sql_v})
if sys_cfg.login.retry != 0 and fail_count >= sys_cfg.login.retry:
is_locked = True
sql_s = 'UPDATE `{tp}user` SET `state`={ph}, `lock_time`={ph} WHERE `id`={ph};' \
''.format(tp=db.table_prefix, ph=db.place_holder)
sql_v = (TP_STATE_LOCKED, tp_timestamp_sec(), user_info.id)
sql_list.append({'s': sql_s, 'v': sql_v})
if db.transaction(sql_list):
return TPE_OK, is_locked
else:
return TPE_DATABASE, is_locked
def remove_users(handler, users):
db = get_db()
s = SQL(db)
str_users = ','.join([str(i) for i in users])
# 1. 获取用户名称,用于记录系统日志
where = 'u.id IN ({})'.format(str_users)
err = s.select_from('user', ['username'], alt_name='u').where(where).query()
if err != TPE_OK:
return err
if len(s.recorder) == 0:
return TPE_NOT_EXISTS
str_names = ''.join([n['username'] for n in s.recorder])
sql_list = []
# 将用户从所在组中移除
sql_s = 'DELETE FROM `{tp}group_map` WHERE `type`={ph} AND `mid` IN ({ids});' \
''.format(tp=db.table_prefix, ph=db.place_holder, ids=str_users)
sql_v = (TP_GROUP_USER,)
sql_list.append({'s': sql_s, 'v': sql_v})
# 删除用户
sql_s = 'DELETE FROM `{tp}user` WHERE `id` IN ({ids});'.format(tp=db.table_prefix, ids=str_users)
sql_list.append({'s': sql_s, 'v': None})
# 将用户从运维授权中移除
sql_s = 'DELETE FROM `{tp}ops_auz` WHERE `rtype`={ph} AND `rid` IN ({ids});' \
''.format(tp=db.table_prefix, ph=db.place_holder, ids=str_users)
sql_v = (TP_USER,)
sql_list.append({'s': sql_s, 'v': sql_v})
sql_s = 'DELETE FROM `{tp}ops_map` WHERE `u_id` IN ({ids});'.format(tp=db.table_prefix, ids=str_users)
sql_list.append({'s': sql_s, 'v': None})
# 将用户从审计授权中移除
sql_s = 'DELETE FROM `{tp}audit_auz` WHERE `rtype`={ph} AND `rid` IN ({ids});' \
''.format(tp=db.table_prefix, ph=db.place_holder, ids=str_users)
sql_v = (TP_USER,)
sql_list.append({'s': sql_s, 'v': sql_v})
sql_s = 'DELETE FROM `{tp}audit_map` WHERE `u_id` IN ({ids});'.format(tp=db.table_prefix, ids=str_users)
sql_list.append({'s': sql_s, 'v': None})
if not db.transaction(sql_list):
return TPE_DATABASE
syslog.sys_log(handler.get_current_user(), handler.request.remote_ip, TPE_OK, "删除用户:{}".format(str_names))
# calc count of users.
err, cnt = s.reset().count('user')
if err == TPE_OK:
tp_stats().user_counter_change(cnt)
return TPE_OK
def get_group_with_member(sql_filter, sql_order, sql_limit):
"""
获取用户组列表以及每个组的总成员数以及不超过5个的成员
"""
# 首先获取要查询的组的信息
sg = SQL(get_db())
sg.select_from('group', ['id', 'state', 'name', 'desc'], alt_name='g')
_where = list()
_where.append('g.type={}'.format(TP_GROUP_USER))
if len(sql_filter) > 0:
for k in sql_filter:
if k == 'search':
_where.append('(g.name LIKE "%{filter}%" OR g.desc LIKE "%{filter}%")'.format(filter=sql_filter[k]))
elif k == 'state':
_where.append('(g.state={filter})'.format(filter=sql_filter[k]))
if len(_where) > 0:
sg.where('( {} )'.format(' AND '.join(_where)))
if sql_order is not None:
_sort = False if not sql_order['asc'] else True
if 'name' == sql_order['name']:
sg.order_by('g.name', _sort)
elif 'state' == sql_order['name']:
sg.order_by('g.state', _sort)
else:
log.e('unknown order field.\n')
return TPE_PARAM, sg.total_count, sg.recorder
if len(sql_limit) > 0:
sg.limit(sql_limit['page_index'], sql_limit['per_page'])
err = sg.query()
if err != TPE_OK or len(sg.recorder) == 0:
return err, sg.total_count, sg.recorder
for g in sg.recorder:
g['member_count'] = 0
g['members'] = []
g['_mid'] = [] # 临时使用构建此组的前5个成员的id
# 对于本次要返回的用户组取其中每一个组内成员的基本信息id/用户名/真实名称等)
groups = [g['id'] for g in sg.recorder]
sgm = SQL(get_db())
sgm.select_from('group_map', ['gid', 'mid'], alt_name='gm')
# sgm.limit(0, 5)
_where = list()
# _where.append('({})'.format(' OR '.join(['gm.gid={}'.format(gid) for gid in groups])))
_where.append('gm.type={}'.format(TP_GROUP_USER))
_where.append('gm.gid IN ({})'.format(','.join([str(gid) for gid in groups])))
str_where = '( {} )'.format(' AND '.join(_where))
sgm.where(str_where)
err = sgm.query()
if err != TPE_OK or len(sgm.recorder) == 0:
return err, sg.total_count, sg.recorder
for g in sg.recorder:
for gm in sgm.recorder:
if gm['gid'] == g['id']:
g['member_count'] += 1
if len(g['_mid']) < 5:
g['_mid'].append(gm['mid'])
# 将得到的用户id合并到列表中并去重然后获取这些用户的信息
users = []
for g in sg.recorder:
users.extend(g['_mid'])
users = list(set(users))
su = SQL(get_db())
su.select_from('user', ['id', 'username', 'surname', 'email'], alt_name='u')
su.where('u.id IN ({})'.format(','.join([str(uid) for uid in users])))
su.order_by('u.username')
err = su.query()
if err != TPE_OK or len(su.recorder) == 0:
return err, sg.total_count, sg.recorder
# 现在可以将具体的用户信息追加到组信息中了
for g in sg.recorder:
for u in su.recorder:
for m in g['_mid']:
if u['id'] == m:
g['members'].append(u)
return err, sg.total_count, sg.recorder
def get_role_list():
s = SQL(get_db())
s.select_from('role', ['id', 'name', 'privilege'], alt_name='r')
err = s.query()
return err, s.recorder

View File

@ -0,0 +1,57 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: teleport
# Required-Start: $local_fs $network $syslog
# Required-Stop: $local_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the teleport daemon
# Description: start or stop teleport service daemon
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON_PATH=/Users/apex/work/tp4a/teleport/server
NAME=teleport
DESC=teleport
test -f "$DAEMON_PATH/start.sh" || exit 0
test -f "$DAEMON_PATH/stop.sh" || exit 0
test -f "$DAEMON_PATH/status.sh" || exit 0
set -e
# . /lib/lsb/init-functions
SRV=all
if [ x$2 != x ]; then
SRV=$2
fi
case "$1" in
start)
$DAEMON_PATH/start.sh $SRV
;;
stop)
$DAEMON_PATH/stop.sh $SRV
;;
restart)
$DAEMON_PATH/stop.sh $SRV
sleep 2
$DAEMON_PATH/start.sh $SRV
sleep 2
$DAEMON_PATH/status.sh $SRV
;;
status)
$DAEMON_PATH/status.sh $SRV
;;
*)
echo "Usage: $NAME {{start|stop|restart|status}}" >&2
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,14 @@
=============================================
Teleport Hotfix for 3.2.2
2022-08-16
=============================================
Teleport服务端安全补丁修复内容
1. 在处理获取文件内容过程中直接拼接了参数到文件路径中导致任意文件读取。
2. 登录接口存在逻辑漏洞可以绕过登录验证,导致可任意账号登入系统。
注意:
1. 仅用于为3.2.2打补丁3.2.x的用户请尽快升级到3.2.2并安装本补丁;
2. 建议尽快升级到3.5.6-rc6
3. 需要以管理员身份执行热修复脚本。

View File

@ -0,0 +1,78 @@
#!/bin/sh
set -e
CREATE_DT='_PLACE_HOLDER_'
REQUEST_VER_NO='_PLACE_HOLDER_'
if [ `id -u` -ne 0 ];then
echo ""
echo "Error: please run hotfix as root."
echo ""
exit 1
fi
PATH_ROOT=$(cd "$(dirname "$0")"; pwd)
PATH_FILES=${PATH_ROOT}/files
DAEMON_FILE=/etc/init.d/teleport
NOW_DT=`date "+%Y%m%d.%H%M%S"`
echo '============================================='
echo " Teleport Hotfix for ${REQUEST_VER_NO}"
echo " create at ${CREATE_DT}"
echo '============================================='
inst_path=`cat ${DAEMON_FILE} | grep "DAEMON_PATH=" | awk -F= '{print $2}'`
if [ 'x-$inst_path' == 'x-' ]; then
echo "Error: teleport installation not detected on your system."
echo "hotfix not patch, exit."
exit 1
else
echo "teleport installation detected at ${inst_path}"
fi
ver_file=${inst_path}/www/teleport/webroot/app/app_ver.py
ver_no=`cat ${ver_file} | grep "TP_SERVER_VER = " | awk -F= '{print $2}' | awk -F\" '{print $2}'`
miss_match_ver=0
if [ "${ver_no}" != "${REQUEST_VER_NO}" ]; then
miss_match_ver=1
fi
if [ ${miss_match_ver} != 0 ]; then
echo "Error: this hotfix works for ${REQUEST_VER_NO}, but your installation is ${ver_no}"
echo 'hotfix not patch, exit.'
exit 1
fi
miss_match_file=0
if [ ! -f "${inst_path}/www/teleport/webroot/app/controller/audit.py" ]; then
miss_match_file=1
fi
if [ ! -f "${inst_path}/www/teleport/webroot/app/controller/auth.py" ]; then
miss_match_file=1
fi
if [ ${miss_match_ver} != 0 ]; then
echo "Error: target file to be fix not found."
echo 'hotfix not patch, exit.'
exit 1
fi
echo "patching..."
echo " backup ${inst_path}/www/teleport/webroot/app/controller/audit.py"
mv "${inst_path}/www/teleport/webroot/app/controller/audit.py" "${inst_path}/www/teleport/webroot/app/controller/audit.py.hotfix.${NOW_DT}"
echo " backup ${inst_path}/www/teleport/webroot/app/controller/auth.py"
mv "${inst_path}/www/teleport/webroot/app/controller/auth.py" "${inst_path}/www/teleport/webroot/app/controller/auth.py.hotfix.${NOW_DT}"
echo " fix ${inst_path}/www/teleport/webroot/app/controller/audit.py"
cp "${PATH_FILES}/controller/audit.py" "${inst_path}/www/teleport/webroot/app/controller/audit.py"
echo " fix ${inst_path}/www/teleport/webroot/app/controller/auth.py"
cp "${PATH_FILES}/controller/auth.py" "${inst_path}/www/teleport/webroot/app/controller/auth.py"
echo ''
echo "done, now please restart teleport web server by following command:"
echo ''
echo 'sudo /etc/init.d/teleport restart web'
echo ''

View File

@ -0,0 +1,42 @@
#!/bin/sh
set -e
REQUEST_VER_NO='3.2.2'
HOTFIX_CREATE_DAY=`date "+%Y%m%d"`
HOTFIX=tp-hotfix-${HOTFIX_CREATE_DAY}-${REQUEST_VER_NO}
PATH_ROOT=$(cd "$(dirname "$0")/../../.."; pwd)
PATH_THIS=$(cd "$(dirname "$0")"; pwd)
PATH_BASE=${PATH_THIS}/base
PATH_DATA=${PATH_THIS}/${HOTFIX}
PATH_FILES=${PATH_DATA}/files
NOW_DT_STR=`date "+%Y-%m-%d %H:%M:%S"`
echo "PATH_ROOT: ${PATH_ROOT}"
echo "PATH_THIS: ${PATH_THIS}"
echo "PATH_BASE: ${PATH_BASE}"
echo "PATH_DATA: ${PATH_DATA}"
echo "PATH_FILES: ${PATH_FILES}"
if [ -d "${PATH_DATA}" ]; then
rm -rf "${PATH_DATA}"
fi
mkdir -p "${PATH_FILES}/controller"
cp "${PATH_BASE}/README.txt" "${PATH_DATA}/."
cp "${PATH_BASE}/tp-hotfix.sh" "${PATH_DATA}/."
cp "${PATH_ROOT}/server/www/teleport/webroot/app/controller/audit.py" "${PATH_FILES}/controller/."
cp "${PATH_ROOT}/server/www/teleport/webroot/app/controller/auth.py" "${PATH_FILES}/controller/."
# 替换脚本文件中的参数部分第4/5行
sed -i ".bak" "4s/.*/CREATE_DT='${NOW_DT_STR}'/" "${PATH_DATA}/tp-hotfix.sh"
sed -i ".bak" "5s/.*/REQUEST_VER_NO='${REQUEST_VER_NO}'/" "${PATH_DATA}/tp-hotfix.sh"
rm -rf "${PATH_DATA}/tp-hotfix.sh.bak"
chmod +x "${PATH_DATA}/tp-hotfix.sh"
tar zcvf "${HOTFIX}.tar.gz" ./${HOTFIX}

View File

@ -0,0 +1,13 @@
=============================================
Teleport Hotfix for 3.5.6-rc6
2022-08-16
=============================================
Teleport服务端安全补丁修复内容
1. 在处理获取文件内容过程中直接拼接了参数到文件路径中导致任意文件读取。
2. 登录接口存在逻辑漏洞可以绕过登录验证,导致可任意账号登入系统。
注意:
1. 仅用于为3.5.6-rc6打补丁3.5.x的用户请尽快升级到3.5.6-rc6并安装本补丁
2. 需要以管理员身份执行热修复脚本。

View File

@ -0,0 +1,83 @@
#!/bin/sh
set -e
CREATE_DT='_PLACE_HOLDER_'
REQUEST_VER_NO='_PLACE_HOLDER_'
REQUEST_VER_STAT='_PLACE_HOLDER_'
if [ `id -u` -ne 0 ];then
echo ""
echo "Error: please run hotfix as root."
echo ""
exit 1
fi
PATH_ROOT=$(cd "$(dirname "$0")"; pwd)
PATH_FILES=${PATH_ROOT}/files
DAEMON_FILE=/etc/init.d/teleport
NOW_DT=`date "+%Y%m%d.%H%M%S"`
echo '============================================='
echo " Teleport Hotfix for ${REQUEST_VER_NO}-${REQUEST_VER_STAT}"
echo " create at ${CREATE_DT}"
echo '============================================='
inst_path=`cat ${DAEMON_FILE} | grep "DAEMON_PATH=" | awk -F= '{print $2}'`
if [ 'x-$inst_path' == 'x-' ]; then
echo "Error: teleport installation not detected on your system."
echo "hotfix not patch, exit."
exit 1
else
echo "teleport installation detected at ${inst_path}"
fi
ver_file=${inst_path}/www/teleport/webroot/app/app_ver.py
ver_no=`cat ${ver_file} | grep "TP_SERVER_VER = " | awk -F= '{print $2}' | awk -F\" '{print $2}'`
ver_stat=`cat ${ver_file} | grep "TP_STATE_VER = " | awk -F= '{print $2}' | awk -F\" '{print $2}'`
miss_match_ver=0
if [ "${ver_no}" != "${REQUEST_VER_NO}" ]; then
miss_match_ver=1
fi
if [ "${ver_stat}" != "${REQUEST_VER_STAT}" ]; then
miss_match_ver=1
fi
if [ ${miss_match_ver} != 0 ]; then
echo "Error: this hotfix works for ${REQUEST_VER_NO}-${REQUEST_VER_STAT}, but your installation is ${ver_no} ${ver_stat}"
echo 'hotfix not patch, exit.'
exit 1
fi
miss_match_file=0
if [ ! -f "${inst_path}/www/teleport/webroot/app/controller/audit.py" ]; then
miss_match_file=1
fi
if [ ! -f "${inst_path}/www/teleport/webroot/app/controller/auth.py" ]; then
miss_match_file=1
fi
if [ ${miss_match_ver} != 0 ]; then
echo "Error: target file to be fix not found."
echo 'hotfix not patch, exit.'
exit 1
fi
echo "patching..."
echo " backup ${inst_path}/www/teleport/webroot/app/controller/audit.py"
mv "${inst_path}/www/teleport/webroot/app/controller/audit.py" "${inst_path}/www/teleport/webroot/app/controller/audit.py.hotfix.${NOW_DT}"
echo " backup ${inst_path}/www/teleport/webroot/app/controller/auth.py"
mv "${inst_path}/www/teleport/webroot/app/controller/auth.py" "${inst_path}/www/teleport/webroot/app/controller/auth.py.hotfix.${NOW_DT}"
echo " fix ${inst_path}/www/teleport/webroot/app/controller/audit.py"
cp "${PATH_FILES}/controller/audit.py" "${inst_path}/www/teleport/webroot/app/controller/audit.py"
echo " fix ${inst_path}/www/teleport/webroot/app/controller/auth.py"
cp "${PATH_FILES}/controller/auth.py" "${inst_path}/www/teleport/webroot/app/controller/auth.py"
echo ''
echo "done, now please restart teleport web server by following command:"
echo ''
echo 'sudo /etc/init.d/teleport restart web'
echo ''

View File

@ -0,0 +1,49 @@
#!/bin/sh
set -e
REQUEST_VER_NO='3.5.6'
REQUEST_VER_STAT='rc6'
HOTFIX_CREATE_DAY=`date "+%Y%m%d"`
HOTFIX=tp-hotfix-${HOTFIX_CREATE_DAY}-${REQUEST_VER_NO}-${REQUEST_VER_STAT}
PATH_ROOT=$(cd "$(dirname "$0")/../../.."; pwd)
PATH_THIS=$(cd "$(dirname "$0")"; pwd)
PATH_BASE=${PATH_THIS}/base
PATH_DATA=${PATH_THIS}/${HOTFIX}
PATH_FILES=${PATH_DATA}/files
NOW_DT_STR=`date "+%Y-%m-%d %H:%M:%S"`
echo "PATH_ROOT: ${PATH_ROOT}"
echo "PATH_THIS: ${PATH_THIS}"
echo "PATH_BASE: ${PATH_BASE}"
echo "PATH_DATA: ${PATH_DATA}"
echo "PATH_FILES: ${PATH_FILES}"
if [ -d "${PATH_DATA}" ]; then
rm -rf "${PATH_DATA}"
fi
# if [ -d "${PATH_FILES}" ]; then
# rm -rf "${PATH_FILES}"
# fi
mkdir -p "${PATH_FILES}/controller"
# mkdir -p "${PATH_FILES}/model"
cp "${PATH_BASE}/README.txt" "${PATH_DATA}/."
cp "${PATH_BASE}/tp-hotfix.sh" "${PATH_DATA}/."
cp "${PATH_ROOT}/server/www/teleport/webroot/app/controller/audit.py" "${PATH_FILES}/controller/."
cp "${PATH_ROOT}/server/www/teleport/webroot/app/controller/auth.py" "${PATH_FILES}/controller/."
# 替换脚本文件中的参数部分第4/5/6行
sed -i ".bak" "4s/.*/CREATE_DT='${NOW_DT_STR}'/" "${PATH_DATA}/tp-hotfix.sh"
sed -i ".bak" "5s/.*/REQUEST_VER_NO='${REQUEST_VER_NO}'/" "${PATH_DATA}/tp-hotfix.sh"
sed -i ".bak" "6s/.*/REQUEST_VER_STAT='${REQUEST_VER_STAT}'/" "${PATH_DATA}/tp-hotfix.sh"
rm -rf "${PATH_DATA}/tp-hotfix.sh.bak"
chmod +x "${PATH_DATA}/tp-hotfix.sh"
tar zcvf "${HOTFIX}.tar.gz" ./${HOTFIX}

View File

@ -0,0 +1,13 @@
=============================================
Teleport Hotfix for 3.6.3-b2
2022-08-16
=============================================
Teleport服务端安全补丁修复内容
1. 在处理获取文件内容过程中直接拼接了参数到文件路径中导致任意文件读取。
2. 登录接口存在逻辑漏洞可以绕过登录验证,导致可任意账号登入系统。
注意:
1. 仅用于为3.6.3-b2打补丁3.6.x的用户请尽快升级到3.6.3-b2并安装本补丁
2. 需要以管理员身份执行热修复脚本。

View File

@ -0,0 +1,83 @@
#!/bin/sh
set -e
CREATE_DT='_PLACE_HOLDER_'
REQUEST_VER_NO='_PLACE_HOLDER_'
REQUEST_VER_STAT='_PLACE_HOLDER_'
if [ `id -u` -ne 0 ];then
echo ""
echo "Error: please run hotfix as root."
echo ""
exit 1
fi
PATH_ROOT=$(cd "$(dirname "$0")"; pwd)
PATH_FILES=${PATH_ROOT}/files
DAEMON_FILE=/etc/init.d/teleport
NOW_DT=`date "+%Y%m%d.%H%M%S"`
echo '============================================='
echo " Teleport Hotfix for ${REQUEST_VER_NO}-${REQUEST_VER_STAT}"
echo " create at ${CREATE_DT}"
echo '============================================='
inst_path=`cat ${DAEMON_FILE} | grep "DAEMON_PATH=" | awk -F= '{print $2}'`
if [ 'x-$inst_path' == 'x-' ]; then
echo "Error: teleport installation not detected on your system."
echo "hotfix not patch, exit."
exit 1
else
echo "teleport installation detected at ${inst_path}"
fi
ver_file=${inst_path}/www/teleport/webroot/app/app_ver.py
ver_no=`cat ${ver_file} | grep "TP_SERVER_VER = " | awk -F= '{print $2}' | awk -F\" '{print $2}'`
ver_stat=`cat ${ver_file} | grep "TP_STATE_VER = " | awk -F= '{print $2}' | awk -F\" '{print $2}'`
miss_match_ver=0
if [ "${ver_no}" != "${REQUEST_VER_NO}" ]; then
miss_match_ver=1
fi
if [ "${ver_stat}" != "${REQUEST_VER_STAT}" ]; then
miss_match_ver=1
fi
if [ ${miss_match_ver} != 0 ]; then
echo "Error: this hotfix works for ${REQUEST_VER_NO}-${REQUEST_VER_STAT}, but your installation is ${ver_no} ${ver_stat}"
echo 'hotfix not patch, exit.'
exit 1
fi
miss_match_file=0
if [ ! -f "${inst_path}/www/teleport/webroot/app/controller/audit.py" ]; then
miss_match_file=1
fi
if [ ! -f "${inst_path}/www/teleport/webroot/app/controller/auth.py" ]; then
miss_match_file=1
fi
if [ ${miss_match_ver} != 0 ]; then
echo "Error: target file to be fix not found."
echo 'hotfix not patch, exit.'
exit 1
fi
echo "patching..."
echo " backup ${inst_path}/www/teleport/webroot/app/controller/audit.py"
mv "${inst_path}/www/teleport/webroot/app/controller/audit.py" "${inst_path}/www/teleport/webroot/app/controller/audit.py.hotfix.${NOW_DT}"
echo " backup ${inst_path}/www/teleport/webroot/app/controller/auth.py"
mv "${inst_path}/www/teleport/webroot/app/controller/auth.py" "${inst_path}/www/teleport/webroot/app/controller/auth.py.hotfix.${NOW_DT}"
echo " fix ${inst_path}/www/teleport/webroot/app/controller/audit.py"
cp "${PATH_FILES}/controller/audit.py" "${inst_path}/www/teleport/webroot/app/controller/audit.py"
echo " fix ${inst_path}/www/teleport/webroot/app/controller/auth.py"
cp "${PATH_FILES}/controller/auth.py" "${inst_path}/www/teleport/webroot/app/controller/auth.py"
echo ''
echo "done, now please restart teleport web server by following command:"
echo ''
echo 'sudo /etc/init.d/teleport restart web'
echo ''

View File

@ -0,0 +1,49 @@
#!/bin/sh
set -e
REQUEST_VER_NO='3.6.3'
REQUEST_VER_STAT='b2'
HOTFIX_CREATE_DAY=`date "+%Y%m%d"`
HOTFIX=tp-hotfix-${HOTFIX_CREATE_DAY}-${REQUEST_VER_NO}-${REQUEST_VER_STAT}
PATH_ROOT=$(cd "$(dirname "$0")/../../.."; pwd)
PATH_THIS=$(cd "$(dirname "$0")"; pwd)
PATH_BASE=${PATH_THIS}/base
PATH_DATA=${PATH_THIS}/${HOTFIX}
PATH_FILES=${PATH_DATA}/files
NOW_DT_STR=`date "+%Y-%m-%d %H:%M:%S"`
echo "PATH_ROOT: ${PATH_ROOT}"
echo "PATH_THIS: ${PATH_THIS}"
echo "PATH_BASE: ${PATH_BASE}"
echo "PATH_DATA: ${PATH_DATA}"
echo "PATH_FILES: ${PATH_FILES}"
if [ -d "${PATH_DATA}" ]; then
rm -rf "${PATH_DATA}"
fi
# if [ -d "${PATH_FILES}" ]; then
# rm -rf "${PATH_FILES}"
# fi
mkdir -p "${PATH_FILES}/controller"
# mkdir -p "${PATH_FILES}/model"
cp "${PATH_BASE}/README.txt" "${PATH_DATA}/."
cp "${PATH_BASE}/tp-hotfix.sh" "${PATH_DATA}/."
cp "${PATH_ROOT}/server/www/teleport/webroot/app/controller/audit.py" "${PATH_FILES}/controller/."
cp "${PATH_ROOT}/server/www/teleport/webroot/app/controller/auth.py" "${PATH_FILES}/controller/."
# 替换脚本文件中的参数部分第4/5/6行
sed -i ".bak" "4s/.*/CREATE_DT='${NOW_DT_STR}'/" "${PATH_DATA}/tp-hotfix.sh"
sed -i ".bak" "5s/.*/REQUEST_VER_NO='${REQUEST_VER_NO}'/" "${PATH_DATA}/tp-hotfix.sh"
sed -i ".bak" "6s/.*/REQUEST_VER_STAT='${REQUEST_VER_STAT}'/" "${PATH_DATA}/tp-hotfix.sh"
rm -rf "${PATH_DATA}/tp-hotfix.sh.bak"
chmod +x "${PATH_DATA}/tp-hotfix.sh"
tar zcvf "${HOTFIX}.tar.gz" ./${HOTFIX}

24
start_web.sh Normal file
View File

@ -0,0 +1,24 @@
#!/bin/bash
# python -B ./server/www/teleport/app_bootstrap.py
#
pyexec=/usr/local/bin/python3
pipexec=/usr/local/bin/pip3
# ${pipexec} install --upgrade pip
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ tornado
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ mako
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ psutil
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ pymysql
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ qrcode
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ ldap3
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ pillow
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ wheezy.captcha
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ pyasn1
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ cryptography
# ${pipexec} --trusted-host mirrors.aliyun.com install -i http://mirrors.aliyun.com/pypi/simple/ cffi
${pyexec} -B ./server/www/teleport/app_bootstrap.py