From e980cbd4ac421938a2484e4d564c81168dab5402 Mon Sep 17 00:00:00 2001 From: zhongning5 Date: Tue, 9 Apr 2024 20:18:43 +0800 Subject: [PATCH] fix code check Signed-off-by: zhongning5 --- .../config_parser_mgr/cfg/config_parser.py | 283 +++++++++--------- .../param/system_parameter_parser.py | 62 ++-- .../user_group/user_group_parser.py | 66 ++-- .../startup_checker/cmds_rule.py | 32 +- .../startup_checker/plug_in_rule.py | 41 ++- .../startup_checker/system_parameter_rules.py | 5 +- .../startup_checker/user_group_rule.py | 22 +- 7 files changed, 260 insertions(+), 251 deletions(-) diff --git a/tools/startup_guard/config_parser_mgr/cfg/config_parser.py b/tools/startup_guard/config_parser_mgr/cfg/config_parser.py index a33a52c..ca77a50 100644 --- a/tools/startup_guard/config_parser_mgr/cfg/config_parser.py +++ b/tools/startup_guard/config_parser_mgr/cfg/config_parser.py @@ -67,9 +67,14 @@ class CmdParser(ItemParser): self["content"] = "" self["fileId"] = -1 + def __str__(self): + return "cmd \"%s\" content \"%s\" " % (self["name"], self["content"]) + def create(self, json_node, parent = None, fileId = None): - assert(isinstance(json_node, str)) - assert(parent != None) + if not isinstance(json_node, str): + raise Exception("json_node type error") + if parent == None: + raise Exception("parent ") info = json_node.partition(" ") # 取第一个空格分割 self["name"] = info[0] self["jobId"] = parent.get("jobId") @@ -79,9 +84,6 @@ class CmdParser(ItemParser): self["content"] = info[2] return - def __str__(self): - return "cmd \"%s\" content \"%s\" " % (self["name"], self["content"]) - class JobParser(ItemParser): def __init__(self, config): ItemParser.__init__(self, config) @@ -92,12 +94,12 @@ class JobParser(ItemParser): self["jobPriority"] = -1 self["executionTime"] = 0 - def _add_cmds(self, cmdList, fileId): - for cmd in cmdList: - self._config_parser.add_cmd(cmd, self, fileId) + def __str__(self): + return "jobs '%s' condition '%s' " % (self["name"], self["condition"]) def create(self, json_node, parent = None, fileId = None): - assert(isinstance(json_node, dict)) + if not isinstance(json_node, dict): + raise Exception("json_node type error") self["name"] = json_node["name"] self["jobId"] = self._config_parser.get_job_id() self["jobPriority"] = self._config_parser.get_job_priority(json_node["name"]) @@ -115,7 +117,8 @@ class JobParser(ItemParser): return def update(self, json_node, parent = None, fileId = None): - assert(isinstance(json_node, dict)) + if not isinstance(json_node, dict): + raise Exception("json_node type error") if parent != None: self["serviceId"] = parent.get("serviceId") if fileId and self["fileId"] is None: @@ -124,8 +127,9 @@ class JobParser(ItemParser): self._add_cmds(json_node.get("cmds"), fileId) return - def __str__(self): - return "jobs '%s' condition '%s' " % (self["name"], self["condition"]) + def _add_cmds(self, cmdList, fileId): + for cmd in cmdList: + self._config_parser.add_cmd(cmd, self, fileId) class ServiceParser(ItemParser): def __init__(self, config): @@ -153,6 +157,47 @@ class ServiceParser(ItemParser): self["permission_acls"] = "" self["fileId"] = -1 + def create(self, json_node, parent = None, fileId = None): + if not isinstance(json_node, dict): + raise Exception("json_node type error") + self["name"] = json_node["name"] + if not self.get("serviceId") : + self["serviceId"] = self._config_parser.get_service_id() + if fileId : + self["fileId"] = fileId + self._handle_string_filed(json_node) + self._handle_Bool_filed(json_node) + self._handle_array_filed(json_node) + self._handle_integer_filed(json_node) + + #for file + if json_node.__contains__("file"): + for item in json_node.get("file"): + self._config_parser.add_service_file(item, self) + + #for socket + if json_node.__contains__("socket"): + for item in json_node.get("socket"): + self._config_parser.add_service_socket(item, self) + #for jobs + if json_node.__contains__("jobs"): + self._handle_scope_jobs(json_node.get("jobs")) + + #for critical + if json_node.__contains__("critical"): + critical = json_node.get("critical") + if isinstance(critical, list): + self["critical_enable"] = int(critical[0]) != 0 + self["limit_time"] = int(critical[0]) + self["limit_count"] = int(critical[0]) + else: + self["critical_enable"] = int(critical) != 0 + return + + def update(self, json_node, parent = None, fileId = None): + self.create(json_node, parent, fileId) + return + def _handle_string_filed(self, json_node): str_field_map = { "uid" : "uid", "caps":"caps", "start_mode":"start-mode", "secon":"secon", "apl":"apl" @@ -201,46 +246,6 @@ class ServiceParser(ItemParser): self[key] = json_node.get(name) self._config_parser.add_job({"name" : json_node.get(name)}, self, self["fileId"]) - def create(self, json_node, parent = None, fileId = None): - assert(isinstance(json_node, dict)) - self["name"] = json_node["name"] - if not self.get("serviceId") : - self["serviceId"] = self._config_parser.get_service_id() - if fileId : - self["fileId"] = fileId - self._handle_string_filed(json_node) - self._handle_Bool_filed(json_node) - self._handle_array_filed(json_node) - self._handle_integer_filed(json_node) - - #for file - if json_node.__contains__("file"): - for item in json_node.get("file"): - self._config_parser.add_service_file(item, self) - - #for socket - if json_node.__contains__("socket"): - for item in json_node.get("socket"): - self._config_parser.add_service_socket(item, self) - #for jobs - if json_node.__contains__("jobs"): - self._handle_scope_jobs(json_node.get("jobs")) - - #for critical - if json_node.__contains__("critical"): - critical = json_node.get("critical") - if isinstance(critical, list): - self["critical_enable"] = int(critical[0]) != 0 - self["limit_time"] = int(critical[0]) - self["limit_count"] = int(critical[0]) - else: - self["critical_enable"] = int(critical) != 0 - return - - def update(self, json_node, parent = None, fileId = None): - self.create(json_node, parent, fileId) - return - class ServiceSocketParser(ItemParser): def __init__(self, config): ItemParser.__init__(self, config) @@ -252,8 +257,15 @@ class ServiceSocketParser(ItemParser): self["gid"] = "" self["serviceId"] = -1 + def __repr__(self): + return self.__str__() + + def __str__(self): + return "socket '%s' serviceid = %d family %s" % (self["name"], self["serviceId"], self["family"]) + def create(self, json_node, parent = None, file_id = None): - assert(isinstance(json_node, dict)) + if not isinstance(json_node, dict): + raise Exception("json_node type error") self["name"] = json_node["name"] if parent != None: self["serviceId"] = parent.get("serviceId") @@ -264,12 +276,6 @@ class ServiceSocketParser(ItemParser): if json_node.get("option") : self["option"] = self.get_strings_value(json_node.get("option")) - def __repr__(self): - return self.__str__() - - def __str__(self): - return "socket '%s' serviceid = %d family %s" % (self["name"], self["serviceId"], self["family"]) - class ServiceFileParser(ItemParser): def __init__(self, config): ItemParser.__init__(self, config) @@ -277,8 +283,15 @@ class ServiceFileParser(ItemParser): self["content"] = "" self["serviceId"] = -1 + def __repr__(self): + return self.__str__() + + def __str__(self): + return "file '%s' serviceid = %d content '%s'" % (self["name"], self["serviceId"], self["content"]) + def create(self, json_node, parent = None, file_id = None): - assert(isinstance(json_node, str)) + if not isinstance(json_node, str): + raise Exception("json_node type error") if parent != None: self["serviceId"] = parent.get("serviceId") info = json_node.partition(" ") @@ -287,12 +300,6 @@ class ServiceFileParser(ItemParser): self["content"] = info[2] return - def __repr__(self): - return self.__str__() - - def __str__(self): - return "file '%s' serviceid = %d content '%s'" % (self["name"], self["serviceId"], self["content"]) - class ConfigParser(): def __init__(self, path): self._path = path @@ -308,33 +315,6 @@ class ConfigParser(): self._selinux = "" self._plug_in = [] - def _load_services(self, json_node, file_id): - assert(isinstance(json_node, list)) - for item in json_node: - self.add_service(item, file_id) - return - - def _load_jobs(self, json_node, file_id): - assert(isinstance(json_node, list)) - for item in json_node: - self.add_job(item, None, file_id) - return - - def _load_import(self, import_node): - assert(isinstance(import_node, list)) - start_with = [ "/system", "/chip_prod", "/sys_prod", "/vendor" ] - for file in import_node: - found = False - for start in start_with: - if file.startswith(start): - found = True - break - if found : - self.load_config(self._path + file) - else: - for start in start_with: - self.load_config(self._path + start + file, file) - def load_config(self, file_name): path = self._path + file_name if not os.path.exists(path): @@ -344,7 +324,8 @@ class ConfigParser(): try: root = json.load(content) fileId = self.add_File(file_name) - assert(isinstance(root, dict)) + if not isinstance(root, dict): + raise Exception("root type error") if (root.__contains__("services")): self._load_services(root["services"], fileId) if (root.__contains__("jobs")): @@ -409,43 +390,6 @@ class ConfigParser(): pp.pprint(self._jobs) pass - def _is_valid_file(self, file, valid_file_ext): - if not file.is_file(): - return False - for ext in valid_file_ext: - if file.name.endswith(ext): - return True - return False - - def _scan_config_file(self, file_name): - dir_config_file = os.path.join(self._path, file_name) - if not os.path.exists(dir_config_file): - return - try: - with os.scandir(dir_config_file) as files: - for file in files: - if self._is_valid_file(file, ".cfg"): - name = file.path[len(self._path) :] - self.load_config(name) - except: - pass - - def _scan_share_library_file(self, file_name): - if not os.path.exists(file_name): - return - try: - for item in os.scandir(file_name): - file_path = os.path.join(file_name, item.name) - if item.is_file(): - if self._is_valid_file(item, ".so"): - self._plug_in.append(file_path) - continue - else: - dir_config_file = os.path.join(file_name, item.name) - self._scan_share_library_file(item) - except: - pass - def scan_library(self, target_cpu): if target_cpu == "arm64": config_paths = [ @@ -494,11 +438,6 @@ class ConfigParser(): return job_priority.get(job_name) return 100 - def _load_boot_event(self, event): - if self._jobs.__contains__(event.get("name")): - print("loadBootEvent_ %s %f" % (event.get("name"), event.get("dur"))) - self._jobs.get(event.get("name"))["executionTime"] = event.get("dur") - def load_boot_event_file(self, boot_event_file): if not os.path.exists(boot_event_file): print("Error, invalid config file %s" % boot_event_file) @@ -535,6 +474,78 @@ class ConfigParser(): print("Error, invalid parameter file ", file_name) pass + def _load_services(self, json_node, file_id): + if not isinstance(json_node, list): + raise Exception("json_node type error") + for item in json_node: + self.add_service(item, file_id) + return + + def _load_jobs(self, json_node, file_id): + if not isinstance(json_node, list): + raise Exception("json_node type error") + for item in json_node: + self.add_job(item, None, file_id) + return + + def _load_import(self, import_node): + if not isinstance(import_node, list): + raise Exception("import_node type error") + start_with = [ "/system", "/chip_prod", "/sys_prod", "/vendor" ] + for file in import_node: + found = False + for start in start_with: + if file.startswith(start): + found = True + break + if found : + self.load_config(self._path + file) + else: + for start in start_with: + self.load_config(self._path + start + file, file) + + def _is_valid_file(self, file, valid_file_ext): + if not file.is_file(): + return False + for ext in valid_file_ext: + if file.name.endswith(ext): + return True + return False + + def _scan_config_file(self, file_name): + dir_config_file = os.path.join(self._path, file_name) + if not os.path.exists(dir_config_file): + return + try: + with os.scandir(dir_config_file) as files: + for file in files: + if self._is_valid_file(file, ".cfg"): + name = file.path[len(self._path) :] + self.load_config(name) + except: + pass + + def _scan_share_library_file(self, file_name): + if not os.path.exists(file_name): + return + try: + for item in os.scandir(file_name): + file_path = os.path.join(file_name, item.name) + if item.is_file(): + if self._is_valid_file(item, ".so"): + self._plug_in.append(file_path) + continue + else: + dir_config_file = os.path.join(file_name, item.name) + self._scan_share_library_file(item) + except: + pass + + def _load_boot_event(self, event): + if self._jobs.__contains__(event.get("name")): + print("loadBootEvent_ %s %f" % (event.get("name"), event.get("dur"))) + self._jobs.get(event.get("name"))["executionTime"] = event.get("dur") + def startup_config_collect(base_path, target_cpu): parser = ConfigParser(os.path.join(base_path, "packages/phone")) parser.load_config("/system/etc/init.cfg") diff --git a/tools/startup_guard/config_parser_mgr/param/system_parameter_parser.py b/tools/startup_guard/config_parser_mgr/param/system_parameter_parser.py index 46bcfbd..5aa7948 100644 --- a/tools/startup_guard/config_parser_mgr/param/system_parameter_parser.py +++ b/tools/startup_guard/config_parser_mgr/param/system_parameter_parser.py @@ -36,10 +36,6 @@ class ParameterParser(dict): self["selinuxLabel"] = parameter.get("selinuxLabel") self["value"] = parameter.get("value") - def decode(self, info): - self["value"] = info.strip("\"").strip("\'") - return True - def __repr__(self): return self.__str__() @@ -48,6 +44,10 @@ class ParameterParser(dict): self["prefix"], self["dacUser"], self["dacGroup"], self["dacMode"], self["selinuxLabel"], self["value"]) + def decode(self, info): + self["value"] = info.strip("\"").strip("\'") + return True + class ParameterDacParser(ParameterParser): def __init__(self, prefix, parameter=None): ParameterParser.__init__(self, prefix, parameter) @@ -77,22 +77,6 @@ class ParameterFileParser(): def __init__(self): self._parameters = {} - def _handle_param_info(self, file_name, param_info): - param_name = param_info[0].strip() - old_param = self._parameters.get(param_name) - if file_name.endswith(".para.dac"): - param = ParameterDacParser(param_name, old_param) - if (param.decode(param_info[2].strip())): - self._parameters[param_name] = param - elif file_name.endswith(".para"): - param = ParameterParser(param_name, old_param) - if (param.decode(param_info[2].strip())): - self._parameters[param_name] = param - else: - param = ParameterSelinuxParser(param_name, old_param) - if (param.decode(param_info[2].strip())): - self._parameters[param_name] = param - def load_parameter_file(self, file_name, str = "="): try: with open(file_name, encoding='utf-8') as fp: @@ -115,6 +99,33 @@ class ParameterFileParser(): for param in self._parameters.values(): print(str(param)) + def scan_parameter_file(self, dir): + parameter_paths = [ + "/system/etc/param/ohos_const", + "/vendor/etc/param", + "/chip_prod/etc/param", + "/sys_prod/etc/param", + "/system/etc/param", + ] + for path in parameter_paths: + self._scan_parameter_file("{}/packages/phone{}".format(dir, path)) + + def _handle_param_info(self, file_name, param_info): + param_name = param_info[0].strip() + old_param = self._parameters.get(param_name) + if file_name.endswith(".para.dac"): + param = ParameterDacParser(param_name, old_param) + if (param.decode(param_info[2].strip())): + self._parameters[param_name] = param + elif file_name.endswith(".para"): + param = ParameterParser(param_name, old_param) + if (param.decode(param_info[2].strip())): + self._parameters[param_name] = param + else: + param = ParameterSelinuxParser(param_name, old_param) + if (param.decode(param_info[2].strip())): + self._parameters[param_name] = param + def _check_file(self, file): valid_file_ext = [".para", ".para.dac"] if not file.is_file(): @@ -132,17 +143,6 @@ class ParameterFileParser(): if self._check_file(file): self.load_parameter_file(file.path) - def scan_parameter_file(self, dir): - parameter_paths = [ - "/system/etc/param/ohos_const", - "/vendor/etc/param", - "/chip_prod/etc/param", - "/sys_prod/etc/param", - "/system/etc/param", - ] - for path in parameter_paths: - self._scan_parameter_file("{}/packages/phone{}".format(dir, path)) - def __create_arg_parser(): import argparse parser = argparse.ArgumentParser(description='Collect parameter information from xxxx/etc/param dir.') diff --git a/tools/startup_guard/config_parser_mgr/user_group/user_group_parser.py b/tools/startup_guard/config_parser_mgr/user_group/user_group_parser.py index 66f368f..7456450 100644 --- a/tools/startup_guard/config_parser_mgr/user_group/user_group_parser.py +++ b/tools/startup_guard/config_parser_mgr/user_group/user_group_parser.py @@ -24,21 +24,6 @@ class GroupFileParser(): def __init__(self): self._group = {} - def _handleGroupInfo(self, groupInfo): - name = groupInfo[0].strip() - userNames = name - if len(groupInfo) > 3 and len(groupInfo[3]) > 0: - userNames = groupInfo[3] - oldGroup = self._group.get(name) - if oldGroup: - return - group = { - "name" : name, - "groupId" : int(groupInfo[2], 10), - "userNames" : userNames - } - self._group[name] = group - def loadFile(self, fileName): #print(" loadFile %s" % fileName) if not os.path.exists(fileName): @@ -63,6 +48,21 @@ class GroupFileParser(): for group in self._group.values() : print(str(group)) + def _handleGroupInfo(self, groupInfo): + name = groupInfo[0].strip() + userNames = name + if len(groupInfo) > 3 and len(groupInfo[3]) > 0: + userNames = groupInfo[3] + oldGroup = self._group.get(name) + if oldGroup: + return + group = { + "name" : name, + "groupId" : int(groupInfo[2], 10), + "userNames" : userNames + } + self._group[name] = group + class PasswdFileParser(): def __init__(self): self._passwd = {} @@ -70,24 +70,6 @@ class PasswdFileParser(): self._name_list = [] self._uid_list = [] - def _handlePasswdInfo(self, passwdInfo): - name = passwdInfo[0].strip() - self._uid_list.append(int(passwdInfo[2], 10)) - self._name_list.append(name) - oldPasswd = self._passwd.get(name) - if oldPasswd: - return - - gid = int(passwdInfo[3], 10) - uid = int(passwdInfo[2], 10) - - passwd = { - "name" : name, - "groupId" : gid, - "passwdId" : uid - } - self._passwd[name] = passwd - def loadFile(self, fileName): # print(" loadFile %s" % fileName) if not os.path.exists(fileName): @@ -112,6 +94,24 @@ class PasswdFileParser(): for group in self._passwd.values() : print(str(group)) + def _handlePasswdInfo(self, passwdInfo): + name = passwdInfo[0].strip() + self._uid_list.append(int(passwdInfo[2], 10)) + self._name_list.append(name) + oldPasswd = self._passwd.get(name) + if oldPasswd: + return + + gid = int(passwdInfo[3], 10) + uid = int(passwdInfo[2], 10) + + passwd = { + "name" : name, + "groupId" : gid, + "passwdId" : uid + } + self._passwd[name] = passwd + def _create_arg_parser(): import argparse parser = argparse.ArgumentParser(description='Collect group information from system/etc/group dir.') diff --git a/tools/startup_guard/startup_checker/cmds_rule.py b/tools/startup_guard/startup_checker/cmds_rule.py index 59c7ef1..3c846a9 100644 --- a/tools/startup_guard/startup_checker/cmds_rule.py +++ b/tools/startup_guard/startup_checker/cmds_rule.py @@ -32,6 +32,22 @@ class cmdRule(BaseRule): self._condition_list = {} self._start_cmd_list = {} + def __check__(self): + return self.check_config_cmd() + + def check_config_cmd(self): + passed = True + self._parse_while_list() + cfg_parser = self.get_mgr().get_parser_by_name('config_parser') + self._get_json_service() + + start_passed = self._check_start_cmd(cfg_parser) + secon_passed = self._check_selinux(cfg_parser) + cmd_passed = self._check_cmdline_in_parser(cfg_parser) + start_mode_passed = self._check_service(cfg_parser) + passed = start_passed and secon_passed and cmd_passed and start_mode_passed + return passed + def _get_json_service(self): for i in range(len(self._start_modes)): if self._start_modes[i]["start-mode"] == "boot": @@ -131,19 +147,3 @@ class cmdRule(BaseRule): passed = False pass return passed - - def check_config_cmd(self): - passed = True - self._parse_while_list() - cfg_parser = self.get_mgr().get_parser_by_name('config_parser') - self._get_json_service() - - start_passed = self._check_start_cmd(cfg_parser) - secon_passed = self._check_selinux(cfg_parser) - cmd_passed = self._check_cmdline_in_parser(cfg_parser) - start_mode_passed = self._check_service(cfg_parser) - passed = start_passed and secon_passed and cmd_passed and start_mode_passed - return passed - - def __check__(self): - return self.check_config_cmd() diff --git a/tools/startup_guard/startup_checker/plug_in_rule.py b/tools/startup_guard/startup_checker/plug_in_rule.py index 3c3e3bc..3b1fad9 100644 --- a/tools/startup_guard/startup_checker/plug_in_rule.py +++ b/tools/startup_guard/startup_checker/plug_in_rule.py @@ -30,6 +30,26 @@ class PlugInModuleRule(BaseRule): self._private_so = {} self._passwd = True + def __check__(self): + return self.check_plug_in_library() + + def check_plug_in_library(self): + cfg_parser = self.get_mgr().get_parser_by_name('config_parser') + white_lists =self.get_white_lists() + for key, item in white_lists[0].items(): + if key == "base_library": + self._base_so = item + if key == "private_library": + self._private_so = item + keys = list(self._private_so.keys()) + for name in cfg_parser._plug_in: + if os.path.basename(name) not in keys: + self.error("%s is not in whitelists" % os.path.basename(name)) + self._passwd = False + continue + self._read_elf_dt_needed(name) + return self._passwd + def _read_elf_dt_needed(self, file): # print(file) paser = self._private_so @@ -52,24 +72,3 @@ class PlugInModuleRule(BaseRule): self.error("%s" % error_log) continue pass - - - def check_plug_in_library(self): - cfg_parser = self.get_mgr().get_parser_by_name('config_parser') - white_lists =self.get_white_lists() - for key, item in white_lists[0].items(): - if key == "base_library": - self._base_so = item - if key == "private_library": - self._private_so = item - keys = list(self._private_so.keys()) - for name in cfg_parser._plug_in: - if os.path.basename(name) not in keys: - self.error("%s is not in whitelists" % os.path.basename(name)) - self._passwd = False - continue - self._read_elf_dt_needed(name) - return self._passwd - - def __check__(self): - return self.check_plug_in_library() diff --git a/tools/startup_guard/startup_checker/system_parameter_rules.py b/tools/startup_guard/startup_checker/system_parameter_rules.py index cbf1da1..1b71c8f 100644 --- a/tools/startup_guard/startup_checker/system_parameter_rules.py +++ b/tools/startup_guard/startup_checker/system_parameter_rules.py @@ -21,6 +21,8 @@ from .base_rule import BaseRule class SystemParameterRule(BaseRule): RULE_NAME = "NO-Config-SystemParameter-In-INIT" CONFIG_DAC_MAX_NUM = 200 + def __check__(self): + return self._check_Param_in_init() def _check_param_name(self, param_name, empty_flag): # len: (0, 96] @@ -68,6 +70,3 @@ class SystemParameterRule(BaseRule): self.error("DAC overallocated memory") passed = False return passed - - def __check__(self): - return self._check_Param_in_init() diff --git a/tools/startup_guard/startup_checker/user_group_rule.py b/tools/startup_guard/startup_checker/user_group_rule.py index 25f29bd..52c1ab8 100644 --- a/tools/startup_guard/startup_checker/user_group_rule.py +++ b/tools/startup_guard/startup_checker/user_group_rule.py @@ -26,15 +26,8 @@ class UserGroupModuleRule(BaseRule): def __init__(self, mgr, args): super().__init__(mgr, args) - def _check_gid_in_passwd(self, passwd): - isPassed = True - for key, value in passwd.items(): - if value["passwdId"] == value["groupId"]: - pass - else: - isPassed = False - self.error("%s has different passwd and group values" % value["name"]) - return isPassed + def __check__(self): + return self.check_user_group() def check_user_group(self): passed = True @@ -63,5 +56,12 @@ class UserGroupModuleRule(BaseRule): passed = False self.error("%s has different passwd and group values" % value["uid"]) - def __check__(self): - return self.check_user_group() + def _check_gid_in_passwd(self, passwd): + isPassed = True + for key, value in passwd.items(): + if value["passwdId"] == value["groupId"]: + pass + else: + isPassed = False + self.error("%s has different passwd and group values" % value["name"]) + return isPassed -- Gitee