def check_auth_publickey(self, username, key): pubkey = key.get_base64() addr = self.sock_addr[0] if username == "sshproxy-IPC": try: hostkey_file = get_config('sshproxy').get('hostkey_file') hostkey = paramiko.DSSKey(filename=hostkey_file).get_base64() auth_keys_file = get_config('sipc')['authorized_keys'] if os.path.isfile(auth_keys_file): authorized_keys = open(auth_keys_file).readlines() else: authorized_keys = [] authorized_keys.append(hostkey) if not len([k for k in authorized_keys if pubkey in k]): log.error("ATTENTION: unauthorized attempt to connect " "on IPC channel from %s@%s" % (username, addr)) return paramiko.AUTH_FAILED except: log.exception("SIPC: exception in check_auth_pubkey") return paramiko.AUTH_FAILED self.username = username return paramiko.AUTH_SUCCESSFUL log.error("ATTENTION: unauthorized attempt to connect " "on IPC channel from %s@%s" % (username, addr)) return paramiko.AUTH_FAILED
def check_auth_publickey(self, username, key): pubkey = key.get_base64() addr = self.sock_addr[0] if username == "sshproxy-IPC": try: hostkey_file = get_config('sshproxy').get('hostkey_file') hostkey = paramiko.DSSKey(filename=hostkey_file).get_base64() auth_keys_file = get_config('sipc')['authorized_keys'] if os.path.isfile(auth_keys_file): authorized_keys = open(auth_keys_file).readlines() else: authorized_keys = [] authorized_keys.append(hostkey) if not len([ k for k in authorized_keys if pubkey in k ]): log.error("ATTENTION: unauthorized attempt to connect " "on IPC channel from %s@%s" % (username, addr)) return paramiko.AUTH_FAILED except: log.exception("SIPC: exception in check_auth_pubkey") return paramiko.AUTH_FAILED self.username = username return paramiko.AUTH_SUCCESSFUL log.error("ATTENTION: unauthorized attempt to connect " "on IPC channel from %s@%s" % (username, addr)) return paramiko.AUTH_FAILED
def __setup__(): from sshproxy import menu from sshproxy.config import get_config cfg = get_config('sshproxy') items = [] if cfg['acl_db'] == 'ini_db': import acl def update(value): get_config('acl_db.ini')['file'] = value items.append(menu.MenuInput('ACL database file', "", get_config('acl_db.ini').get('file', raw=True), cb=update)) if cfg['client_db'] == 'ini_db': import client def update(value): get_config('client_db.ini')['file'] = value items.append(menu.MenuInput('Client database file', "", get_config('client_db.ini').get('file', raw=True), cb=update)) if cfg['site_db'] == 'ini_db': import site def update(value): get_config('site_db.ini')['db_path'] = value items.append(menu.MenuInput('Site database directory', "", get_config('site_db.ini').get('db_path', raw=True), cb=update)) return menu.MenuSub("FileDB", "", *items)
def __reginit__(self, *args, **kw): conf = get_config("logusers") if not os.path.isdir(conf["logdir"]): os.makedirs(conf["logdir"]) self.logdir = conf["logdir"] # fill our translation table for key in dir(keys): if key[0] == "_" or not isinstance(getattr(keys, key), str): continue self.tr_table[getattr(keys, key)] = "<%s>" % key for key, value in self._tr_table.items(): self.tr_table[key] = value ProxyShell.__reginit__(self, *args, **kw) user = self.ipc_chan.call("get_ns_tag", namespace="client", tag="username") path = os.path.join(self.logdir, user) if not os.path.isdir(path): os.makedirs(path) site_login = self.ipc_chan.call("get_ns_tag", namespace="site", tag="login") site_name = self.ipc_chan.call("get_ns_tag", namespace="site", tag="name") site = "%s@%s" % (site_login, site_name) logfile = os.path.join(path, site) self.log = open(logfile, "a")
def __setup__(): from sshproxy import menu from sshproxy.config import get_config cfg = get_config('sshproxy') items = [] if cfg['acl_db'] == 'mysql_db': import acl items.append(menu.Menu('ACL database', "", *get_menu_items('acl_db'))) if cfg['client_db'] == 'mysql_db': import client items.append(menu.Menu('Client database file', "", *get_menu_items('client_db'))) if cfg['site_db'] == 'mysql_db': import site items.append(menu.Menu('Site database directory', "", *get_menu_items('site_db'))) return menu.MenuSub("MySQLDB", "", *items)
def __reginit__(self, *args, **kw): conf = get_config('logusers') if not os.path.isdir(conf['logdir']): os.makedirs(conf['logdir']) self.logdir = conf['logdir'] # fill our translation table for key in dir(keys): if key[0] == '_' or not isinstance(getattr(keys, key), str): continue self.tr_table[getattr(keys, key)] = '<%s>' % key for key, value in self._tr_table.items(): self.tr_table[key] = value ProxyShell.__reginit__(self, *args, **kw) user = self.ipc_chan.call('get_ns_tag', namespace='client', tag='username') path = os.path.join(self.logdir, user) if not os.path.isdir(path): os.makedirs(path) site_login = self.ipc_chan.call('get_ns_tag', namespace='site', tag='login') site_name = self.ipc_chan.call('get_ns_tag', namespace='site', tag='name') site = '%s@%s' % (site_login, site_name) logfile = os.path.join(path, site) self.log = open(logfile, 'a')
def __reginit__(self, *args, **kw): conf = get_config('ttyrpl') if not os.path.isdir(conf['logdir']): os.makedirs(conf['logdir']) self.logdir = conf['logdir'] ProxyShell.__reginit__(self, *args, **kw) user = self.ipc_chan.call('get_ns_tag', namespace='client', tag='username') path = os.path.join(self.logdir, user) if not os.path.isdir(path): os.makedirs(path) site_login = self.ipc_chan.call('get_ns_tag', namespace='site', tag='login') site_name = self.ipc_chan.call('get_ns_tag', namespace='site', tag='name') site = '%s@%s' % (site_login, site_name) path = os.path.join(path, site) if not os.path.isdir(path): os.makedirs(path) date = datetime.datetime.now().isoformat() logfile = os.path.join(path, date) self.log = TTYrplLogger(logfile) self.log.log_user("%s->%s" % (user, site))
def authenticate(self, **tokens): resp = False for token in self.auth_token_order(): if token in tokens.keys() and tokens[token] is not None: if token == 'password': query = """select id from client where uid='%s' and '%s' = password""" % (Q(self.username), Q(sha.new(tokens['password']).hexdigest())) if self.sql_get(query): resp = True break elif token == 'pubkey': pubkeys = self.get_token(token, '').split('\n') pubkeys = [ pk.split()[0] for pk in pubkeys if len(pk) ] for pk in pubkeys: if pk == tokens[token]: resp = True break ClientDB()._unauth_pubkey = tokens[token] elif self.get_token(token) == tokens[token]: resp = True break pubkey = getattr(ClientDB(), '_unauth_pubkey', None) if resp and pubkey and istrue(get_config('sshproxy')['auto_add_key']): tokens['pubkey'] = pubkey if self.add_pubkey(**tokens): Server().message_client("WARNING: Your public key" " has been added to the keyring\n") del ClientDB()._unauth_pubkey return resp
def authenticate(self, **tokens): resp = False for token in self.auth_token_order(): if token in tokens.keys() and tokens[token] is not None: if token == 'password': query = """select id from client where uid='%s' and '%s' = password""" % ( Q(self.username), Q(sha.new(tokens['password']).hexdigest())) if self.sql_get(query): resp = True break elif token == 'pubkey': pubkeys = self.get_token(token, '').split('\n') pubkeys = [pk.split()[0] for pk in pubkeys if len(pk)] for pk in pubkeys: if pk == tokens[token]: resp = True break ClientDB()._unauth_pubkey = tokens[token] elif self.get_token(token) == tokens[token]: resp = True break pubkey = getattr(ClientDB(), '_unauth_pubkey', None) if resp and pubkey and istrue(get_config('sshproxy')['auto_add_key']): tokens['pubkey'] = pubkey if self.add_pubkey(**tokens): Server().message_client("WARNING: Your public key" " has been added to the keyring\n") del ClientDB()._unauth_pubkey return resp
def __setup__(): from sshproxy import menu from sshproxy.config import get_config from sshproxy.util import istrue import notifier cfg = get_config('email_notifier') items = [] def update_admin_email(value): cfg['admin_email'] = value def update_smtp_server(value): cfg['smtp_server'] = value def update_smtp_port(value): cfg['smtp_port'] = value def update_smtp_tls(value): if istrue(value): cfg['smtp_tls'] = 'yes' else: cfg['smtp_tls'] = 'no' def update_smtp_login(value): cfg['smtp_login'] = value def update_smtp_password(value): cfg['smtp_password'] = value def update_smtp_sender(value): cfg['smtp_sender'] = value items.append(menu.MenuInput("Email used for notifications.", "", cfg.get('admin_email', raw=True), cb=update_admin_email)) items.append(menu.MenuInput("Sender email.", "", cfg.get('smtp_sender', raw=True), cb=update_smtp_password)) items.append(menu.MenuInput("SMTP Server IP address.", "", cfg.get('smtp_server', raw=True), cb=update_smtp_server)) items.append(menu.MenuInput("SMTP Server port (default 25).", "25", cfg.get('smtp_port', raw=True), cb=update_smtp_port)) items.append(menu.MenuInput("Use TLS for SMTP connection [yes/no].", "", cfg.get('smtp_tls', raw=True), cb=update_smtp_tls)) items.append(menu.MenuInput("SMTP login, leave empty if not used.", "", cfg.get('smtp_login', raw=True), cb=update_smtp_login)) items.append(menu.MenuInput("SMTP password, leave empty if not used.", "", cfg.get('smtp_password', raw=True), cb=update_smtp_password)) return items
def __setup__(): from sshproxy import menu from sshproxy.config import get_config cfg = get_config('sshproxy') items = [] if cfg['acl_db'] == 'ini_db': import acl def update(value): get_config('acl_db.ini')['file'] = value items.append( menu.MenuInput('ACL database file', "", get_config('acl_db.ini').get('file', raw=True), cb=update)) if cfg['client_db'] == 'ini_db': import client def update(value): get_config('client_db.ini')['file'] = value items.append( menu.MenuInput('Client database file', "", get_config('client_db.ini').get('file', raw=True), cb=update)) if cfg['site_db'] == 'ini_db': import site def update(value): get_config('site_db.ini')['db_path'] = value items.append( menu.MenuInput('Site database directory', "", get_config('site_db.ini').get('db_path', raw=True), cb=update)) return menu.MenuSub("FileDB", "", *items)
def get_config_file(self): clientfile = get_config('client_db.ini')['file'] if not os.path.exists(clientfile): open(clientfile, 'w').close() os.chmod(clientfile, 0600) # no need to parse an empty file return None file = ConfigParser() file.read(clientfile) return file
def save_rules(self): rulefile = get_config('acl_db.ini')['file'] if not os.path.exists(rulefile): open(rulefile, 'w').close() fd = open(rulefile+'.new', 'w') for acl in self.rules.keys(): for rule in self.rules[acl]: fd.write('%s:\n %s\n\n' % (acl, rule.rule.replace('\n', '\n '))) fd.close() os.rename(rulefile+'.new', rulefile)
def save_rules(self): rulefile = get_config('acl_db.ini')['file'] if not os.path.exists(rulefile): open(rulefile, 'w').close() fd = open(rulefile + '.new', 'w') for acl in self.rules.keys(): for rule in self.rules[acl]: fd.write('%s:\n %s\n\n' % (acl, rule.rule.replace('\n', '\n '))) fd.close() os.rename(rulefile + '.new', rulefile)
def _sock_connect(self, real_sock, sock_addr): if self.sock_type == socket.AF_UNIX and self.sock_addr[0] == '\x00': return IPCClient._sock_connect(self, real_sock, sock_addr) real_sock.connect(sock_addr) log.info("IPC: Connecting to secure server %s", sock_addr) transport = paramiko.Transport(real_sock) ev = threading.Event() transport.start_client(ev) while not ev.isSet(): ev.wait(0.5) if not transport.is_active(): log.error("SIPC: SSH negotiation failed") raise 'SSH negotiation failed' ev = threading.Event() key_file = get_config("sipc").get("key_file") if not os.path.isfile(key_file): key_file = get_config("sshproxy").get("hostkey_file") key = paramiko.DSSKey(filename=key_file) transport.auth_publickey('sshproxy-IPC', key, ev) while not ev.isSet(): ev.wait(0.5) if not transport.is_authenticated(): log.error("SIPC: SSH authentication failed") raise 'SSH authentication failed' sock = transport.open_channel('sshproxy-IPC') self.real_sock = real_sock self.transport = transport return sock
def get_config_file(name): sitepath = get_config('site_db.ini')['db_path'] if not os.path.exists(sitepath): os.makedirs(sitepath) # no need to search for the site file return None sitefile = os.path.join(sitepath, name) if not os.path.exists(sitefile): return None file = ConfigParser() file.read(sitefile) return file
def __setup__(): from sshproxy import menu from sshproxy.config import get_config import ttyrpl cfg = get_config("ttyrpl") items = [] def update(value): cfg["logdir"] = value items.append(menu.MenuInput("Log directory", "", cfg.get("logdir", raw=True), cb=update)) return items
def get_public_key(pkey): # accept a string or a PKey object from sshproxy.config import get_config if isinstance(pkey, str): if len(pkey): pkey = get_dss_key_from_string(pkey) else: return None cfg = get_config('sshproxy') pkey_id = cfg.get('pkey_id', '*****@*****.**') return (pkey.get_name(), pkey.get_base64(), pkey_id)
def __init_plugin__(): from sshproxy.config import get_config cfg = get_config('sshproxy') if cfg['acl_db'] == 'ini_db': from acl import FileACLDB FileACLDB.register() if cfg['client_db'] == 'ini_db': from client import FileClientDB, FileClientInfo FileClientDB.register() FileClientInfo.register() if cfg['site_db'] == 'ini_db': from site import FileSiteInfo, FileSiteDB FileSiteInfo.register() FileSiteDB.register()
def __init_plugin__(): from sshproxy.config import get_config cfg = get_config('sshproxy') if cfg['acl_db'] == 'mysql_db': from acl import MySQLACLDB MySQLACLDB.register() if cfg['client_db'] == 'mysql_db': from client import MySQLClientInfo, MySQLClientDB MySQLClientInfo.register() MySQLClientDB.register() if cfg['site_db'] == 'mysql_db': from site import MySQLSiteInfo, MySQLSiteDB MySQLSiteInfo.register() MySQLSiteDB.register()
def report_failure(self, reason, *args, **kwargs): """Reporting error @param reason: reason of failure""" from datetime import datetime cfg = get_config('email_notifier') tpldict = {} tpldict['reason'] = reason if len(args) > 0: tpldict['msg'] = args[0] else: tpldict['msg'] = "No additional message." tpldict['client'] = self.username tpldict['site'] = self.g_site tpldict['when'] = datetime.now() tpldict['conntype'] = self.g_conn_type tpldict['sshproxy_id'] = cfg['smtp_sender'] # ? server = cfg['smtp_server'] try: port = cfg['smtp_port'] except ValueError: port = 25 login = cfg['smtp_login'] password = cfg['smtp_password'] admin_email = cfg['admin_email'] sender = cfg['smtp_sender'] tls = istrue(cfg["smtp_tls"]) msg = cfg['message_template'] % tpldict if admin_email != "" and "@" in admin_email: email = Email(server, port, login, password, tls=tls) email.new(admin_email, sender, "Failure Report", msg) try: email.send_email() except smtplib.SMTPException, e: log.exception(e)
def open_db(self): cfg = get_config('%s.mysql' % self._db_handler) conid = 'mysql://%s@%s:%s/%s' % (cfg['user'], cfg['host'], cfg['port'], cfg['db']) if not self.__db.has_key(conid): try: MySQLDB.__db[conid] = MySQLdb.connect(host=cfg['host'], port=cfg['port'], db=cfg['db'], user=cfg['user'], passwd=cfg['password']) except: if not os.environ.get('SSHPROXY_WIZARD', None): raise self.db = self.__db[conid]
def __setup__(): from sshproxy import menu from sshproxy.config import get_config import logusers cfg = get_config('logusers') items = [] def update(value): cfg['logdir'] = value items.append(menu.MenuInput('Log directory', "", cfg.get('logdir', raw=True), cb=update)) return items
def load_rules(self): rulefile = get_config('acl_db.ini')['file'] if not os.path.exists(rulefile): open(rulefile, 'w').close() os.chmod(rulefile, 0600) # no need to parse an empty file return None fd = open(rulefile) nline = [] line = [] for linepart in fd.readlines(): if not linepart.strip() or linepart.strip()[0] == '#': continue if linepart[0] not in (' ', '\t'): nline = [linepart.strip()] if not line: line = nline continue else: line.append(linepart.strip()) continue try: acl, rule = (' '.join(line)).split(':', 1) if rule is None or not rule.strip(): raise ValueError except ValueError: # drop rule, it won't parse anyway log.warning('Dropped unparseable rule %s' % acl) line = nline continue self.add_rule(acl=acl, rule=rule.lstrip()) line = nline if line: try: acl, rule = (' '.join(line)).split(':', 1) if rule is None or not rule.strip(): raise ValueError self.add_rule(acl=acl, rule=rule.lstrip()) except ValueError: # drop rule, it won't parse anyway log.warning('Dropped unparseable rule %s' % acl) pass fd.close()
def load_rules(self): rulefile = get_config('acl_db.ini')['file'] if not os.path.exists(rulefile): open(rulefile, 'w').close() os.chmod(rulefile, 0600) # no need to parse an empty file return None fd = open(rulefile) nline = [] line = [] for linepart in fd.readlines(): if not linepart.strip() or linepart.strip()[0] == '#': continue if linepart[0] not in (' ', '\t'): nline = [ linepart.strip() ] if not line: line = nline continue else: line.append(linepart.strip()) continue try: acl, rule = (' '.join(line)).split(':', 1) if rule is None or not rule.strip(): raise ValueError except ValueError: # drop rule, it won't parse anyway log.warning('Dropped unparseable rule %s' % acl) line = nline continue self.add_rule(acl=acl, rule=rule.lstrip()) line = nline if line: try: acl, rule = (' '.join(line)).split(':', 1) if rule is None or not rule.strip(): raise ValueError self.add_rule(acl=acl, rule=rule.lstrip()) except ValueError: # drop rule, it won't parse anyway log.warning('Dropped unparseable rule %s' % acl) pass fd.close()
def get_menu_items(db_type): from sshproxy import menu from sshproxy.config import get_config def update(value, item, db_type): cfg = get_config('%s.mysql' % db_type) cfg[item] = value cfg = get_config('%s.mysql' % db_type) return [ menu.MenuInput(title, "", cfg[name], update, item=name, db_type=db_type) for name, title in (('host', 'Database host'), ('user', 'Database user'), ('password', 'Database password'), ('db', 'Database name'), ('port', 'Database port')) ]
def save(self): file = get_config_file(self.name) if not file: return if self.login: if not file.has_section(self.login): file.add_section(self.login) for tag, value in self.l_tokens.items(): file.set(self.login, tag, str(value or '')) else: for tag, value in self.s_tokens.items(): file.set('DEFAULT', tag, str(value or '')) sitepath = get_config('site_db.ini')['db_path'] sitefile = os.path.join(sitepath, self.name) fd = open(sitefile + '.new', 'w') file.write(fd) fd.close() os.rename(sitefile + '.new', sitefile)
def del_site(self, sitename, **tokens): sitepath = get_config('site_db.ini')['db_path'] login, name = self.split_user_site(sitename) if login == '*': sitename = name if not os.path.exists(sitepath) or not self.exists(sitename, **tokens): return 'Site %s does not exist' % sitename sitefile = os.path.join(sitepath, name) file = get_config_file(name) if login: ret = False if login == '*': for login in file.sections(): file.remove_section(login) ret = True sitename = '*@%s' % name else: file.remove_section(login) ret = True fd = open(sitefile + '.new', 'w') file.write(fd) fd.close() os.rename(sitefile + '.new', sitefile) if not ret: return 'Site %s does not exist' % sitename return 'Site %s deleted.' % sitename count = len(file.sections()) if count > 0: return "Site %s has still %d logins" % (sitename, count) os.unlink(sitefile) return 'Site %s deleted' % sitename
def list_site_users(self, **tokens): sitepath = get_config('site_db.ini')['db_path'] if not os.path.exists(sitepath): os.makedirs(sitepath) # no need to search for the site files return [] sitefiles = os.listdir(sitepath) sites = [] for sitefile in sitefiles: if sitefile[0] == '.': continue file = ConfigParser() file.read(os.path.join(sitepath, sitefile)) users = file.sections() if len(users): for user in users: sites.append(SiteInfo(user, sitefile)) else: sites.append(SiteInfo(None, sitefile)) return sites
def add_site(self, sitename, **tokens): sitepath = get_config('site_db.ini')['db_path'] if not os.path.exists(sitepath): os.makedirs(sitepath) login, name = self.split_user_site(sitename) if login == '*': return "'*' is not allowed, be more specific." if self.exists(sitename, **tokens): return 'Site %s does already exist' % sitename sitefile = os.path.join(sitepath, name) if not os.path.exists(sitefile): if login: return 'Site %s does not exist. Please create it first.' % name # touch the file open(sitefile, 'w').close() os.chmod(sitefile, 0600) siteinfo = SiteInfo(login, name, **tokens) siteinfo.save() return 'Site %s added' % sitename
def save(self, file=None): if not file: file = self.get_config_file() if not file: return if self.username: if not file.has_section(self.username): file.add_section(self.username) for tag, value in self.tokens.items(): if tag in ('username', 'ip_addr'): continue elif value and str(value): file.set(self.username, tag, str(value)) elif file.has_option(self.username, tag): file.remove_option(self.username, tag) clientfile = get_config('client_db.ini')['file'] fd = open(clientfile + '.new', 'w') file.write(fd) fd.close() os.rename(clientfile + '.new', clientfile)
def save(self, file=None): if not file: file = self.get_config_file() if not file: return if self.username: if not file.has_section(self.username): file.add_section(self.username) for tag, value in self.tokens.items(): if tag in ('username', 'ip_addr'): continue elif value and str(value): file.set(self.username, tag, str(value)) elif file.has_option(self.username, tag): file.remove_option(self.username, tag) clientfile = get_config('client_db.ini')['file'] fd = open(clientfile+'.new', 'w') file.write(fd) fd.close() os.rename(clientfile+'.new', clientfile)
def __setup__(): from sshproxy import menu from sshproxy.config import get_config cfg = get_config('sshproxy') items = [] if cfg['acl_db'] == 'mysql_db': import acl items.append(menu.Menu('ACL database', "", *get_menu_items('acl_db'))) if cfg['client_db'] == 'mysql_db': import client items.append( menu.Menu('Client database file', "", *get_menu_items('client_db'))) if cfg['site_db'] == 'mysql_db': import site items.append( menu.Menu('Site database directory', "", *get_menu_items('site_db'))) return menu.MenuSub("MySQLDB", "", *items)
def update(value, item, db_type): cfg = get_config('%s.mysql' % db_type) cfg[item] = value
def update(value): get_config('acl_db.ini')['file'] = value
def update(value): get_config('site_db.ini')['db_path'] = value
def update(value): get_config('client_db.ini')['file'] = value
def __setup__(): from sshproxy import menu from sshproxy.config import get_config from sshproxy.util import istrue import notifier cfg = get_config('email_notifier') items = [] def update_admin_email(value): cfg['admin_email'] = value def update_smtp_server(value): cfg['smtp_server'] = value def update_smtp_port(value): cfg['smtp_port'] = value def update_smtp_tls(value): if istrue(value): cfg['smtp_tls'] = 'yes' else: cfg['smtp_tls'] = 'no' def update_smtp_login(value): cfg['smtp_login'] = value def update_smtp_password(value): cfg['smtp_password'] = value def update_smtp_sender(value): cfg['smtp_sender'] = value items.append( menu.MenuInput("Email used for notifications.", "", cfg.get('admin_email', raw=True), cb=update_admin_email)) items.append( menu.MenuInput("Sender email.", "", cfg.get('smtp_sender', raw=True), cb=update_smtp_password)) items.append( menu.MenuInput("SMTP Server IP address.", "", cfg.get('smtp_server', raw=True), cb=update_smtp_server)) items.append( menu.MenuInput("SMTP Server port (default 25).", "25", cfg.get('smtp_port', raw=True), cb=update_smtp_port)) items.append( menu.MenuInput("Use TLS for SMTP connection [yes/no].", "", cfg.get('smtp_tls', raw=True), cb=update_smtp_tls)) items.append( menu.MenuInput("SMTP login, leave empty if not used.", "", cfg.get('smtp_login', raw=True), cb=update_smtp_login)) items.append( menu.MenuInput("SMTP password, leave empty if not used.", "", cfg.get('smtp_password', raw=True), cb=update_smtp_password)) return items