#!/usr/bin/python3
# -*- coding: utf-8 -*-

import os
import sys

import logging
import configparser
from gi.repository import GLib
import dbus
import dbus.service
import dbus.mainloop.glib

import requests
import platform
import json
import socket
import random
import shutil
import subprocess
from urllib import parse
import uuid

from datetime import datetime
import base64

import gettext

gettext.bindtextdomain('kim-domain', '/usr/share/kim-client/locale')
gettext.textdomain('kim-domain')
_ = gettext.gettext

logger = logging.getLogger()

SUCCESS = 0
NETWORK_ERROR = 100
REQUEST_ERROR = 101
JOIN_ERROR = 200
UNENROLL_ERROR = 300
KCM_ERROR = 400

USER_PWD_EXPIRE = 201

kim_dbus = None
KIM_RPC_PORT = 31443
KCM_JOIN_PORT = 30234
KCM_RPC_PORT = 30234

HTTP_SCHEMA = 'https'

kim_config_path = "/etc/kim/default.conf"

kim_nss_service = ('su', 'lightdm', 'ukui-greeter', 'login', 'sshd', 'id', 'getent')

# Used by standard_logging_setup() for console message
LOGGING_FORMAT_STANDARD_CONSOLE = '%(name)-12s: %(levelname)-8s %(message)s'
# Used by standard_logging_setup() for file message
LOGGING_FORMAT_STANDARD_FILE = '%(asctime)s %(levelname)s %(message)s'

auth_type = None
remote_server = None
new_hostname = None
auth_token = None

requests.packages.urllib3.disable_warnings()

class InstallError(Exception):

    def __init__(self, msg = '', rval = 1):
        if msg is None:
            msg = _('undefined error') #'未定义错误'
        super(InstallError, self).__init__(msg)
        self.rval = rval

    @property
    def msg(self):
        return str(self)

def cmd_run(args, skip_output=False):
    p_in = None
    p_out = None
    p_err = None
    p_in = subprocess.PIPE
    if skip_output:
        p_out = p_err = open(os.devnull, 'w')
    else:
        p_out = subprocess.PIPE
        p_err = subprocess.PIPE
    try:
        # pylint: disable=subprocess-popen-preexec-fn
        p = subprocess.Popen(args, stdin=p_in, stdout=p_out, stderr=p_err)
        stdout, stderr = p.communicate(timeout=5)
    except KeyboardInterrupt:
        logger.debug('Process interrupted')
        p.wait()
        raise
    except:
        logger.debug('Process execution failed')
        raise
    finally:
        if skip_output:
            p_out.close()
    return p.returncode, stdout.decode(), stderr.decode()

def standard_logging_setup(filename=None, verbose=False, debug=False,
                           filemode='w', console_format=None):
    if console_format is None:
        console_format = LOGGING_FORMAT_STANDARD_CONSOLE

    root_logger = logging.getLogger()
    root_logger.setLevel(logging.DEBUG)

    # File output is always logged at debug level
    if filename is not None:
        umask = os.umask(0o133)
        try:
            file_handler = logging.FileHandler(filename, mode=filemode)
        finally:
            os.umask(umask)
        file_handler.setLevel(logging.DEBUG)
        file_handler.setFormatter(logging.Formatter(LOGGING_FORMAT_STANDARD_FILE))
        root_logger.addHandler(file_handler)

    level = logging.ERROR
    if verbose:
        level = logging.INFO
    if debug:
        level = logging.DEBUG

    console_handler = logging.StreamHandler()
    console_handler.setLevel(level)
    console_handler.setFormatter(logging.Formatter(console_format))
    root_logger.addHandler(console_handler)

def extract_ip():
    st = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        st.connect(('10.255.255.255', 1))
        IP = st.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        st.close()
    return IP

### 获取终端序列号sn
def get_device_serialno():
    run_args = ['/usr/sbin/dmidecode', '-s', 'system-serial-number']
    try:
        ret, out, err = cmd_run(run_args)
    except Exception:
        return ''
    else:
        return out.rstrip('\n')

def get_devsn():
    run_args = ['/usr/bin/kylin_gen_register']
    try:
        ret, out, err = cmd_run(run_args)
    except Exception:
        return ''
    else:
        return out.rstrip('\n')

#获取系统版本
def get_os_version():
    os_version = 'Unknow'
    with open('/etc/os-release', 'r') as orl:
        for line in orl:
            if line.startswith('VERSION'):
                os_version=line.split('=')[1].rstrip('\n').strip('"')
                break
    return os_version

#获取运行环境PC、Server、Cloud
def get_run_env():
    if os.path.exists('/usr/bin/dpkg'):
        return 'PC'
    elif os.path.exists('/usr/bin/rpm'):
        return 'Server'
    else:
        return 'Cloud'

#获取客户端版本
def get_client_version():
    client_version = ''
    run_env = get_run_env()
    if run_env == 'PC':
        cmd = 'dpkg -s hedron-client'
    elif run_env == 'Server':
        cmd = 'rpm -qi kim-client'
    else:
        cmd = 'dpkg -s kim-client'
    with os.popen(cmd) as cv:
        for line in cv:
            if line.startswith('Version'):
                client_version = line.split(':')[1].rstrip('\n').strip(' ')
                break
    return client_version

def get_mac_address():
    mac_num = hex(uuid.getnode()).replace('0x', '')
    mac = ':'.join(mac_num[i: i + 2] for i in range(0, 11, 2))
    return mac

def check_if_keyring_support():
    run_args = ['/usr/bin/keyctl', 'get_persistent', '@u']
    try:
        ret, out, err = cmd_run(run_args)
    except Exception:
        return False
    else:
        return ret == 0

