def _set_password_config(self): common.backup("/etc/shadow") path = "/etc/login.defs" common.backup(path) params = { "PASS_MAX_DAYS": "365", "PASS_MIN_DAYS": "7", "PASS_WARN_AGE": "7" } common.change_parameters(path, params) # inactive password lock common.run("useradd -D -f 30") current_user = common.input_text("What is the current username") users = common.get_current_users() for user in users: if user == current_user: continue common.run_full("chage --lastday $(date +%Y/%m/%d) {}".format(user)) common.run("chage --maxdays 365 {}".format(user)) common.run("chage --mindays 7 {}".format(user)) common.run("chage --warndays 7 {}".format(user)) common.run("chage --inactive 30 {}".format(user)) common.run("passwd --expire {}".format(user))
def modify_network_config(self): log('Modify network config for environment %s' % self.env_id) network_yaml = ('%s/network_%s.yaml' % (self.yaml_config_dir, self.env_id)) check_file_exists(network_yaml) backup(network_yaml) network_config = self.dea.get_property('network') with io.open(network_yaml) as stream: network = yaml.load(stream) net_names = self.dea.get_network_names() net_id = {} for net in network['networks']: if net['name'] in net_names: net_id[net['name']] = { 'id': net['id'], 'group_id': net['group_id'] } for network in network_config['networks']: network.update(net_id[network['name']]) with io.open(network_yaml, 'w') as stream: yaml.dump(network_config, stream, default_flow_style=False)
def modify_node_interface(self, node_id, roles_blade): log('Modify interface config for node %s' % node_id) interface_yaml = ('%s/node_%s/interfaces.yaml' % (self.yaml_config_dir, node_id)) check_file_exists(interface_yaml) backup('%s/node_%s' % (self.yaml_config_dir, node_id)) with io.open(interface_yaml) as stream: interfaces = yaml.load(stream) net_name_id = {} for interface in interfaces: for network in interface['assigned_networks']: net_name_id[network['name']] = network['id'] type = self.dea.get_node_property(roles_blade[1], 'interfaces') interface_config = self.dea.get_property(type) for interface in interfaces: interface['assigned_networks'] = [] if interface['name'] in interface_config: for net_name in interface_config[interface['name']]: net = {} net['id'] = net_name_id[net_name] net['name'] = net_name interface['assigned_networks'].append(net) with io.open(interface_yaml, 'w') as stream: yaml.dump(interfaces, stream, default_flow_style=False)
def modify_settings(self): log('Modify settings for environment %s' % self.env_id) settings_yaml = ('%s/settings_%s.yaml' % (self.yaml_config_dir, self.env_id)) check_file_exists(settings_yaml) with io.open(settings_yaml, 'r') as stream: orig_dea = yaml.load(stream) backup(settings_yaml) settings = self.dea.get_property('settings') # Copy fuel defined plugin_id's to user defined settings # From Fuel 8.0 chosen_id was added because it is now # possible to install many version of the same plugin # but we will install only one version for plugin in orig_dea['editable']: if 'metadata' in orig_dea['editable'][plugin]: if 'plugin_id' in orig_dea['editable'][plugin]['metadata']: if not plugin in settings['editable']: settings['editable'][plugin] = orig_dea['editable'][plugin] else: settings['editable'][plugin]["metadata"]["plugin_id"] = orig_dea['editable'][plugin]["metadata"]["plugin_id"] elif 'chosen_id' in orig_dea['editable'][plugin]['metadata']: if not plugin in settings['editable']: settings['editable'][plugin] = orig_dea['editable'][plugin] else: settings['editable'][plugin]['metadata']['chosen_id'] = orig_dea['editable'][plugin]['metadata']['chosen_id'] settings['editable'][plugin]['metadata']['versions'][0]['metadata']['plugin_id'] = orig_dea['editable'][plugin]['metadata']['versions'][0]['metadata']['plugin_id'] with io.open(settings_yaml, 'w') as stream: yaml.dump(settings, stream, default_flow_style=False)
def generate_hosts(): backup(BACKUP_HOSTS_CMD) ori_hosts = [] with open(HOSTS, "r") as old: line = old.readline() while line: ori_hosts.append(line) if "metadata" in line: break line = old.readline() tmp_hosts = "{}/hosts".format(APP_HOME) with open(tmp_hosts, "w") as hosts: for line in ori_hosts: hosts.write(line) with open(HOSTS_INFO_FILE, "r") as ehpc_hosts: hosts_lines = ehpc_hosts.readlines() for i in range(len(hosts_lines)): # replace node1 to node001 if hosts_lines[i].find(COMPUTE_HOSTNAME_PREFIX) != -1: node = hosts_lines[i].split()[1] sid = int(node.split(COMPUTE_HOSTNAME_PREFIX)[1]) new_node = "%s%03d" % (COMPUTE_HOSTNAME_PREFIX, sid) hosts_lines[i] = hosts_lines[i].replace(node, new_node) hosts.writelines(hosts_lines) run_shell("mv {} {}".format(tmp_hosts, HOSTS))
def update_slurm_conf(update_cmpnode_res=False, nodes_change=False): # backup last slurm configuration if os_path.exists(SLURM_CONF): backup(BACKUP_SLURM_CONF_CMD) # replace slurm.conf.template tmp_file = "{}/slurm.conf.tmp".format(APP_HOME) run_shell("cp -f {} {}".format(SLURM_CONF, tmp_file)) # update NodeName if update_cmpnode_res: update_cmpnodes_res_conf(tmp_file) # get current queues info queues_info = get_queues_details() # update queues_info according to nodes changing if nodes_change: update_queues_info_with_nodes_change(queues_info) # update queues_info to slurm conf Partition update_queues_conf_file(tmp_file, queues_info) run_shell("mv {} {}".format(tmp_file, SLURM_CONF)) pass
def _set_default_hosts(self): """Clears hosts and sets default hostname.""" if "Linux" in plugin.get_os(): hostname = "CADSHOST" common.backup("/etc/hostname") with open("/etc/hostname", "w") as out_file: out_file.write(hostname + "\n") with open("policies/hosts") as in_file: text = in_file.read() hosts = text.format(hostname) common.backup("/etc/hosts") with open("/etc/hosts", "w") as out_file: out_file.write(hosts) common.run("hostname {}".format(hostname)) else: with open("policies/hosts.win") as in_file: text = in_file.read() path = "C:\\Windows\\System32\\drivers\\etc\\hosts" # Ah ha, CI, you won't get past this! common.backup(path) with open(path, "w") as out_file: out_file.write(text)
def saveent(self, e): cm.backup(self.dbname) tagstr = ','.join(set(e.tag)) keyword = {'name':e.name, 'rank':e.rank, 'content':e.content, 'tag':tagstr} objdict = e.property.copy() objdict.update(keyword) # combine two dictionary self.db.remove(Query().rank == e.rank) # make sure there is no duplication self.db.insert(objdict)
def _set_password_lockout(self): paths = ["/etc/pam.d/system-authand", "/etc/pam.d/password-auth"] for path in paths: if os.path.isfile(path): common.warn( "{} exists, needs checking (password lockout)".format( path)) path = "/etc/pam.d/common-auth" common.backup(path) with open(path) as in_file: lines = in_file.read().split("\n") permit_index = None # used for fedora based distros # text = """auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900 # auth required pam_faillock.so preauth audit silent deny=5 unlock_time=900 # auth sufficient pam_unix.so # auth [default=die] pam_faillock.so authfail audit deny=5unlock_time=900 # auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=900""" text = """auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900""" for index, line in enumerate(lines): if "pam_faillock.so" in line: common.warn( "Found faillock, needs checking (password lockout)") elif "pam_permit.so" in line: permit_index = index if text == lines[permit_index - 1]: common.debug("Tally already exists") elif permit_index is not None: lines.insert(permit_index, text) else: common.error("Error {} not formatted as expected".format(path)) return with open(path, "w") as out_file: out_file.write("\n".join(lines)) # Ensure user doesn't get locked out user = common.input_text("Enter current user") common.run("pam_tally2 -u {} --reset".format(user)) # Everytime they use sudo the tally gets reset with open("/home/{}/.bashrc".format(user), "a") as out_file: out_file.write( "\nalias sudo='sudo pam_tally2 -u {} --reset >/dev/null; sudo '\n" .format(user)) common.reminder( "You need to reload .bashrc in all currently used terminals: source ~/.bashrc" ) common.debug("Set Password Lockout")
def generate_conf(): # get cluster_name cluster_info = get_cluster_info() cls_name = cluster_info["cluster_name"] ctl_resource = "" # the first line in resource.info cmp_resource = "" # the last line in resource.info with open(RESOURCE_INFO_FILE, "r") as info: lines = info.readlines() for line in lines: if line: if not ctl_resource: ctl_resource = line else: cmp_resource = line # generate default NodeName, eg: node[1-6,8,12-15] sids = [int(s) for s in cluster_info["sids"].split(",") if s] sids.sort() node_name = "{}[".format(COMPUTE_HOSTNAME_PREFIX) # eg: [1-6,8] start_sid = sids[0] # eg: 1 last_sid = start_sid for sid in sids: if sid - last_sid > 1: if last_sid == start_sid: node_name = "{}{},".format(node_name, start_sid) # eg: [1-6,8, else: node_name = "{}{}-{},".format(node_name, start_sid, last_sid) # eg: [1-6,8,12-15] start_sid = sid last_sid = sid if last_sid == start_sid: # the end of sids node_name = "{}{}]".format(node_name, start_sid) else: node_name = "{}{}-{}]".format(node_name, start_sid, last_sid) # backup last slurm configuration if os_path.exists(SLURM_CONF): backup(BACKUP_SLURM_CONF_CMD) # replace slurm.conf.template tmp_file = "{}/slurm.conf.tmp".format(APP_HOME) with open(tmp_file, "w") as conf: with open(SLURM_CONF_TMPL, "r") as tmpl: for line in tmpl.readlines(): if line: line = line.format(CLUSTER_NAME=cls_name, CONTROLLER_RESOURCE=ctl_resource, COMPUTE_RESOURCE=cmp_resource, DEFAULT_NODE_NAME=node_name) conf.write(line) run_shell("mv {} {}".format(tmp_file, SLURM_CONF))
def modify_settings(self): log('Modify settings for environment %s' % self.env_id) settings_yaml = ('%s/settings_%s.yaml' % (self.yaml_config_dir, self.env_id)) check_file_exists(settings_yaml) backup(settings_yaml) settings = self.dea.get_property('settings') with io.open(settings_yaml, 'w') as stream: yaml.dump(settings, stream, default_flow_style=False)
def _remove_user_jobs(self): """Removes all user cronjobs.""" path = "/var/spool/cron" common.backup(path, compress=True) # Definitely didn't copy this straight off Stack Overflow for root, dirs, files in os.walk(path): for f in files: os.unlink(os.path.join(root, f)) for d in dirs: shutil.rmtree(os.path.join(root, d)) common.debug("Removed all user cronjobs")
def update_queues_conf(queues_info): # backup last slurm configuration if os_path.exists(SLURM_CONF): backup(BACKUP_SLURM_CONF_CMD) # replace slurm.conf.template tmp_file = "{}/slurm.conf.tmp".format(APP_HOME) run_shell("cp -f {} {}".format(SLURM_CONF, tmp_file)) update_queues_conf_file(tmp_file, queues_info) run_shell("mv {} {}".format(tmp_file, SLURM_CONF)) return 0
def _remove_and_backup(self, path): """Backs up file and removes it. Args: path (str): the path to remove """ if os.path.isfile(path): common.backup(path, compress=True) os.remove(path) # remove the file elif os.path.isdir(path): common.backup(path, compress=True) shutil.rmtree(path) # remove dir and all contains
def _configure_hosts(self): """Secure allow and deny hosts files.""" common.backup("/etc/hosts.allow") common.backup("/etc/hosts.deny") reminder = "You need to set up /etc/hosts.allow\nIn the format: 'ALL: <net>/<mask>, <net>/<mask>'" common.reminder(reminder) with open("/etc/hosts.deny", "w") as out_file: out_file.write("ALL: ALL") common.set_permissions("/etc/hosts.allow", "root", "root", "644") common.set_permissions("/etc/hosts.deny", "root", "root", "644")
def modify_node_network_schemes(self, node_id, roles_blade): log('Modify network transformations for node %s' % node_id) type = self.dea.get_node_property(roles_blade[1], 'transformations') transformations = self.dea.get_property(type) deployment_dir = '%s/deployment_%s' % (self.yaml_config_dir, self.env_id) backup(deployment_dir) for node_file in glob.glob(deployment_dir + '/*_%s.yaml' % node_id): with io.open(node_file) as stream: node = yaml.load(stream) node['network_scheme'].update(transformations) with io.open(node_file, 'w') as stream: yaml.dump(node, stream, default_flow_style=False)
def modify_node_network_schemes(self, node_id, roles_blade): log('Modify network transformations for node %s' % node_id) type = self.dea.get_node_property(roles_blade[1], 'transformations') transformations = self.dea.get_property(type) deployment_dir = '%s/deployment_%s' % ( self.yaml_config_dir, self.env_id) backup(deployment_dir) for node_file in glob.glob(deployment_dir + '/*_%s.yaml' % node_id): with io.open(node_file) as stream: node = yaml.load(stream) node['network_scheme'].update(transformations) with io.open(node_file, 'w') as stream: yaml.dump(node, stream, default_flow_style=False)
def execute(self): """Execute plugin.""" path = "/etc/ssh/sshd_config" if os.path.isfile(path): common.backup(path) else: common.info("{} not found, skipping SSH".format(path)) return # set correct permissions common.run("chown root:root {}".format(path)) common.run("chmod og-rwx {}".format(path)) # some fancy commands that ensure correct permissions on private keys common.run_full("find /etc/ssh -xdev -type f -name 'ssh_host_*_key' -exec chown root:root {} \\;") common.run_full("find /etc/ssh -xdev -type f -name 'ssh_host_*_key' -exec chmod 0600 {} \\;") # some fancy commands that ensure correct permissions on public keys common.run_full("find /etc/ssh -xdev -type f -name 'ssh_host_*_key.pub' -exec chmod 0644 {} \\;") common.run_full("find /etc/ssh -xdev -type f -name 'ssh_host_*_key.pub' -exec chown root:root {} \\;") params = { "Protocol": "2", "LogLevel": "VERBOSE", "X11Forwarding": "no", "MaxAuthTries": "4", "IgnoreRhosts": "yes", "HostbasedAuthentication": "no", "PermitRootLogin": "******", "PermitEmptyPasswords": "no", "PermitUserEnvironment": "no", "Ciphers": "[email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr", "MACs": "[email protected],[email protected],hmac-sha2-512,hmac-sha2-256", "KexAlgorithms": "[email protected],ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256", "ClientAliveInterval": "300", "ClientAliveCountMax": "0", "LoginGraceTime": "60", "Banner": "/etc/issue.net", "UsePAM": "yes", "AllowTcpForwarding": "no", "maxstartups": "10:30:60", "MaxSessions": "4" } common.change_parameters(path, params) common.warn("Not doing anything about ssh access, (groups, users)")
def _set_profile(self): # set umask and shell timeout profiles = ["/etc/bashrc", "/etc/bash.bashrc", "/etc/profile"] for profile in profiles: try: common.backup(profile) with open(profile, "a") as out_file: out_file.write("\numask 027\nTMOUT=900\n") except FileNotFoundError: continue # sets umask alt_profiles = glob.glob("/etc/profile.d/*.sh") for profile in alt_profiles: common.backup(profile) with open(profile, "a") as out_file: out_file.write("\numask 027\n")
def modify_node_attributes(self, node_id, roles_blade): log('Modify attributes for node {0}'.format(node_id)) dea_key = self.dea.get_node_property(roles_blade[1], 'attributes') if not dea_key: # Node attributes are not overridden. Nothing to do. return new_attributes = self.dea.get_property(dea_key) attributes_yaml = ('%s/node_%s/attributes.yaml' % (self.yaml_config_dir, node_id)) check_file_exists(attributes_yaml) backup('%s/node_%s' % (self.yaml_config_dir, node_id)) with open(attributes_yaml) as stream: attributes = yaml.load(stream) result_attributes = self._merge_dicts(attributes, new_attributes) with open(attributes_yaml, 'w') as stream: yaml.dump(result_attributes, stream, default_flow_style=False)
def strip(file): real_file = common.slashfix(file) lines = [] with open(real_file, 'r') as f: for line in f: lines.append(fix(line.rstrip('\n'))) with common.backup(real_file): with open(real_file, 'w') as f: for line in lines: print(line, file=f)
def execute(self): """Execute plugin.""" # Fetch a list of home directories dirs = self._get_home_directories() common.info("Found {} home directories: {}".format(len(dirs), dirs)) exclude = common.input_list( "Please input a list of folder names to exclude (recommended to add your username)" ) for d in dirs: if any(e == self._last_folder_name(d) for e in exclude): common.debug("Skipping directory {}".format(d)) continue common.info("Purging {}...".format(d)) common.debug("Backing up folder...") common.backup(d, compress=True) common.debug("Removing folder contents...") self._clear_folder(d)
def generate_hosts(): backup(BACKUP_HOSTS_CMD) ori_hosts = [] with open(HOSTS, "r") as old: line = old.readline() while line: ori_hosts.append(line) if "metadata" in line: break line = old.readline() tmp_hosts = "{}/hosts".format(APP_HOME) with open(tmp_hosts, "w") as hosts: for line in ori_hosts: hosts.write(line) with open(HOSTS_INFO_FILE, "r") as ehpc_hosts: hosts.writelines(ehpc_hosts.readlines()) run_shell("mv {} {}".format(tmp_hosts, HOSTS))
def execute(self): """Execute plugin.""" path = "/etc/lightdm/lightdm.conf" config = configparser.ConfigParser() try: common.backup(path) config.read(path) except FileNotFoundError as ex: common.error("{} not found".format(path), ex) config["Seat:*"] = {} config["Seat:*"]["user-session"] = "ubuntu" config["Seat:*"]["greeter-session"] = "unity-greeter" config["Seat:*"]["greeter-show-manual-login"] = "******" config["Seat:*"]["greeter-hide-users"] = "true" config["Seat:*"]["allow-guest"] = "false" with open(path, "w+") as out_file: config.write(out_file) common.info("{} updated".format(path))
def modify_node_interface(self, node_id, roles_blade): log('Modify interface config for node %s' % node_id) interface_yaml = ('%s/node_%s/interfaces.yaml' % (self.yaml_config_dir, node_id)) check_file_exists(interface_yaml) backup('%s/node_%s' % (self.yaml_config_dir, node_id)) with io.open(interface_yaml) as stream: interfaces = yaml.load(stream) net_name_id = {} for interface in interfaces: for network in interface['assigned_networks']: net_name_id[network['name']] = network['id'] type = self.dea.get_node_property(roles_blade[1], 'interfaces') interface_config = self.dea.get_property(type) for interface in interfaces: interface['assigned_networks'] = [] if interface['name'] in interface_config: for prop in interface_config[interface['name']]: net = {} # net name if isinstance(prop, six.string_types): net['id'] = net_name_id[prop] net['name'] = prop interface['assigned_networks'].append(net) # network properties elif isinstance(prop, dict): if 'interface_properties' not in prop: log('Interface configuration contains unknown dict: %s' % prop) continue interface['attributes'] = self._merge_dicts( interface.get('attributes', {}), prop.get('interface_properties', {})) with io.open(interface_yaml, 'w') as stream: yaml.dump(interfaces, stream, default_flow_style=False)
def modify_settings(self): log('Modify settings for environment %s' % self.env_id) settings_yaml = ('%s/settings_%s.yaml' % (self.yaml_config_dir, self.env_id)) check_file_exists(settings_yaml) with io.open(settings_yaml, 'r') as stream: orig_dea = yaml.load(stream) backup(settings_yaml) settings = self.dea.get_property('settings') # Copy fuel defined plugin_id's to user defined settings # From Fuel 8.0 chosen_id was added because it is now # possible to install many version of the same plugin # but we will install only one version for plugin in orig_dea['editable']: if 'metadata' in orig_dea['editable'][plugin]: if 'plugin_id' in orig_dea['editable'][plugin]['metadata']: if not plugin in settings['editable']: settings['editable'][plugin] = orig_dea['editable'][ plugin] else: settings['editable'][plugin]["metadata"][ "plugin_id"] = orig_dea['editable'][plugin][ "metadata"]["plugin_id"] elif 'chosen_id' in orig_dea['editable'][plugin]['metadata']: if not plugin in settings['editable']: settings['editable'][plugin] = orig_dea['editable'][ plugin] else: settings['editable'][plugin]['metadata'][ 'chosen_id'] = orig_dea['editable'][plugin][ 'metadata']['chosen_id'] settings['editable'][plugin]['metadata']['versions'][ 0]['metadata']['plugin_id'] = orig_dea['editable'][ plugin]['metadata']['versions'][0]['metadata'][ 'plugin_id'] with io.open(settings_yaml, 'w') as stream: yaml.dump(settings, stream, default_flow_style=False)
def generate_slurm_conf(): # get cluster_name cluster_info = get_cluster_info() cls_name = cluster_info["cluster_name"] ctl_resource = "" # the first line in resource.info cmp_resource = "" # the last line in resource.info with open(RESOURCE_INFO_FILE, "r") as info: lines = info.readlines() for line in lines: if line: if not ctl_resource: ctl_resource = line else: cmp_resource = line node_list = get_slurm_cmpnode_list(cluster_info) ctl_machine = get_ctl_machine() # backup last slurm configuration if os_path.exists(SLURM_CONF): backup(BACKUP_SLURM_CONF_CMD) # replace slurm.conf.template tmp_file = "{}/slurm.conf.tmp".format(APP_HOME) with open(tmp_file, "w") as conf: with open(SLURM_CONF_TMPL, "r") as tmpl: for line in tmpl.readlines(): if line: line = line.format(CLUSTER_NAME=cls_name, CONTROL_MACHINE=ctl_machine, CONTROLLER_RESOURCE=ctl_resource, COMPUTE_RESOURCE=cmp_resource, DEFAULT_NODE_NAME=node_list) conf.write(line) run_shell("mv {} {}".format(tmp_file, SLURM_CONF))
def execute(self): """Execute plugin.""" if "Linux" in plugin.get_os(): common.backup("/etc/passwd") common.backup("/etc/group") common.backup("/etc/shadow") current_user = common.input_text("What is the current username") admins = self._get_users("Admin") # ensures the current user isn't in the admin list if current_user in admins: admins.remove(current_user) standard = self._get_users("Standard") # ensures the current user isn't in the standard list if current_user in standard: standard.remove(current_user) current_users = self._get_current_users() common.debug("Found users: {}".format(", ".join(current_users))) # first we need to get rid of the bad users bad_users = [] for user in current_users: if user not in [current_user] + admins + standard: bad_users.append(user) self._delete_users(bad_users) current_users = list(set(current_users) - set(bad_users)) # find new users new_users = [] for user in admins + standard: if user not in current_users: new_users.append(user) self._create_users(new_users) # set all users to a standard user self._set_standard_users(standard) # set admin users to admin self._set_admin_users(admins) # change password to a secure one common.info("Changing passwords") for index, user in enumerate([current_user] + admins + standard): if user != current_user: # Not sure if we want to do this on the main user password = "******".format(index) self._change_password(user, password) self._set_password_no_expire(user) self._change_password_on_login(user)
def _set_password_requirements( self ): # also deals with password reuse and ensuring sha512 is used # /etc/pam.d/system-auth - check if exists due to alternative method of implementation path = "/etc/pam.d/system-auth" if os.path.isfile(path): common.reminder( "{} exists, needs checking (cracklib/pwquality)".format(path)) path = "/etc/pam.d/common-password" common.backup(path) # we need to ensure cracklib is installed, it will also change common-password common.run("sudo apt install libpam-cracklib -y -q") common.backup(path) with open(path) as in_file: lines = in_file.read().split("\n") cracklib_index = None pwquality_index = None unix_index = None for index, line in enumerate(lines): if "pam_cracklib.so" in line: cracklib_index = index elif "pam_pwquality.so" in line: pwquality_index = index elif "pam_unix.so" in line: unix_index = index cracklib = "password required pam_cracklib.so try_first_pass retry=3 minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1" pwquality = "password requisite pam_pwquality.so try_first_pass retry=3" # we can also ensure that it remembers passwords unix = "password sufficient pam_unix.so sha512 shadow use_authtok remember=5" if unix_index is not None: lines[unix_index] = unix else: common.error( "Error, could not find unix_index, {} is misconfigured".format( path)) return # You can use either cracklib or pwquality, but one of them must be used if cracklib_index is not None: lines[cracklib_index] = cracklib elif pwquality_index is not None: common.debug("pwquality is used instead of cracklib") lines[pwquality_index] = pwquality else: # no cracklib or pwquality, we'll add cracklib (in the right place) common.error("Cracklib is not configured correctly") return with open(path, "w") as out_file: out_file.write("\n".join(lines)) # This only needs to be done for the pwquality, although it can't hurt to do it anyway path = "/etc/security/pwquality.conf" common.backup(path) with open(path, "w") as out_file: text = "minlen = 14\ndcredit = -1\nucredit = -1\nocredit = -1\nlcredit = -1" out_file.write(text) common.info("Added Password requirements")