def _adjustSssdConfiguration(domain): logging.info("Adjusting sssd.conf") sssdConfigFilePath = '/etc/sssd/sssd.conf' sssdConfig = configparser.ConfigParser(interpolation=None) sssdConfig.read(sssdConfigFilePath) # accept usernames without domain sssdConfig[f"domain/{domain}"]["use_fully_qualified_names"] = "False" # override homedir sssdConfig[f"domain/{domain}"]["override_homedir"] = "/home/%u" # Don't validate KVNO! Otherwise the Login will fail when the KVNO stored # in /etc/krb5.keytab does not match the one in the AD (msDS-KeyVersionNumber) sssdConfig[f"domain/{domain}"]["krb5_validate"] = "False" sssdConfig[f"domain/{domain}"]["ad_gpo_access_control"] = "permissive" sssdConfig[f"domain/{domain}"]["ad_gpo_ignore_unreadable"] = "True" # Don't renew the machine password, as this will break the domain join # See: https://github.com/linuxmuster/linuxmuster-linuxclient7/issues/27 sssdConfig[f"domain/{domain}"][ "ad_maximum_machine_account_password_age"] = "0" # Make sure usernames are not case sensitive sssdConfig[f"domain/{domain}"]["case_sensitive"] = "False" try: logging.info("Writing new Configuration") with open(sssdConfigFilePath, 'w') as sssdConfigFile: sssdConfig.write(sssdConfigFile) except Exception as e: logging.error("Failed!") logging.exception(e) return False logging.info("Restarting sssd") if subprocess.call(["service", "sssd", "restart"]) != 0: logging.error("Failed!") return False return True
def network(): rc, rawNetworkConfig = _readNetworkConfig() if not rc: return False if not _checkNetworkConfigVersion(rawNetworkConfig)[0]: return False networkConfig = {} try: networkConfig["serverHostname"] = rawNetworkConfig["serverHostname"] networkConfig["domain"] = rawNetworkConfig["domain"] networkConfig["realm"] = rawNetworkConfig["realm"] except KeyError as e: logging.error("Error when reading network.conf (2)") logging.exception(e) return False, None return True, networkConfig
def removeLinesInFileContainingString(filePath, forbiddenStrings): """ Remove all lines containing a given string form a file. :param filePath: The path to the file :type filePath: str :param forbiddenStrings: The string to search for :type forbiddenStrings: str :return: True on success, False otherwise :rtype: bool """ if not isinstance(forbiddenStrings, list): forbiddenStrings = [forbiddenStrings] try: with open(filePath, "r") as originalFile: originalContents = originalFile.read() except Exception as e: logging.exception(e) logging.warning("Could not read contents of original file") return False newContents = "" for line in originalContents.split("\n"): lineIsClean = True for forbiddenString in forbiddenStrings: lineIsClean = lineIsClean and not forbiddenString in line if lineIsClean: newContents += line + "\n" try: with open(filePath, "w") as originalFile: originalFile.write(newContents) except Exception as e: logging.exception(e) logging.warning("Could not write new contents to original file") return False return True
def searchOne(filter): if conn() == None: logging.error("Cannot talk to LDAP") return False, None try: rawResult = conn().search_s(baseDn(), ldap.SCOPE_SUBTREE, filter) except Exception as e: logging.error("Error executing LDAP search!") logging.exception(e) return False, None try: result = {} if len(rawResult) <= 0 or rawResult[0][0] == None: logging.debug( "Search \"{}\" did not return any objects".format(filter)) return False, None for k in rawResult[0][1]: if k != 'objectSid' and k != 'objectGUID' and rawResult[0][1][ k] != None: rawAttribute = rawResult[0][1][k] if len(rawAttribute) == 1: result[k] = str(rawAttribute[0].decode()) elif len(rawAttribute) > 0: result[k] = [] for rawItem in rawAttribute: result[k].append(str(rawItem.decode())) #print(k, str(rawResult[0][1][k])) #print(result) return True, result except Exception as e: logging.error("Error while reading ldap search results!") logging.exception(e) return False, None
def mountHomeShare(): """ Mounts the serverhome of the current user :return: True on success, False otherwise :rtype: bool """ rc1, userAttributes = readAttributes() rc2, shareName = _getHomeShareName(userAttributes) if rc1 and rc2: try: homeShareServerPath = userAttributes["homeDirectory"] res = shares.mountShare(homeShareServerPath, shareName=shareName, hiddenShare=False, username=username()) return res except Exception as e: logging.error("Could not mount home dir of user") logging.exception(e) return False, None
def _clearUserHomes(unattended=False): print("\nCAUTION! This will delete all userhomes of AD users!") if not unattended and not _askStep("clear all user homes now", False): return True if not _checkLoggedInUsers(): return False if not _unmountAllCifsMounts(): logging.info( "Aborting deletion of user homes to prevent deleting data on the server." ) return False userHomes = os.listdir("/home") logging.info("Deleting all user homes now!") for userHome in userHomes: if not user.isUserInAD(userHome): logging.info("* {} [SKIPPED]".format(userHome)) continue logging.info("* {}".format(userHome)) try: shutil.rmtree("/home/{}".format(userHome)) except Exception as e: logging.error("* FAILED!") logging.exception(e) try: shutil.rmtree(constants.hiddenShareMountBasepath.format(userHome)) except: pass logging.info("Done.") return True
def _adjustSssdConfiguration(domain): logging.info("Adjusting sssd.conf") sssdConfigFilePath = '/etc/sssd/sssd.conf' sssdConfig = configparser.ConfigParser(interpolation=None) sssdConfig.read(sssdConfigFilePath) # accept usernames without domain sssdConfig[f"domain/{domain}"]["use_fully_qualified_names"] = "False" # override homedir sssdConfig[f"domain/{domain}"]["override_homedir"] = "/home/%u" # Don't validate KVNO! Otherwise the Login will fail when the KVNO stored # in /etc/krb5.keytab does not match the one in the AD (msDS-KeyVersionNumber) sssdConfig[f"domain/{domain}"]["krb5_validate"] = "False" sssdConfig[f"domain/{domain}"]["ad_gpo_access_control"] = "permissive" sssdConfig[f"domain/{domain}"]["ad_gpo_ignore_unreadable"] = "True" try: logging.info("Writing new Configuration") with open(sssdConfigFilePath, 'w') as sssdConfigFile: sssdConfig.write(sssdConfigFile) except Exception as e: logging.error("Failed!") logging.exception(e) return False logging.info("Restarting sssd") if subprocess.call(["service", "sssd", "restart"]) != 0: logging.error("Failed!") return False return True
def _processPrintersPolicy(policyBasepath): logging.info("== Parsing a printer policy! ==") policyFile = "{}/User/Preferences/Printers/Printers.xml".format( policyBasepath) printerList = [] # test rc, tree = _parseXmlPolicy(policyFile) if not rc: logging.error( "==> Error while reading Printer policy file, skipping! ==") return xmlPrinters = tree.getroot() if not xmlPrinters.tag == "Printers": logging.warning( "==> Printer policy xml File is of invalid format, skipping! ==") return for xmlPrinter in xmlPrinters: if xmlPrinter.tag != "SharedPrinter" or ( "disabled" in xmlPrinter.attrib and xmlPrinter.attrib["disabled"] == "1"): continue printer = {} printer["filters"] = [] try: printer["name"] = xmlPrinter.attrib["name"] except Exception as e: logging.warning( "Exception when reading a printer name from a printer policy XML file" ) logging.exception(e) for xmlPrinterProperty in xmlPrinter: if xmlPrinterProperty.tag == "Properties": try: rc, printerUrl = printers.translateSambaToIpp( xmlPrinterProperty.attrib["path"]) if rc: printer["path"] = printerUrl except Exception as e: logging.warning( "Exception when parsing a printer policy XML file") logging.exception(e) continue if xmlPrinterProperty.tag == "Filters": printer["filters"] = _parseXmlFilters(xmlPrinterProperty) printerList.append(printer) printerList = _processFilters(printerList) logging.info("Found printers:") for printer in printerList: logging.info("* {0}\t\t| {1}\t| {2}".format(printer["name"], printer["path"], printer["filters"])) printers.installPrinter(printer["path"], printer["name"]) logging.info("==> Successfully parsed a printer policy! ==")
def _processDrivesPolicy(policyBasepath): logging.info("== Parsing a drive policy! ==") policyFile = "{}/User/Preferences/Drives/Drives.xml".format(policyBasepath) shareList = [] rc, tree = _parseXmlPolicy(policyFile) if not rc: logging.error( "==> Error while reading Drives policy file, skipping! ==") return xmlDrives = tree.getroot() if not xmlDrives.tag == "Drives": logging.warning( "==> Drive policy xml File is of invalid format, skipping! ==") return for xmlDrive in xmlDrives: if xmlDrive.tag != "Drive" or ("disabled" in xmlDrive.attrib and xmlDrive.attrib["disabled"] == "1"): continue drive = {} drive["filters"] = [] for xmlDriveProperty in xmlDrive: if xmlDriveProperty.tag == "Properties": try: drive["label"] = xmlDriveProperty.attrib["label"] drive["letter"] = xmlDriveProperty.attrib["letter"] drive["path"] = xmlDriveProperty.attrib["path"] drive["useLetter"] = xmlDriveProperty.attrib["useLetter"] except Exception as e: logging.warning( "Exception when parsing a drive policy XML file") logging.exception(e) continue if xmlDriveProperty.tag == "Filters": drive["filters"] = _parseXmlFilters(xmlDriveProperty) shareList.append(drive) shareList = _processFilters(shareList) logging.info("Found shares:") for drive in shareList: logging.info("* {:10}| {:5}| {:40}| {:5}".format( drive["label"], drive["letter"], drive["path"], drive["useLetter"])) for drive in shareList: if drive["useLetter"] == "1": shareName = f"{drive['label']} ({drive['letter']}:)" else: drive["label"] shares.mountShare(drive["path"], shareName=shareName) logging.info("==> Successfully parsed a drive policy! ==")