### 获取默认的服务器配置
def get_server_info():
    global KIM_RPC_PORT
    global KCM_JOIN_PORT
    global KCM_RPC_PORT
    config = configparser.ConfigParser()
    config.read('/etc/.kimserver.conf', encoding='utf-8')
    server = config.get('default', 'server')
    port = config.getint('default', 'port')
    if KIM_RPC_PORT != port:
        KIM_RPC_PORT = port
    if KCM_JOIN_PORT != port:
        KCM_JOIN_PORT = port
        KCM_RPC_PORT = KCM_JOIN_PORT
    return server, port

def get_kcm_server(sect='kcm'):
    config = configparser.ConfigParser()
    config.read('/etc/kim/default.conf', encoding='utf-8')
    try:
        server = config.get(sect, 'server')
        port = config.getint(sect, 'port')
    except Exception:
        raise InstallError('Not enrolled.', rval=JOIN_ERROR)
    return server, port

def update_server_info(server, port=None):
    config = configparser.ConfigParser()
    config.read('/etc/.kimserver.conf', encoding='utf-8')
    if not config.has_section('default'):
        config.add_section('default')
    config.set('default', 'server', server)
    if port is None:
        port = KIM_RPC_PORT
    config.set('default', 'port', str(port))
    with open('/etc/.kimserver.conf', 'w') as f:
        config.write(f)

def enable_kimbackend():
    cmd_run(['/usr/bin/systemctl', 'restart', 'kimbackend.service'])
    cmd_run(['/usr/bin/systemctl', 'enable', 'kimbackend.service'])

def disable_kimbackend():
    cmd_run(['/usr/bin/systemctl', 'disable', 'kimbackend.service'])
    cmd_run(['/usr/bin/systemctl', 'stop', 'kimbackend.service'])

def kim_access_control(enable):
    pol_link_dist = '/var/lib/polkit-1/localauthority/40-domain.d'
    pol_file_dir = '/usr/share/kim-daemon/pkla'
    sudo_link_dist = '/usr/lib/%s-linux-gnu/libsss_sudo.so' % platform.machine()
    sudo_file_path = '/usr/lib/libsudo-kim.so'
    sudo_bak_dist = '/var/lib/kim/bak/libsss_sudo.so'

    netconf = '/lib/NetworkManager/conf.d/10-polkit-false.conf'
    netconf_bak = '/var/lib/kim/bak/10-polkit-false.conf'
    if enable:
        if not os.path.islink(pol_link_dist):
            os.symlink(pol_file_dir, pol_link_dist)
        #if not os.path.islink(sudo_link_dist):
        #    os.symlink(sudo_file_path, sudo_link_dist)
        if os.path.exists(sudo_link_dist):
            if not os.path.islink(sudo_link_dist):
                shutil.move(sudo_link_dist, sudo_bak_dist)
                os.symlink(sudo_file_path, sudo_link_dist)
        else:
            os.symlink(sudo_file_path, sudo_link_dist)
        if os.path.exists(netconf):
            shutil.move(netconf, netconf_bak)
    else:
        if os.path.exists(pol_link_dist):
            os.unlink(pol_link_dist)
        if os.path.islink(sudo_link_dist):
            os.unlink(sudo_link_dist)
        if os.path.exists(sudo_bak_dist) and not os.path.exists(sudo_link_dist):
            shutil.move(sudo_bak_dist, sudo_link_dist)
        if os.path.exists(netconf_bak):
            shutil.move(netconf_bak, netconf)

def kim_configure(server, port, provider='kim', nossl = False):
    config = configparser.ConfigParser()
    config.add_section('global')
    config.set('global', 'provider', provider)
    config.set('global', 'cachetime', '900')
    config.set('global', 'nss', ','.join(kim_nss_service))
    config.add_section(provider)
    config.set(provider, 'server', server)
    if port == 0:
        port = KCM_JOIN_PORT
    config.set(provider, 'port', str(port))
    config.set(provider, 'nossl', str(nossl))
    with open(kim_config_path, 'w') as f:
        config.write(f)
    kim_config_krb5()
    kim_pam_enable()
    kim_nss_insert()
    kim_access_control(True)
    enable_kimbackend()

def kim_unconfigure():
    kim_access_control(False)
    kim_nss_remove()
    kim_pam_disable()
    disable_kimbackend()

def kim_config_krb5():
    config = configparser.RawConfigParser()
    config.add_section('libdefaults')
    #config.set('libdefaults', 'default_realm', None)
    config.set('libdefaults', 'dns_lookup_realm', 'false')
    config.set('libdefaults', 'dns_lookup_kdc', 'true')
    config.set('libdefaults', 'rdns', 'false')
    config.set('libdefaults', 'dns_canonicalize_hostname', 'false')
    config.set('libdefaults', 'ticket_lifetime', '24h')
    config.set('libdefaults', 'forwardable', 'true')
    config.set('libdefaults', 'udp_preference_limit', '0')
    if check_if_keyring_support():
        config.set('libdefaults', 'default_ccache_name', 'KEYRING:persistent:%{uid}')
    with open('/etc/krb5.conf', 'w') as f:
        config.write(f)



FIREFOX_PREFERENCES_FILENAME = "all-kimsso.js"
FIREFOX_PREFERENCES_REL_PATH = "browser/defaults/preferences"

FIREFOX_ESR_PATH = "/usr/lib/firefox-esr"


