def _reloadSamba(): logger.notice(u" Reloading samba") try: execute(u'service {name} reload'.format(name=getSambaServiceName(default="smbd"))) except Exception as error: logger.warning(error)
def getImageInformation(imagePath): """ Read information from a WIM file at `imagePath`. This method acts as a generator that yields information for each image in the file as a `dict`. The keys in the dict are all lowercase. Every dict has at least the key 'name'. """ if not os.path.exists(imagePath): raise OSError(u"File {0!r} not found!".format(imagePath)) try: imagex = which('wimlib-imagex') except Exception as error: LOGGER.logException(error) LOGGER.warning("Unable to find 'wimlib-imagex': {0}".format(error)) LOGGER.warning("Please install 'wimtools'.") raise RuntimeError("Unable to find 'wimlib-imagex': {0}".format(error)) imageinfo = {} for line in execute("{imagex} info '{file}'".format(imagex=imagex, file=imagePath)): if line and ':' in line: key, value = line.split(':', 1) key = key.strip().lower() value = value.strip() if key == 'languages': langs = value if ' ' in langs: langs = langs.split(' ') elif ',' in langs: langs = langs.split(',') else: langs = [langs] languages = set() for lang in langs: if lang.strip(): languages.add(lang.strip()) value = languages imageinfo[key] = value elif not line and imageinfo: if 'name' in imageinfo: # Do not return file information. LOGGER.debug("Collected information {0!r}".format(imageinfo)) yield imageinfo imageinfo = {}
def isSamba4(): """ Check if the current system uses samba 4. :return: True if running Samba 4. False otherwise. :rtype: bool """ samba4 = False try: smbd = which('smbd') result = execute('%s -V 2>/dev/null' % smbd) for line in result: if line.lower().startswith("version"): samba4 = line.split()[1].startswith('4') except Exception as error: logger.debug('Getting Samba Version failed due to: {0}', error) return samba4
def _runPackageScript(self, scriptName, env={}): logger.info(u"Attempt to run package script {0!r}", scriptName) try: if not self.packageControlFile: raise ValueError(u"Metadata not present") if not self.clientDataDir: raise ValueError(u"Client data dir not set") script = os.path.join(self.tmpUnpackDir, u'OPSI', scriptName) if not os.path.exists(script): logger.info(u"Package script '%s' not found" % scriptName) return [] logger.notice(u"Running package script '%s'" % scriptName) os.chmod(script, 0o700) os.putenv('PRODUCT_ID', self.packageControlFile.getProduct().getId()) os.putenv('PRODUCT_TYPE', self.packageControlFile.getProduct().getType()) os.putenv('PRODUCT_VERSION', self.packageControlFile.getProduct().getProductVersion()) os.putenv('PACKAGE_VERSION', self.packageControlFile.getProduct().getPackageVersion()) os.putenv('CLIENT_DATA_DIR', self.getProductClientDataDir()) for (k, v) in env.items(): os.putenv(k, v) return execute(script, timeout=PACKAGE_SCRIPT_TIMEOUT) except Exception as error: logger.logException(error, LOG_ERROR) self.cleanup() raise RuntimeError( u"Failed to execute package script '%s' of package '%s': %s" % (scriptName, self.packageFile, error)) finally: logger.debug( u"Finished running package script {0!r}".format(scriptName))
def check_signature(bin_dir): logger.info("check_signature is called") if not RUNNING_ON_WINDOWS: return # Not yet implemented windowsVersion = sys.getwindowsversion() # pylint: disable=no-member if windowsVersion.major < 6 or (windowsVersion.major == 6 and windowsVersion.minor < 4): return # Get-AuthenticodeSignature is only defined for versions since 2016 binary_list = [ os.path.join(bin_dir, "opsiclientd.exe"), os.path.join(bin_dir, "opsiclientd_rpc.exe"), os.path.join(bin_dir, "action_processor_starter.exe") ] for binary in binary_list: cmd = f'powershell.exe -ExecutionPolicy Bypass -Command \"(Get-AuthenticodeSignature \'{binary}\').Status -eq \'Valid\'\"' result = execute(cmd, captureStderr=True, waitForEnding=True, timeout=20) logger.debug(result) if not "True" in result: raise ValueError(f"Invalid Signature of file {binary}") logger.notice("Successfully verified %s", binary_list)
def createCertificate(path=None, config=None): """ Creates a certificate. Will overwrite any certificate that may exists in ``path``. .. versionchanged:: 4.0.6.2 Incrementing previously set serial number on re-creation. For new certificates a random number will be generated. :param path: The path of the certificate. \ If this is `None` the default will be used. :type path: str :param config: The configuration of the certificate. \ If not given will use a default. :type config: dict :raises CertificateCreationError: If errors exist in configuration. """ try: which("ucr") LOGGER.notice(u"Don't use certificate creation method on UCS-Systems") return except Exception: pass if path is None: path = OPSICONFD_CERTFILE if config is None: certparams = DEFAULT_CERTIFICATE_PARAMETERS else: certparams = config try: certparams["expires"] = forceInt(certparams["expires"]) except Exception: raise CertificateCreationError( u"No valid expiration date given. Must be an integer." ) if certparams["commonName"] != forceHostId(getfqdn()): raise CertificateCreationError( u"commonName must be the FQDN of the local server" ) LOGGER.notice(u"Creating new opsiconfd cert") LOGGER.notice(u"Generating new key pair") k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 2048) LOGGER.notice(u"Generating new self-signed cert") cert = crypto.X509() cert.get_subject().C = certparams['country'] cert.get_subject().ST = certparams['state'] cert.get_subject().L = certparams['locality'] cert.get_subject().O = certparams['organization'] cert.get_subject().CN = certparams['commonName'] try: if certparams['organizationalUnit']: cert.get_subject().OU = certparams['organizationalUnit'] else: del certparams['organizationalUnit'] except KeyError: pass try: if certparams['emailAddress']: cert.get_subject().emailAddress = certparams['emailAddress'] else: del certparams['emailAddress'] except KeyError: pass LOGGER.notice("Generating new Serialnumber") # As described in RFC5280 this value is required and must be a # positive and unique integer. # Source: http://tools.ietf.org/html/rfc5280#page-19 # # We currently do not have the ability to make the serial unique # but we assume that this is called only once in 2-3 years. # If we have an old serial number present we increment it by 1. # If we do not have an old serial number we create a random one. try: serialNumber = int(certparams['serialNumber']) + 1 except (KeyError, ValueError): LOGGER.debug(u"Reading in the existing serial number failed.") LOGGER.info(u"Creating new random serial number.") serialNumber = random.randint(0, pow(2, 16)) cert.set_serial_number(serialNumber) LOGGER.notice( u"Setting new expiration date (%d years)" % certparams["expires"] ) cert.gmtime_adj_notBefore(0) cert.gmtime_adj_notAfter(certparams["expires"] * 365 * 24 * 60 * 60) LOGGER.notice(u"Filling certificate with new data") cert.set_issuer(cert.get_subject()) cert.set_pubkey(k) cert.set_version(2) LOGGER.notice(u"Signing Certificate") cert.sign(k, str('sha512')) certcontext = "".join( ( crypto.dump_certificate(crypto.FILETYPE_PEM, cert), crypto.dump_privatekey(crypto.FILETYPE_PEM, k) ) ) LOGGER.notice(u"Beginning to write certificate.") with open(path, "wt") as certfile: certfile.write(certcontext) with NamedTemporaryFile(mode="wt") as randfile: LOGGER.notice(u"Generating and filling new randomize string") randomBytes = os.urandom(512) randfile.write(randomBytes) execute( u"{command} dhparam -rand {tempfile} 512 >> {target}".format( command=which("openssl"), tempfile=randfile.name, target=path ) ) LOGGER.notice(u'Certificate creation done.')
def configureDHCPD(configFile=DHCPD_CONF): """ Configure the configuration file for DHCPD. If any changes are made the original file will be backed up. The backup file has a timestamp appended to the filename. :param configFile: The configuration file for DHCP. """ if not os.path.exists(configFile): logger.warning("Can't find an dhcpd.conf. Aborting configuration.") return sysConfig = getNetworkConfiguration() logger.notice(u"Configuring dhcpd") dhcpdConf = DHCPDConfFile(configFile) dhcpdConf.parse() confChanged = False if dhcpdConf.getGlobalBlock().getParameters_hash().get( 'use-host-decl-names', False): logger.info(u" use-host-decl-names already enabled") else: confChanged = True logger.notice(u" enabling use-host-decl-names") dhcpdConf.getGlobalBlock().addComponent( DHCPDConf_Parameter(startLine=-1, parentBlock=dhcpdConf.getGlobalBlock(), key='use-host-decl-names', value=True)) subnets = dhcpdConf.getGlobalBlock().getBlocks('subnet', recursive=True) if not subnets: confChanged = True logger.notice(u" No subnets found, adding subnet") dhcpdConf.getGlobalBlock().addComponent( DHCPDConf_Block(startLine=-1, parentBlock=dhcpdConf.getGlobalBlock(), type='subnet', settings=[ 'subnet', sysConfig['subnet'], 'netmask', sysConfig['netmask'] ])) for subnet in dhcpdConf.getGlobalBlock().getBlocks('subnet', recursive=True): logger.info(u" Found subnet %s/%s" % (subnet.settings[1], subnet.settings[3])) groups = subnet.getBlocks('group') if not groups: confChanged = True logger.notice(u" No groups found, adding group") subnet.addComponent( DHCPDConf_Block(startLine=-1, parentBlock=subnet, type='group', settings=['group'])) for group in subnet.getBlocks('group'): logger.info(u" Configuring group") params = group.getParameters_hash(inherit='global') if params.get('next-server'): logger.info(u" next-server already set") else: confChanged = True group.addComponent( DHCPDConf_Parameter(startLine=-1, parentBlock=group, key='next-server', value=sysConfig['ipAddress'])) logger.notice(u" next-server set to %s" % sysConfig['ipAddress']) if params.get('filename'): logger.info(u" filename already set") else: confChanged = True filename = 'linux/pxelinux.0' if isSLES() or isOpenSUSE(): filename = 'opsi/pxelinux.0' group.addComponent( DHCPDConf_Parameter(startLine=-1, parentBlock=group, key='filename', value=filename)) logger.notice(u" filename set to %s" % filename) restartCommand = getDHCPDRestartCommand( default=u'/etc/init.d/dhcp3-server restart') if confChanged: logger.notice(u" Creating backup of %s" % configFile) shutil.copy(configFile, configFile + u'.' + time.strftime("%Y-%m-%d_%H:%M")) logger.notice(u" Writing new %s" % configFile) dhcpdConf.generate() logger.notice(u" Restarting dhcpd") try: execute(restartCommand) except Exception as error: logger.warning(error) logger.notice(u"Configuring sudoers") patchSudoersFileToAllowRestartingDHCPD(restartCommand) opsiconfdUid = pwd.getpwnam(OPSICONFD_USER)[2] adminGroupGid = grp.getgrnam(ADMIN_GROUP)[2] os.chown(configFile, opsiconfdUid, adminGroupGid) os.chmod(configFile, 0o664) if isRHEL() or isCentOS(): dhcpDir = os.path.dirname(configFile) if dhcpDir == '/etc': return logger.notice( 'Detected Red Hat-family system. Providing rights on "{dir}" ' 'to group "{group}"'.format(dir=dhcpDir, group=ADMIN_GROUP)) os.chown(dhcpDir, -1, adminGroupGid) backendConfigFile = os.path.join('/etc', 'opsi', 'backends', 'dhcpd.conf') logger.notice('Configuring backend file {0}'.format(backendConfigFile)) insertDHCPDRestartCommand(backendConfigFile, restartCommand)