def configure_firefox(domain, firefox_dir = None):
    try:
        logger.debug("Setting up Firefox configuration.")

        preferences_dir = None

        # Check user specified location of firefox install directory
        if firefox_dir is not None:
            pref_path = os.path.join(firefox_dir,
                                     FIREFOX_PREFERENCES_REL_PATH)
            if os.path.isdir(pref_path):
                preferences_dir = pref_path
            else:
                logger.error("Directory '%s' does not exists.", pref_path)
        else:
            # test if firefox is installed
            if os.path.isdir(FIREFOX_ESR_PATH):
                pref_path = os.path.join(FIREFOX_ESR_PATH, FIREFOX_PREFERENCES_REL_PATH)
                if os.path.isdir(pref_path):
                    preferences_dir = pref_path

            else:
                logger.error(
                    "Firefox configuration skipped (Firefox not found).")
                return

        # setting up firefox
        if preferences_dir is not None:

            # user could specify relative path, we need to store absolute
            preferences_dir = os.path.abspath(preferences_dir)
            logger.debug(
                "Firefox preferences directory found '%s'.", preferences_dir)
            preferences_fname = os.path.join(
                preferences_dir, FIREFOX_PREFERENCES_FILENAME)
            logger.debug(
                "Firefox trusted uris will be set as '.%s' domain.", domain)
            logger.debug(
                "Firefox configuration will be stored in '%s' file.",
                preferences_fname)

            try:
                with open(preferences_fname, 'w') as f:
                    f.write('\n/* Kerberos SSO configuration */\n')
                    f.write('\n/* These are the defaults */\n')
                    f.write('pref("network.negotiate-auth.gsslib", "");\n')
                    f.write('pref("network.negotiate-auth.trusted-uris", ".%s");\n' % domain)
                    f.write('pref("network.negotiate-auth.using-native-gsslib", true);\n')
                    f.write('pref("network.negotiate-auth.allow-proxies", true);\n')
                logger.info("Firefox sucessfully configured.")
            except Exception as e:
                logger.debug(
                    "An error occured during creating preferences file: %s.",
                    e)
                logger.error("Firefox configuration failed.")
        else:
            logger.debug("Firefox preferences directory not found.")
            logger.error("Firefox configuration failed.")

    except Exception as e:
        logger.debug("%s", str(e))
        logger.error("Firefox configuration failed.")

CHROMIUM_PREFERENCES_FILENAME = "kimsso.json"
CHROMIUM_PREFERENCES_REL_PATH = "policies/managed"

CHROMIUM_PATH = "/etc/chromium-browser"

def configure_chromium(domain, chromium_dir=None):
    try:
        logger.debug("Setting up Chrome configuration.")
        preferences_dir = None
        if chromium_dir is not None:
            pref_path = os.path.join(chromium_dir, CHROMIUM_PREFERENCES_REL_PATH)
            if os.path.isdir(pref_path):
                preferences_dir = pref_path
            else:
                logger.error("Directory '%s' does not exists.", pref_path)
        else:
            if os.path.isdir(CHROMIUM_PATH):
                pref_path = os.path.join(CHROMIUM_PATH, CHROMIUM_PREFERENCES_REL_PATH)
                if os.path.isdir(pref_path):
                    preferences_dir = pref_path
            else:
                logger.error("Chromium configuration skipped (Chromium not found).")

        if preferences_dir is not None:
            preferences_dir = os.path.abspath(preferences_dir)
            logger.debug(
                "Chromium preferences directory found '%s'.", preferences_dir)
            preferences_fname = os.path.join(
                preferences_dir, CHROMIUM_PREFERENCES_FILENAME)
            logger.debug(
                "Chromium trusted uris will be set as '.%s' domain.", domain)
            logger.debug(
                "Chromium configuration will be stored in '%s' file.", preferences_fname)

            try:
                with open(preferences_fname, 'w') as f:
                    f.write('{\n')
                    f.write('  "AuthServerWhitelist":  "*.%s",\n' % domain)
                    f.write('  "AuthServerAllowlist": "*.%s",\n' % domain)
                    f.write('  "AuthNegotiateDelegateAllowlist": "*.%s"\n' % domain)
                    f.write('}\n')
                logger.info("Chromium sucessfully configured.")
            except Exception as e:
                logger.debug(
                    "An error occured during creating preferences file: %s.",
                    e)
                logger.error("Chromium configuration failed.")
    except Exception as e:
        logger.debug("%s", str(e))
        logger.error("chrome configuration failed.")

def kim_browser_configure(domain):
    configure_chromium(domain)
    configure_firefox(domain)
    configure_chromium(domain, '/etc/opt/chromium')
    qax_path = '/etc/chromium'
    if not os.path.exists(qax_path):
        pref_path = os.path.join(qax_path, CHROMIUM_PREFERENCES_REL_PATH)
        os.makedirs(pref_path)
    configure_chromium(domain, qax_path)

KRB_CONF_DIR = "/var/lib/kim/krbconf"

def kim_add_krbconf(domain, server):
    realm = domain.upper()
    kdcfile = os.path.join(KRB_CONF_DIR, 'kdcinfo.%s' % realm)
    kpassfile = os.path.join(KRB_CONF_DIR, 'kpasswdinfo.%s' % realm)

    try:
        with open(kdcfile, 'w') as f:
            f.write('%s:30288"\n' % server)
        logger.info("kdcconf sucessfully configured.")

    except Exception as e:
        logger.error("kdc configuration failed.")

def kim_krb5_setall(server):
    domain = None
    if '.' in server:
        short_name, _sep, domain = server.partition('.')
    if domain is None:
        logger.error("need fqdn servername")
        return
    kim_add_krbconf(domain, server)
    kim_browser_configure(domain)

def kim_sethostname(hostname, domain = None):
    if '.' in hostname:
        short_name, _sep, hostdomain = hostname.partition('.')
        if domain is None:
            domain = hostdomain
    else:
        short_name = hostname
        if domain is None:
            logger.warning('Invalid hostname %s.', hostname)
            #raise InstallError(_('Invalid hostname, use fqdn format.'), rval=REQUEST_ERROR) #请指定域名或者设定fqdn格式主机名
    if domain is None:
        fqdn = short_name
    else:
        fqdn = '%s.%s' % (short_name, domain)
    orig_hostname = ''
    try:
        orig_hostname = socket.gethostname()
    except Exception:
        pass
    if orig_hostname != fqdn:
        #ipautil.run([paths.BIN_HOSTNAMECTL, 'set-hostname', hostname])
        cmd_run(['/usr/bin/hostnamectl', 'set-hostname', fqdn])
        with open('/etc/hosts', 'r') as hf:
            with open('/etc/hosts.kimbak', 'w') as fw:
                modify = False
                for line in hf:
                    if line.startswith('127.0.1.1'):
                        new_line = '127.0.1.1\t%s %s\n' % (fqdn, short_name)
                        modify = True
                    else:
                        new_line = line
                    fw.write(new_line)
                if not modify:
                    fw.write('127.0.1.1\t%s %s\n' % (fqdn, short_name))
        shutil.move('/etc/hosts.kimbak', '/etc/hosts')


def kim_setmkhomedir():
    new_config = []
    edited = False
    with open('/usr/share/pam-configs/mkhomedir', 'r') as fr:
        for line in fr:
            if 'pam_mkhomedir.so' in line and 'umask=0077' not in line:
                edited = True
                new_config.append('     optional                        pam_mkhomedir.so umask=0077\n')
            else:
                new_config.append(line)
    if edited:
        with open('/usr/share/pam-configs/mkhomedir', 'w') as fw:
            for lw in new_config:
                fw.write(lw)
    try:
        cmd_run(['/usr/sbin/pam-auth-update', '--package', '--enable', 'mkhomedir'])
    except Exception as e:
        raise InstallError(_('set auto create home directtory failed.'), rval = JOIN_ERROR)


def kim_pam_enable():
    try:
        cmd_run(['/usr/sbin/pam-auth-update', '--package', '--enable', 'kim'])
    except Exception as e:
        logger.error('Enable kim auth module failed: %s' % str(e))
        raise InstallError(_('Enable kim auth module failed.'), rval = JOIN_ERROR)

def kim_pam_disable():
    try:
        cmd_run(['/usr/sbin/pam-auth-update', '--package', '--remove', 'kim'])
    except Exception as e:
        logger.error('Disable kim auth module failed: %s' % str(e))
        raise InstallError(_('Disable kim auth module failed.'), rval = JOIN_ERROR)

NS_SWITCH_CONF = '/etc/nsswitch.conf'

def kim_nss_insert():
    bak_file = NS_SWITCH_CONF + '.kimbak'
    with open(NS_SWITCH_CONF, 'r') as nf:
        sudo_found = False
        with open(bak_file, 'w') as fw:
            for line in nf:
                if line.startswith('passwd:') and 'kim' not in line:
                    new_line = '%s %s\n' % (line.rstrip('\n').rstrip(' '), 'kim')
                elif line.startswith('group:') and 'kim' not in line:
                    new_line = '%s %s\n' % (line.rstrip('\n').rstrip(' '), 'kim')
                elif line.startswith('sudoers:'):
                    new_line = 'sudoers:        files sss'
                    sudo_found = True
                else:
                    new_line = line
                fw.write(new_line)
            if not sudo_found:
                fw.write('sudoers:        files sss\n')
    shutil.move(bak_file, NS_SWITCH_CONF)

def kim_nss_remove():
    bak_file = NS_SWITCH_CONF + '.kimbak1'
    with open(NS_SWITCH_CONF, 'r') as nf:
        with open(bak_file, 'w') as fw:
            for line in nf:
                if line.startswith('passwd:'):
                    new_line = line.replace('kim', '')
                elif line.startswith('group:'):
                    new_line = line.replace('kim', '')
                elif line.startswith('sudoers:'):
                    new_line = ''
                else:
                    new_line = line
                fw.write(new_line)
    shutil.move(bak_file, NS_SWITCH_CONF)

### 获取当前管控状态，1表示已加域，0表示未加域
def get_domain_status():
    status = os.path.exists(kim_config_path)
    return 1 if status else 0

### 是否存在电池，用于判断是否为笔记本
def get_battery_status():
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('org.freedesktop.UPower',
                       '/org/freedesktop/UPower')
        upower = dbus.Interface(proxy,dbus_interface="org.freedesktop.UPower")
        devices = upower.EnumerateDevices()
        for dvc in devices:
            if dvc.startswith('/org/freedesktop/UPower/devices/battery'):
                return True
    except Exception as e:
        pass
    return False

### 判断设备类型为笔记本还是台式机
def get_device_type():
    run_args = ['/usr/sbin/dmidecode', '-s', 'chassis-type']
    notebook_type = ['Notebook', 'Laptop', 'Portable']
    chassis_type = None
    try:
        _ret, out, _err = cmd_run(run_args)
    except Exception:
        out = ''
    else:
        chassis_type = out.rstrip('\n')
    if chassis_type and chassis_type in notebook_type:
        if get_battery_status():
            return 'Notebook'
    return 'Desktop'

def kim_extra_config(server):
    url = "https://%s:%d/aptserver/icbc_config.json" % (server, KCM_RPC_PORT)
    dest_file = '/usr/lib/biometric-authentication/drivers/extra/icbc/configs/icbc_config.json'
    shutil.copy(dest_file, dest_file + '.kimbak')
    try:
        resp = requests.get(url, verify=False, timeout=8)
        if resp.status_code != 200:
            raise InstallError(_('Failed to get config'), rval = REQUEST_ERROR)
        with open(dest_file, 'w') as f:
            f.write(resp.text)
    except InstallError:
        raise
    except Exception as e:
        raise InstallError(_('Failed to get config'), rval = REQUEST_ERROR)


### 退出域，通过dbus调用之前的接口
def unrolling_host(rollback = False):
    #hostname = socket.getfqdn()
    if rollback:
        ret = kcm_force_uninstall()
    else:
        #ret, msg = uninstall_kcm()
        ret, msg = kcm_unrolled_v2()
    if ret != 0 and not rollback:
        logger.error('uninstall failed:%s' % msg)
        raise InstallError(msg, rval = UNENROLL_ERROR)
    if ret != 0:
        logger.warning('rollback failed')
    if os.path.exists(kim_config_path):
        kim_unconfigure()
        os.remove(kim_config_path)
    if os.path.exists('/var/lib/kim/data/kimcd.db'):
        os.remove('/var/lib/kim/data/kimcd.db')
    if os.path.exists('/var/lib/kim/private/pri.db'):
        os.remove('/var/lib/kim/private/pri.db')


def get_err_from_code(code):
    msg = '未知错误，请查看日志'
    if code == 300000:
        msg = '请求成功'
    elif code == 300001:
        msg = '关联用户不存在'
    elif code == 300002:
        msg = 'sn不存在'
    elif code == 300003:
        msg = 'sn关联主机失败'
    elif code == 300004:
        msg = '主机名已存在或无效的主机名'
    elif code == 300005:
        msg = '用户不存在'
    elif code == 300007:
        msg = '激活注册码不存在'
    elif code == 300008:
        msg = '激活注册码已存在'
    elif code == 300009:
        msg = '添加主机记录失败'
    elif code == 300010:
        msg = '主机关联组织失败'
    elif code == 300011:
        msg = '添加访问规则失败'
    elif code == 300012:
        msg = '用户不在组织内'
    elif code == 300013:
        msg = '发布策略错误'
    elif code == 300014:
        msg = '参数错误，密码编码无效'
    elif code == 300400:
        msg = '用户认证失败，请检查用户名和密码'
    elif code == 300401:
        msg = '请求未认证，请重新认证'
    elif code == 300403:
        msg = '用户权限不足'
    elif code == 300500:
        msg = '服务器错误'
    return msg

def change_system_time(dt):
    cli_dt = dt.strftime('%Y-%m-%d %H:%M:%S')
    cmd_run(['/usr/bin/timedatectl', 'set-ntp', 'false'])
    ret, msg, emsg = cmd_run(['/usr/bin/timedatectl', 'set-time', cli_dt])
    if ret != 0:
        logger.warning('change system time error:%s' % emsg)
    cmd_run(['/usr/bin/timedatectl', 'set-ntp', 'true'])

def http_check_server_info(server):
    global auth_type
    global remote_server
    remote_server = server
    url = '%s://%s:%d/kim/checkServer' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    kim_dbus.joinProgress(3)
    resp_data = send_kcm_request(url, timeout=8, method='Get')
    server_time = resp_data['nowtime']
    dt_server = datetime.fromisoformat(server_time)
    #datetime.strptime(server_time,"%Y-%m-%dT%H:%M:%S%z")
    dt_now = datetime.now()
    dt_delta = dt_now.timestamp() - dt_server.timestamp()
    if(dt_delta > 60):
        logger.warning('get server time: %s' % server_time)
        change_system_time(dt_server)
        #raise InstallError(_('check server failed: The client and server time skews too large.'), rval = REQUEST_ERROR)
    auth_type = resp_data['authtype']
    remote_server = server
    #kim_sethostname(resp_hostname)


def get_hostname_by_sn(server, sn):
    url = 'https://%s:%d/kim/validateSN' % (server, KCM_JOIN_PORT)
    language = os.environ['LANGUAGE']
    headers = {
        'Accept-Language': language.replace('_', '-')
    }
    datas = {
        "sn": sn,
        "device_type": get_device_type(),
        "devsn": get_devsn()
    }
    try:
        kim_dbus.joinProgress(3)
        resp = requests.post(url=url, json=datas, headers=headers, verify=False, timeout=8)
        if resp.status_code != 200:
            raise InstallError(_('Validate sn error: server request error[%d]') % resp.status_code, rval = REQUEST_ERROR)
        #resp_json = resp.json
        resp_json = json.loads(resp.text)
        print(resp_json)
        resp_ret = resp_json['ret']
        resp_msg = resp_json['msg']
        if resp_ret != 300000:
            logger.error('Validate sn error: %s.', resp_msg)
            join_msg = _('unknow error, please see the infomation in log file')
            if resp_ret == 300002:
                join_msg = _('Host authenticaion failed, please input sn to server.')
            elif resp_ret == 300001:
                join_msg = _('Host authentication failed, please bind an employee number.')
            elif resp_ret == 300008:
                join_msg = _('Host authentication failed, devsn has already exists.')
            elif resp_ret == 300500:
                join_msg = _('Host authentication failed, remote server error.')
            raise InstallError(join_msg, rval = REQUEST_ERROR)
        resp_data = resp_json['data']
        print(resp_data)
        resp_hostname = resp_data['hostname']
        kim_sethostname(resp_hostname)
    except InstallError:
        raise
    except requests.exceptions.InvalidURL:
        raise InstallError(_('invalid server url'), rval = REQUEST_ERROR) #无效的服务器地址
    except requests.exceptions.ConnectTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = REQUEST_ERROR)
    except requests.exceptions.ReadTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = REQUEST_ERROR)
    except requests.exceptions.ConnectionError as conn_e:
        logger.error(conn_e)
        raise InstallError(_('connect to server failed, please check your network'), rval = REQUEST_ERROR) #'连接服务器失败，请检查网络状态'
    except Exception as e:
        print('%s:%s' % (type(e), str(e)))
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = REQUEST_ERROR)

def kcm_init(servername):
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret, msg = kcm.init_kcm(servername, str(KCM_RPC_PORT), timeout=10)
        if ret != 0:
            raise InstallError(_('Client configure error:%s') % msg,rval = JOIN_ERROR)
    except Exception as e:
        pass


def http_join_comfirm(server):
    url = '%s://%s:%d/kim/reportRegistrationStatus' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    language = os.environ['LANGUAGE']
    headers = {
        'Accept-Language': language.replace('_', '-'),
        'Authorization': auth_token
    }
    datas = {
        #"sn": sn,
        "hostname": new_hostname,
        "devsn": get_devsn()
    }
    try:
        kim_dbus.joinProgress(80)
        resp = requests.post(url=url, json=datas, headers=headers, verify=False, timeout=8)
        if resp.status_code != 200:
            raise InstallError(_('Confirm error: server request error[%d]') % resp.status_code, rval = REQUEST_ERROR)
        #resp_json = resp.json
        resp_json = json.loads(resp.text)
        print(resp.text)
        resp_ret = resp_json['ret']
        resp_msg = resp_json['msg']
        if resp_ret != 300000:
            logger.error('Validate sn error: %s.', resp_msg)
            join_msg = _('unknow error, please see the infomation in log file')
            if resp_ret == 300003:
                join_msg = _('Enrolled failed, can not bind a user and organization')
            elif resp_ret == 300002:
                join_msg = _('Host authentication failed, please bind an employee number.')
            elif resp_ret == 300003:
                join_msg = _('Enrolled failed, host related error.')
            elif resp_ret == 300004:
                join_msg = _('Enrolled failed, hostname is already exist or invalid, please try again.')
            elif resp_ret == 300009:
                join_msg = _('Enrolled failed, add host error, please try again.')
            elif resp_ret == 300010:
                join_msg = _('Enrolled failed, add host to organization failed.')
            elif resp_ret == 300011:
                join_msg = _('Enrolled failed, bind to user failed.')
            elif resp_ret == 300500:
                join_msg = _('Enrolled failed, remote server error')
            raise InstallError(join_msg, rval = JOIN_ERROR)
        resp_data = resp_json['data']
        resp_hostname = resp_data['hostname']
        print(resp_hostname)
        #kim_sethostname(resp_hostname)
    except InstallError:
        raise
    except requests.exceptions.InvalidURL:
        raise InstallError(_('invalid server url'), rval = JOIN_ERROR) #无效的服务器地址
    except requests.exceptions.ConnectTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERROR)
    except requests.exceptions.ReadTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERROR)
    except requests.exceptions.ConnectionError as conn_e:
        logger.error(conn_e)
        raise InstallError(_('connect to server failed, please check your network'), rval = JOIN_ERROR) #'连接服务器失败，请检查网络状态'
    except Exception as e:
        print('%s:%s' % (type(e), str(e)))
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERROR)

def admin_confirm_join_http(server):
    url = '%s://%s:%d/kim/regconfirm' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        #"sn": sn,
        "hostname": new_hostname,
        "devsn": get_devsn(),
        "macaddr": get_mac_address(),
        "osVersion": get_os_version(),
        "hardwarePlatform": platform.machine(),
        "kernel": platform.release(),
        "clientVersion": get_client_version(),
        "environment": get_run_env()
    }
    kim_dbus.joinProgress(80)
    send_kcm_request(url, datas=datas, token=auth_token)

def check_kcm_availability(server):
    kim_server = server
    #try:
    #    url = 'http://%s:%d' % (server, KCM_RPC_PORT)
    #    resp = requests.get(url=url, allow_redirects=False, verify=False, timeout=8)
    #    if resp.status_code > 300 and resp.status_code < 310:
    #        real_addr = resp.headers.get('Location')
    #        kim_server = real_addr.split('//')[-1].split(':')[0]
    #except Exception as e:
    #    pass
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret, msg = kcm.check_kcm_availability(kim_server, str(KCM_RPC_PORT))
        if ret != SUCCESS:
            raise InstallError(msg, rval = KCM_ERROR)
    except InstallError:
        raise
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
        raise InstallError(_('dbus error, please check the service status'), rval = KCM_ERROR)
    except Exception as e:
        logger.error(e)
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = REQUEST_ERROR)

def set_lang(lang):
    os.environ['LANGUAGE'] = lang
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        kcm.set_lang(lang)
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)

def kcm_restore_policy():
    system_bus = dbus.SystemBus()
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        kcm.restore_policy()
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)

def uninstall_kcm():
    system_bus = dbus.SystemBus()
    ret = 0
    msg = 'uncall'
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret, msg = kcm.uninstall()
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)
    return ret, msg

def kcm_force_uninstall():
    system_bus = dbus.SystemBus()
    ret = -1
    try:
        proxy = system_bus.get_object('com.kylin.kydevmonit.domainhook',
                       '/com/kylin/kydevmonit/domainhook')
        kcm = dbus.Interface(proxy,dbus_interface="com.kylin.kydevmonit.domainhook")
        ret = kcm.force_uninstall()
    except dbus.exceptions.UnknownMethodException:
        ret = 0
    except dbus.exceptions.DBusException as dbus_e:
        logger.error(dbus_e)
    except Exception as e:
        logger.error(e)
    return ret

def device_sn_join(server):
    try:
        cmd_run(['setstatus', '-f', 'netctl', 'off', '-p'])
    except Exception as e:
        print(e)
    sn = get_device_serialno()
    try:
        kim_dbus.joinProgress(5)
        get_hostname_by_sn(server, sn)
        kim_dbus.joinProgress(20)
        check_kcm_availability(server)
        #http_join_by_sn(server, sn)
        kim_dbus.joinProgress(40)
        kim_extra_config(server)
        kim_configure(server, KCM_JOIN_PORT, provider='kcm')
        kim_setmkhomedir()
        kim_dbus.joinProgress(60)
        kcm_init(server)
        kim_dbus.joinProgress(80)
        http_join_comfirm(server, sn)
        update_server_info(server, KCM_JOIN_PORT)
        kim_dbus.joinProgress(100)
    except InstallError as ie:
        if ie.rval == JOIN_ERROR:
            try:
                unrolling_host()
            except Exception as e:
                print(e)
    except Exception as e:
        print(e)
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERROR)

def check_server_info(server, hostname):
    global new_hostname
    http_check_server_info(server)
    new_hostname = hostname

def user_auth_proxy(server, username, password):
    global auth_token
    if server is None:
        raise InstallError(_('can not get server, please check server first.'), rval = REQUEST_ERROR)
    if auth_type is None:
        auth_plugin = "HTTP"
    else:
        auth_plugin = auth_type
    url = '%s://%s:%d/kim/auth' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        'username': username,
        'btoken': base64.b64encode(password.encode('utf-8')),
        'authplugin': auth_plugin,
        'ipaddr': extract_ip()
    }
    kim_dbus.joinProgress(20)
    resp_data = send_kcm_request(url, datas=datas, timeout=8)
    auth_token = resp_data['token']

def send_kcm_request(url, datas=None, user=None, pwd=None, timeout=8, token=None, method='Post'):
    language = os.environ['LANGUAGE']
    headers = {
        'Accept-Language': language.replace('_', '-')
    }
    if token is not None:
        headers['Authorization'] = token
    try:
        if method == 'Get':
            resp = requests.get(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        elif method == 'Post':
            resp = requests.post(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        elif method == 'Delete':
            resp = requests.delete(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        else:
            resp = requests.post(url=url, json=datas, headers=headers, verify=False,timeout=timeout)
        if resp.status_code != 200:
            raise InstallError(_('Request error[%d]') % resp.status_code, rval = JOIN_ERROR)
        resp_json = json.loads(resp.text)
        print(resp.text)
        resp_ret = resp_json['ret']
        resp_msg = resp_json['msg']
        if resp_ret != 300000:
            logger.error('Error: [%d] %s' % (resp_ret, resp_msg))
            if 'describe' in resp_json:
                msg = resp_json['describe']
            elif 'chinese' in resp_json:
                msg = resp_json['chinese']
            else:
                msg = get_err_from_code(resp_ret)
            if resp_ret == 300421:
                raise InstallError(msg, rval = USER_PWD_EXPIRE)
            raise InstallError(msg, rval = JOIN_ERROR)
        print('success')
        if 'data' in resp_json:
            return resp_json['data']
    except InstallError:
        raise
    except requests.exceptions.InvalidURL:
        raise InstallError(_('invalid server url'), rval = JOIN_ERROR) #无效的服务器地址
    except requests.exceptions.ConnectTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERROR)
    except requests.exceptions.ReadTimeout:
        raise InstallError(_('connect to server failed: timeout.'), rval = JOIN_ERROR)
    except requests.exceptions.ConnectionError as conn_e:
        logger.error(conn_e)
        raise InstallError(_('connect to server failed, please check your network'), rval = JOIN_ERROR) #'连接服务器失败，请检查网络状态'
    except Exception as e:
        print('%s:%s' % (type(e), str(e)))
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERROR)

def change_password(user, oldpwd, newpwd):
    if auth_type is None:
        auth_plugin = "HTTP"
    else:
        auth_plugin = auth_type
    if remote_server is None:
        server, _port = get_kcm_server()
    else:
        server = remote_server
    url = '%s://%s:%d/kim/modifypwd' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        'username': user,
        'btoken': base64.b64encode(oldpwd.encode('utf-8')),
        'nbtoken': base64.b64encode(newpwd.encode('utf-8'))
    }
    resp_data = send_kcm_request(url, datas=datas, timeout=8)

def unenroll_http(server):
    hostname = socket.gethostname()
    url = '%s://%s:%d/kim/exitdomain' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        "hostname": hostname,
        "devsn": get_devsn()
    }
    send_kcm_request(url, datas, token=auth_token, method='Delete')

def kcm_unrolled_v2():
    serv, _port = get_kcm_server()
    try:
        unenroll_http(serv)
        kcm_restore_policy()
    except InstallError as ie:
        return ie.rval, ie.msg
    except Exception as e:
        logger.error('Unrolled unknow error: %s' % str(e))
        return -1, str(e)
    return 0, 'success'

def admin_verify_join_GSSAPI(server, user, password):
    pass

def admin_verify_join_http(server, hostname):
    url = '%s://%s:%d/kim/hostreg' % (HTTP_SCHEMA, server, KCM_JOIN_PORT)
    datas = {
        #"sn": sn,
        "hostname": hostname,
        "devsn": get_devsn()
    }
    kim_dbus.joinProgress(50)
    resp_data = send_kcm_request(url, datas=datas, timeout=8, token=auth_token)
    resp_hostname = resp_data['hostname']
    print(resp_hostname)
    kim_krb5_setall(server)

def admin_verify_join(user, password):
    if auth_type == 'GSSAPI':
        pass
    else:
        user_auth_proxy(remote_server, user, password)
    check_kcm_availability(remote_server)
    admin_verify_join_http(remote_server, new_hostname)

def admin_join_confirm():
    try:
        kim_configure(remote_server, KCM_JOIN_PORT, provider='kcm')
        kim_setmkhomedir()
        kim_sethostname(new_hostname)
        kim_dbus.joinProgress(60)
        kcm_init(remote_server)
        kim_dbus.joinProgress(80)
        admin_confirm_join_http(remote_server)
        #update_server_info(remote_server, KCM_JOIN_PORT)
        kim_dbus.joinProgress(100)
    except InstallError as ie:
        if ie.rval == JOIN_ERROR:
            try:
                unrolling_host(rollback = True)
            except Exception as e:
                logger.error(e)
        raise ie
    except Exception as e:
        logger.error(e)
        raise InstallError(_('unknow error, please see the infomation in log file'), rval = JOIN_ERROR)

env_black_list = ('LD_PRELOAD', 'LD_LIBRARY_PATH', 'LD_AUDIT')
app_allow_list = ('/usr/sbin/kim-client',
                  '/etc/sbin/domain-control',
                  '/opt/script/exit-domain.py')

class KimDomain(dbus.service.Object):
    def __init__(self, bus, object_path):
        logger.info('kim service start.')
        dbus.service.Object.__init__(self, bus, object_path)
        self._last_input = None

    def getSenderLang(self, sender):
        lang = 'zh_CN'
        try:
            system_bus = dbus.SystemBus()
            send_uid = system_bus.get_unix_user(sender)
            path = '/org/freedesktop/Accounts/User%d' % send_uid
            proxy = system_bus.get_object('org.freedesktop.Accounts', path)
            auser = dbus.Interface(proxy,dbus_interface="org.freedesktop.DBus.Properties")
            lang = auser.Get('org.freedesktop.Accounts.User', 'Language')
        except Exception as e:
            print(e)
        return lang

    def getSenderPid(self, sender):
        system_bus = dbus.SystemBus()
        proxy = system_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
        dbus_obj = dbus.Interface(proxy,dbus_interface='org.freedesktop.DBus')
        try:
            pid = dbus_obj.GetConnectionUnixProcessID(sender)
            print(f"Caller PID: {pid}")
        except dbus.DBusException as e:
            print(f"Failed to get PID for sender {sender}: {e}")
            raise dbus.exceptions.DBusException('[%s] dbus method control,operation not permitted' % sender)
        return pid

    def checkSenderEnv(self, pid):
        env_file = '/proc/%u/environ' % pid
        with open(env_file, 'r') as ef:
            env_lines = ef.readline()
            env_details = env_lines.replace('\0', '\n').split('\n')
            for env_detail in env_details:
                key = env_detail.split('=')[0]
                if key in env_black_list:
                    raise dbus.exceptions.DBusException('[%u] dbus method control,env forbidden' % pid)

    def checkSenderAllow(self, sender):
        pid = self.getSenderPid(sender)
        self.checkSenderEnv(pid)
        exe_file = '/proc/%u/exe' % pid
        real_file = os.readlink(exe_file)
        if real_file.startswith('/usr/bin/python'):
            cmd_file = '/proc/%u/cmdline' % pid
            with open(cmd_file, 'r') as cf:
                cmd_line = cf.readline()
                cmds = cmd_line.split('\0')
                if len(cmds) >= 2:
                    real_file = cmds[1]
        if real_file not in app_allow_list:
            raise dbus.exceptions.DBusException('[%s] dbus method control,operation not permitted' % real_file)

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='s')
    def getDefaultServer(self):
        try:
            server, _port = get_server_info()
            return server
        except Exception as e:
            return ''

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='s')
    def getSerialNo(self):
        try:
            sn = get_device_serialno()
            return sn
        except Exception as e:
            return ''

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='s', out_signature='is', sender_keyword='sender')
    def deviceSNJoin(self, server, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start join server[%s].' % server)
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            device_sn_join(server)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('register success') #'注册成功'

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ss', out_signature='is', sender_keyword='sender')
    def checkServer(self, server, hostname, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start check server[%s].' % server)
        try:
            lang = self.getSenderLang(sender)
            set_lang(lang)
            check_server_info(server, hostname)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ss', out_signature='is', sender_keyword='sender')
    def userVerifyJoin(self, user, password, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start join server.')
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            admin_verify_join(user, password)
        except InstallError as ie:
            print(ie.rval)
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='is', sender_keyword='sender')
    def joinComfirm(self, sender = None):
        self.checkSenderAllow(sender)
        logger.info('comfirm join server.')
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            admin_join_confirm()
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ssss', out_signature='is', sender_keyword='sender')
    def userJoinCommand(self, server, hostname, user, password, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start join server[%s].' % server)
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            check_server_info(server, hostname)
            admin_verify_join(user, password)
            admin_join_confirm()
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='ss', out_signature='is', sender_keyword='sender')
    def userAuthRemote(self, user, password, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start authenticaion [%s].' % user)
        try:
            lang = self.getSenderLang(sender)
            os.environ['LANGUAGE'] = lang
            serv, _port = get_kcm_server()
            user_auth_proxy(serv, user, password)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='sss', out_signature='is', sender_keyword='sender')
    def userChangePwd(self, user, oldpwd, newpwd, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start changing password [%s].' % user)
        try:
            lang = self.getSenderLang(sender)
            os.environ['LANGUAGE'] = lang
            change_password(user, oldpwd, newpwd)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('success')

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='i')
    def getDomainStatus(self):
        return get_domain_status()

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='is', sender_keyword='sender')
    def unenroll(self, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start unenroll.')
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            unrolling_host()
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('unenroll success') #'注销成功'

    @dbus.service.method(dbus_interface='com.kylin.kim.domain', in_signature='', out_signature='is', sender_keyword='sender')
    def unenroll_local(self, sender = None):
        self.checkSenderAllow(sender)
        logger.info('start unenroll_local.')
        try:
            lang = self.getSenderLang(sender)
            #os.environ['LANGUAGE'] = lang
            set_lang(lang)
            unrolling_host(rollback = True)
        except InstallError as ie:
            return ie.rval, ie.msg
        return SUCCESS, _('unenroll success') #'注销成功'

    @dbus.service.signal(dbus_interface='com.kylin.kim.domain', signature='i')
    def joinProgress(self, prog):
        print('join:%d%%' % prog)


def kcmcfg2kim():
    if get_domain_status() != 0:
        return
    kcm_file = '/etc/hedron/client.conf'
    config = configparser.ConfigParser()
    config.read(kcm_file, encoding='utf-8')
    url = config.get('hedron-client', 'url')
    up = parse.urlparse(url)
    kim_configure(up.hostname, up.port, provider='kcm')

def updatekimconfig():
    if get_domain_status() != 0:
        return
    try:
        server, port = get_server_info()
        kim_configure(server, port, provider='kcm')
    except Exception:
        pass

def main():
    global kim_dbus
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
    standard_logging_setup('/var/log/kim-domain.log', filemode='a')

    sys_bus = dbus.SystemBus()
    name = dbus.service.BusName('com.kylin.kim.domain', sys_bus)
    kim_dbus = KimDomain(sys_bus, '/')
    mainloop = GLib.MainLoop()
    mainloop.run()


if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == 'kcm2kim':
        kcmcfg2kim()
    elif len(sys.argv) > 1 and sys.argv[1] == 'kimupdate':
        updatekimconfig()
    else:
        main()
