def create_rsa_ca(self, months=VALID): """ Create a self signed CA. """ # Wait a second to avoid an NSS bug with serial ids based on time. time.sleep(1) # Create noise. self._generate_noise('%s/noise.txt' % self._certdb) # Now run the command. Can we do this with NSS native? cmd = [ '/usr/bin/certutil', '-S', '-n', CA_NAME, '-s', ISSUER, '-x', '-g', '%s' % KEYBITS, '-t', 'CT,,', '-v', '%s' % months, '-2', '--keyUsage', 'certSigning', '-d', self._certdb, '-z', '%s/noise.txt' % self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT), ] cmd_input = b'y\n\n' # responses to certutil questions self.log.debug("nss cmd: %s", format_cmd_list(cmd)) result = ensure_str( run(cmd, check=True, stderr=PIPE, stdout=PIPE, input=cmd_input).stdout) self.log.debug("nss output: %s", result) # Now extract the CAcert to a well know place. # This allows us to point the cacert dir here and it "just works" cmd = [ '/usr/bin/certutil', '-L', '-n', CA_NAME, '-d', self._certdb, '-a', ] self.log.debug("nss cmd: %s", format_cmd_list(cmd)) try: certdetails = check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: raise ValueError(e.output.decode('utf-8').rstrip()) with open('%s/ca.crt' % self._certdb, 'w') as f: f.write(ensure_str(certdetails)) self.openssl_rehash(self._certdb) return True
def __getattr__(self, name): from lib389.utils import ensure_str if self._defaults_cached is False and self._islocal: self._read_defaults() self._validate_defaults() # Are we online? Is our key in the config map? if name in CONFIG_MAP and self._instance is not None and self._instance.state == DIRSRV_STATE_ONLINE: # Get the online value. (dn, attr) = CONFIG_MAP[name] ent = self._instance.getEntry(dn, attrlist=[ attr, ]) # If the server doesn't have it, fall back to our configuration. if attr is not None: v = ensure_str(ent.getValue(attr)) # Do we need to post-process the value? if name == 'version': # We need to post process this - it's 389-Directory/1.4.2.2.20191031git8166d8345 B2019.304.19 # but we need a string like: 1.4.2.2.20191031git8166d8345 v = v.split('/')[1].split()[0] return v # Else get from the config if self._serverid is not None: return ensure_str( self._config.get(SECTION, name).format(instance_name=self._serverid)) else: return ensure_str(self._config.get(SECTION, name))
def __init__(self, path, name, log): self.log = log self.log.debug(f"olDatabase path -> {path}") entries = ldif_parse(path, f'{name}.ldif') assert len(entries) == 1 self.config = entries.pop() self.log.debug(f"{self.config}") # olcSuffix, olcDbIndex, entryUUID self.suffix = ensure_str(self.config[1]['olcSuffix'][0]) self.idx = name.split('}', 1)[0].split('{', 1)[1] self.uuid = ensure_str(self.config[1]['entryUUID'][0]) self.index = [ tuple(ensure_str(x).split(' ')) for x in self.config[1]['olcDbIndex'] ] self.log.debug( f"settings -> {self.suffix}, {self.idx}, {self.uuid}, {self.index}" ) overlay_path = os.path.join(path, name) self.overlays = [] if os.path.isdir(overlay_path): self.overlays = [ olOverlay(overlay_path, x, log) for x in sorted(os.listdir(overlay_path)) ]
def __init__(self, instance, basedn, rdn=None): super(CosTemplates, self).__init__(instance) self._objectclasses = ['cosTemplate'] self._filterattrs = ['cn'] self._childobject = CosTemplate self._basedn = basedn if rdn is not None: self._basedn = '{},{}'.format(ensure_str(rdn), ensure_str(basedn))
def _validate(self, rdn, properties, basedn): """ Used to validate a create request. This way, it can be over-ridden without affecting the create types It also checks that all the values in _must_attribute exist in some form in the dictionary It has the useful trick of returning the dn, so subtypes can use extra properties to create the dn's here for this. """ if properties is None: raise ldap.UNWILLING_TO_PERFORM('Invalid request to create. Properties cannot be None') if type(properties) != dict: raise ldap.UNWILLING_TO_PERFORM("properties must be a dictionary") # I think this needs to be made case insensitive # How will this work with the dictionary? for attr in self._must_attributes: if properties.get(attr, None) is None: raise ldap.UNWILLING_TO_PERFORM('Attribute %s must not be None' % attr) # Make sure the naming attribute is present if properties.get(self._rdn_attribute, None) is None and rdn is None: raise ldap.UNWILLING_TO_PERFORM('Attribute %s must not be None or rdn provided' % self._rdn_attribute) # This change here, means we can pre-load a full dn to _dn, or we can # accept based on the rdn tdn = self._dn if tdn is None: if basedn is None: raise ldap.UNWILLING_TO_PERFORM('Invalid request to create. basedn cannot be None') if properties.get(self._rdn_attribute, None) is not None: # Favour the value in the properties dictionary v = properties.get(self._rdn_attribute) if isinstance(v, list): rdn = ensure_str(v[0]) else: rdn = ensure_str(v) tdn = '%s=%s,%s' % (self._rdn_attribute, rdn, basedn) # We may need to map over the data in the properties dict to satisfy python-ldap str_props = {} for k, v in properties.items(): if isinstance(v, list): # str_props[k] = map(lambda v1: ensure_bytes(v1), v) str_props[k] = ensure_list_bytes(v) else: str_props[k] = ensure_bytes(v) # # Do we need to do extra dn validation here? return (tdn, str_props)
def create_rsa_ca(self, months=VALID): """ Create a self signed CA. """ # Wait a second to avoid an NSS bug with serial ids based on time. time.sleep(1) # Create noise. self._generate_noise('%s/noise.txt' % self._certdb) # Now run the command. Can we do this with NSS native? cmd = [ '/usr/bin/certutil', '-S', '-n', CA_NAME, '-s', ISSUER, '-x', '-g', '%s' % KEYBITS, '-t', 'CT,,', '-v', '%s' % months, '--keyUsage', 'certSigning', '-d', self._certdb, '-z', '%s/noise.txt' % self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT), ] self.log.debug("nss cmd: %s", format_cmd_list(cmd)) result = ensure_str(check_output(cmd, stderr=subprocess.STDOUT)) self.log.debug("nss output: %s", result) # Now extract the CAcert to a well know place. # This allows us to point the cacert dir here and it "just works" cmd = [ '/usr/bin/certutil', '-L', '-n', CA_NAME, '-d', self._certdb, '-a', ] self.log.debug("nss cmd: %s", format_cmd_list(cmd)) certdetails = check_output(cmd, stderr=subprocess.STDOUT) with open('%s/ca.crt' % self._certdb, 'w') as f: f.write(ensure_str(certdetails)) cmd = ['/usr/bin/c_rehash', self._certdb] self.log.debug("nss cmd: %s", format_cmd_list(cmd)) check_output(cmd, stderr=subprocess.STDOUT) return True
def __getattr__(self, name): from lib389.utils import ensure_str if self._defaults_cached is False and self._islocal: self._read_defaults() self._validate_defaults() # Are we online? Is our key in the config map? while name in CONFIG_MAP and self._instance is not None and self._instance.state == DIRSRV_STATE_ONLINE: # Get the online value. err = None try: (dn, attr) = CONFIG_MAP[name] ent = self._instance.getEntry(dn, attrlist=[ attr, ]) except ldap.LDAPError as e: err = e if isinstance(err, ldap.NO_SUCH_OBJECT) and name in CONFIG_MAP2: try: (dn, attr) = CONFIG_MAP2[name] ent = self._instance.getEntry(dn, attrlist=[ attr, ]) err = None except ldap.LDAPError as e: err = e if isinstance(err, ldap.SERVER_DOWN): # Search in config. break if err is not None: raise _pretty_exception( err, f"while searching attribute {attr} in entry {dn} on server {self.serverid}" ) # If the server doesn't have it, fall back to our configuration. if attr is not None: v = ensure_str(ent.getValue(attr)) # Do we need to post-process the value? if name == 'version': # We need to post process this - it's 389-Directory/1.4.2.2.20191031git8166d8345 B2019.304.19 # but we need a string like: 1.4.2.2.20191031git8166d8345 v = v.split('/')[1].split()[0] return v # Else get from the config if self._config: if self._serverid is not None: return ensure_str( self._config.get( SECTION, name).format(instance_name=self._serverid)) else: return ensure_str(self._config.get(SECTION, name)) else: raise LookupError("""Invalid state No paths config (defaults.inf) could be found. This may be because the remote instance is offline, or your /etc/hosts is misconfigured for a local instance """)
def __init__(self, instance, basedn, rdn='ou=Groups'): super(Groups, self).__init__(instance) self._objectclasses = [ 'groupOfNames', ] self._filterattrs = [RDN] self._childobject = Group if rdn is None: self._basedn = ensure_str(basedn) else: self._basedn = '{},{}'.format(ensure_str(rdn), ensure_str(basedn))
def __init__(self, instance, basedn, rdn=None): super(CosIndirectDefinitions, self).__init__(instance) self._objectclasses = [ 'cosSuperDefinition', 'cosIndirectDefinition', ] self._filterattrs = ['cn'] self._childobject = CosIndirectDefinition self._basedn = basedn if rdn is not None: self._basedn = '{},{}'.format(ensure_str(rdn), ensure_str(basedn))
def _jsonify(self, fn, *args, **kwargs): # This needs to map all the values to ensure_str attrs = fn(*args, **kwargs) str_attrs = {} for k in attrs: str_attrs[ensure_str(k)] = ensure_list_str(attrs[k]) response = {"dn": ensure_str(self._dn), "attrs": str_attrs} print('json response') print(response) return response
def detect_alt_names(self, alt_names=[]): """Attempt to determine appropriate subject alternate names for a host. Returns the list of names we derive. :param alt_names: A list of alternate names. :type alt_names: list[str] :returns: list[str] """ if self.dirsrv and self.dirsrv.host not in alt_names: alt_names.append(ensure_str(self.dirsrv.host)) if len(alt_names) == 0: alt_names.append(ensure_str(socket.gethostname())) return alt_names
def _jsonify(self, fn, *args, **kwargs): # This needs to map all the values to ensure_str attrs = fn(use_json=True, *args, **kwargs) str_attrs = {} for k in attrs: str_attrs[ensure_str(k)] = ensure_list_str(attrs[k]) # ensure all the keys are lowercase str_attrs = dict((k.lower(), v) for k, v in list(str_attrs.items())) response = json.dumps({"type": "entry", "dn": ensure_str(self._dn), "attrs": str_attrs}, indent=4) return response
def _jsonify(self, fn, *args, **kwargs): # This needs to map all the values to ensure_str attrs = fn(*args, **kwargs) str_attrs = {} for k in attrs: str_attrs[ensure_str(k)] = ensure_list_str(attrs[k]) response = json.dumps({ "type": "entry", "dn": ensure_str(self._dn), "attrs": str_attrs }) return response
def _rsa_cert_list(self): cmd = [ '/usr/bin/certutil', '-L', '-d', self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT), ] try: result = ensure_str(check_output(cmd, stderr=subprocess.STDOUT)) except subprocess.CalledProcessError as e: raise ValueError(e.output.decode('utf-8').rstrip()) # We can skip the first few lines. They are junk # IE ['', # 'Certificate Nickname Trust Attributes', # ' SSL,S/MIME,JAR/XPI', # '', # 'Self-Signed-CA CTu,u,u', # ''] lines = result.split('\n')[4:-1] # Now make the lines usable cert_values = [] for line in lines: if line == '': continue if line == 'Database needs user init': # There are no certs, abort... return [] cert_values.append( re.match(r'^(.+[^\s])[\s]+([^\s]+)$', line.rstrip()).groups()) return cert_values
def __init__(self, path, name, log): self.log = log self.log.debug(f"olOverlay path -> {path}/{name}") entries = ldif_parse(path, name) assert len(entries) == 1 self.config = entries.pop() self.log.debug(f"{self.config}") # olcOverlay self.name = ensure_str(self.config[1]['olcOverlay'][0]).split('}', 1)[1] self.classes = ensure_list_str(self.config[1]['objectClass']) self.log.debug(f"{self.name} {self.classes}") if 'olcMemberOf' in self.classes: self.otype = olOverlayType.MEMBEROF # elif 'olcRefintConfig' in self.classes: self.otype = olOverlayType.REFINT # olcRefintAttribute self.attrs = ensure_list_str(self.config[1]['olcRefintAttribute']) elif 'olcUniqueConfig' in self.classes: self.otype = olOverlayType.UNIQUE # olcUniqueURI self.attrs = ensure_list_str([ # This is a ldap:///?uid?sub, so split ? [1] will give uid. attr.split('?')[1] for attr in ensure_list_str(self.config[1]['olcUniqueURI']) ]) else: self.otype = olOverlayType.UNKNOWN
def reinit(self): """ Re-init (create) the nss db. """ # 48886: The DB that DS ships with is .... well, broken. Purge it! for f in ('key3.db', 'cert8.db', 'key4.db', 'cert9.db', 'secmod.db', 'pkcs11.txt'): try: # Perhaps we should be backing these up instead ... os.remove("%s/%s" % (self._certdb, f )) except: pass try: os.makedirs(self._certdb) except FileExistsError: pass # In the future we may add the needed option to avoid writing the pin # files. # Write the pin.txt, and the pwdfile.txt if not os.path.exists('%s/%s' % (self._certdb, PIN_TXT)): with open('%s/%s' % (self._certdb, PIN_TXT), 'w') as f: f.write('Internal (Software) Token:%s' % self.dbpassword) if not os.path.exists('%s/%s' % (self._certdb, PWD_TXT)): with open('%s/%s' % (self._certdb, PWD_TXT), 'w') as f: f.write('%s' % self.dbpassword) # Init the db. # 48886; This needs to be sql format ... cmd = ['/usr/bin/certutil', '-N', '-d', self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT)] self._generate_noise('%s/noise.txt' % self._certdb) self.log.debug("nss cmd: %s" % cmd) result = ensure_str(check_output(cmd, stderr=subprocess.STDOUT)) self.log.debug("nss output: %s" % result) return True
def resume(self, agmtdn, interval=ALWAYS): """Resume a paused replication agreement, paused with the "pause" method. It tries to enabled the replica agreement. If it fails (not implemented in all versions) It uses the schedule() with interval '0000-2359 0123456'. :param agmtdn: agreement dn :type agmtdn: str :param interval: - 'HHMM-HHMM D+' With D=[0123456]+ - Agreement.ALWAYS - Agreement.NEVER - Default is NEVER :type interval: str :returns: None :raises: - ValueError - if interval is not valid - ldap.NO_SUCH_OBJECT - if agmtdn does not exist """ self.log.info("Resuming replication %s" % agmtdn) mod = [(ldap.MOD_REPLACE, 'nsds5ReplicaEnabled', [b'on'])] self.conn.modify_s(ensure_str(agmtdn), mod) # Allow a little time for the repl agmt thread to start time.sleep(2)
def changes(self, agmnt_dn): """Get a number of changes sent by this agreement. :param agmtdn: agreement dn :type agmtdn: str :returns: Number of changes :raises: NoSuchEntryError - if agreement entry with changes attribute is not found """ retval = 0 try: ent = self.conn.getEntry(ensure_str(agmnt_dn), ldap.SCOPE_BASE, "(objectclass=*)", [RA_PROPNAME_TO_ATTRNAME[RA_CHANGES]]) except: raise NoSuchEntryError("Error reading status from agreement", agmnt_dn) if ent.nsds5replicaChangesSentSinceStartup: val = ent.nsds5replicaChangesSentSinceStartup items = val.split(ensure_bytes(' ')) if len(items) == 1: retval = int(items[0]) else: for item in items: ary = item.split(ensure_bytes(":")) if ary and len(ary) > 1: retval = retval + int(ary[1].split( ensure_bytes("/"))[0]) return retval
def _rsa_cert_list(self): cmd = [ '/usr/bin/certutil', '-L', '-d', self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT), ] result = ensure_str(check_output(cmd, stderr=subprocess.STDOUT)) # We can skip the first few lines. They are junk # IE ['', # 'Certificate Nickname Trust Attributes', # ' SSL,S/MIME,JAR/XPI', # '', # 'Self-Signed-CA CTu,u,u', # ''] lines = result.split('\n')[4:-1] # Now make the lines usable cert_values = [] for line in lines: data = line.split() cert_values.append((data[0], data[1])) return cert_values
def pause(self, agmtdn, interval=NEVER): """Pause this replication agreement. This replication agreement will send no more changes. Use the resume() method to "unpause". It tries to disable the replica agreement. If it fails (not implemented in all version), It uses the schedule() with interval '2358-2359 0' :param agmtdn: agreement dn :type agmtdn: str :param interval: - 'HHMM-HHMM D+' With D=[0123456]+ - Agreement.ALWAYS - Agreement.NEVER - Default is NEVER :type interval: str :returns: None :raises: ValueError - if interval is not valid """ self.log.info("Pausing replication %s" % agmtdn) mod = [(ldap.MOD_REPLACE, 'nsds5ReplicaEnabled', [b'off'])] self.conn.modify_s(ensure_str(agmtdn), mod) # Allow a little time for repl agmt thread to stop time.sleep(5)
def __init__(self, entry, rawaci, verbose=False): """ """ self.verbose = verbose self.entry = entry self._rawaci = ensure_str(rawaci) self.acidata = self._parse_aci(self._rawaci)
def _run_ldclt(self, cmd): result = None self.log.debug("ldclt loadtest ...") self.log.debug(format_cmd_list(cmd)) try: result = ensure_str(subprocess.check_output(cmd)) # If verbose, capture / log the output. except subprocess.CalledProcessError as e: print(format_cmd_list(cmd)) print(result) raise (e) self.log.debug(result) # The output looks like: # ldclt[44308]: Average rate: 4017.60/thr (4017.60/sec), total: 40176 # ldclt[44308]: Number of samples achieved. Bye-bye... # ldclt[44308]: All threads are dead - exit. # ldclt[44308]: Global average rate: 40604.00/thr (4060.40/sec), total: 406040 # ldclt[44308]: Global number times "no activity" reports: never # ldclt[44308]: Global no error occurs during this session. # So we want the "global avg rate" per second. section = None for line in result.splitlines(): if 'Global average rate' in line: section = line.split('(')[1].split(')')[0].split('/')[0] return section
def _get_pw_policy(inst, targetdn, log, use_json=None): pwp_manager = PwPolicyManager(inst) policy_type = _get_policy_type(inst, targetdn) attr_list = pwp_manager.get_attr_list() if "global" in policy_type.lower(): targetdn = 'cn=config' attr_list.extend(['passwordIsGlobalPolicy', 'nsslapd-pwpolicy_local']) attrs = inst.config.get_attrs_vals_utf8(attr_list) else: policy = pwp_manager.get_pwpolicy_entry(targetdn) targetdn = policy.dn attrs = policy.get_attrs_vals_utf8(attr_list) if use_json: print(json.dumps({"type": "entry", "pwp_type": policy_type, "dn": ensure_str(targetdn), "attrs": attrs})) else: if "global" in policy_type.lower(): response = "Global Password Policy: cn=config\n------------------------------------\n" else: response = "Local {} Policy: {}\n------------------------------------\n".format(policy_type, targetdn) for key, value in list(attrs.items()): if len(value) == 0: value = "" else: value = value[0] response += "{}: {}\n".format(key, value) print(response)
def __init__(self, instance, basedn): super(UnsafeExtensibleObjects, self).__init__(instance) self._objectclasses = [ 'extensibleObject', ] self._filterattrs = ["cn"] self._childobject = UnsafeExtensibleObject self._basedn = ensure_str(basedn)
def rdn(self): """Get an object RDN :returns: RDN """ # How can we be sure this returns the primary one? return ensure_str(self.get_attr_val(self._rdn_attribute))
def reinit(self): """ Re-init (create) the nss db. """ # 48886: The DB that DS ships with is .... well, broken. Purge it! assert self.remove_db() try: os.makedirs(self._certdb) except FileExistsError: pass if self.dirsrv is None: # Write a README to let people know what this is readme_file = '%s/%s' % (self._certdb, 'README.txt') if not os.path.exists(readme_file): with open(readme_file, 'w') as f: f.write(""" SSCA - Simple Self-Signed Certificate Authority This is part of the 389 Directory Server project's lib389 toolkit. It creates a simple, standalone certificate authority for testing and development purposes. It's suitable for evaluation and testing purposes only. """) # In the future we may add the needed option to avoid writing the pin # files. # Write the pin.txt, and the pwdfile.txt prv_mask = os.umask(0o177) try: pin_file = '%s/%s' % (self._certdb, PIN_TXT) if not os.path.exists(pin_file): with open(pin_file, 'w') as f: f.write('Internal (Software) Token:%s' % self.dbpassword) pwd_text_file = '%s/%s' % (self._certdb, PWD_TXT) if not os.path.exists(pwd_text_file): with open(pwd_text_file, 'w') as f: f.write('%s' % self.dbpassword) finally: prv_mask = os.umask(prv_mask) # Init the db. # 48886; This needs to be sql format ... cmd = [ '/usr/bin/certutil', '-N', '-d', self._certdb, '-f', '%s/%s' % (self._certdb, PWD_TXT), '-@', '%s/%s' % (self._certdb, PWD_TXT) ] self._generate_noise('%s/noise.txt' % self._certdb) self.log.debug("nss cmd: %s", format_cmd_list(cmd)) try: result = ensure_str(check_output(cmd, stderr=subprocess.STDOUT)) except subprocess.CalledProcessError as e: raise ValueError(e.output.decode('utf-8').rstrip()) self.log.debug("nss output: %s", result) return True
def finalize_ldif_file(instance, ldif_file): # Make the file owned by dirsrv os.chmod(ldif_file, 0o644) if os.getuid() == 0: # root user - chown the ldif to the server user userid = ensure_str(instance.userid) uid = pwd.getpwnam(userid).pw_uid gid = grp.getgrnam(userid).gr_gid os.chown(ldif_file, uid, gid)
def test_status(topology): """Test that status is returned from agreement""" topology.supplier.log.info("\n\n###########\n## STATUS\n##########") ents = topology.supplier.agreement.list(suffix=SUFFIX) for ent in ents: ra_status = topology.supplier.agreement.status(ensure_str(ent.dn)) assert ra_status topology.supplier.log.info("Status of %s: %s" % (ent.dn, ra_status))
def __init__(self, instance, basedn, rdn=None): """The set of costemplates that exist for direct and indirect implementations. :param instance: A dirsrv instance :type instance: DirSrv :param basedn: The basedn of the templates :type basedn: str :param rdn: The rdn of the templates :type rdn: str """ super(CosTemplates, self).__init__(instance) self._objectclasses = ['cosTemplate'] self._filterattrs = ['cn'] self._childobject = CosTemplate self._basedn = basedn if rdn is not None: self._basedn = '{},{}'.format(ensure_str(rdn), ensure_str(basedn))
def _create(self, rdn=None, properties=None, basedn=None, ensure=False): """Internal implementation of create. This is used by ensure and create, to prevent code duplication. You should *never* call this method directly. """ assert (len(self._create_objectclasses) > 0) basedn = ensure_str(basedn) self._log.debug('Checking "%s" under %s : %s' % (rdn, basedn, properties)) # Add the objectClasses to the properties (dn, valid_props) = self._validate(rdn, properties, basedn) # Check if the entry exists or not? .add_s is going to error anyway ... self._log.debug('Validated dn %s : valid_props %s' % (dn, valid_props)) exists = False try: self._instance.search_ext_s(dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1, serverctrls=self._server_controls, clientctrls=self._client_controls) exists = True except ldap.NO_SUCH_OBJECT: pass if exists and ensure: # update properties self._log.debug('Exists %s' % dn) self._dn = dn # Now use replace_many to setup our values mods = [] for k, v in valid_props.items(): mods.append((ldap.MOD_REPLACE, k, v)) self._instance.modify_ext_s(self._dn, mods, serverctrls=self._server_controls, clientctrls=self._client_controls) elif exists and not ensure: # raise "already exists." raise ldap.ALREADY_EXISTS("Entry %s already exists" % dn) if not exists: self._log.debug('Creating %s' % dn) e = Entry(dn) e.update( {'objectclass': ensure_list_bytes(self._create_objectclasses)}) e.update(valid_props) # We rely on exceptions here to indicate failure to the parent. self._log.debug('Creating entry %s : %s' % (dn, e)) self._instance.add_ext_s(e, serverctrls=self._server_controls, clientctrls=self._client_controls) # If it worked, we need to fix our instance dn self._dn = dn return self
def __init__(self, entry, rawaci, verbose=False): """ Breaks down an aci attribute string from 389, into a dictionary of terms and values. These values can then be manipulated, and subsequently rebuilt into an aci string. """ self.verbose = verbose self.entry = entry self._rawaci = ensure_str(rawaci) self.acidata = self._parse_aci(self._rawaci)
def delete_all(self, benamebase): benamebase = ensure_str(benamebase) dn = "cn=index,cn=" + benamebase + "," + DN_LDBM # delete each defined index self.conn.delete_branch_s(dn, ldap.SCOPE_ONELEVEL) # Then delete the top index entry self.log.debug("Delete head index entry %s" % (dn)) self.conn.delete_s(dn)
def get_attr_val_utf8(self, key, use_json=False): """Get a single attribute value from the entry in utf8 type :param key: An attribute name :type key: str :returns: A single bytes value :raises: ValueError - if instance is offline """ return ensure_str(self.get_attr_val(key))
def complex_aci(topology): ACI_TARGET = ('(targetfilter ="(ou=groups)")(targetattr ="uniqueMember ' '|| member")') ACI_ALLOW = ('(version 3.0; acl "Allow test aci";allow (read, search, ' 'write)') ACI_SUBJECT = ('(userdn="ldap:///dc=example,dc=com??sub?(ou=engineering)" ' 'and userdn="ldap:///dc=example,dc=com??sub?(manager=uid=' 'wbrown,ou=managers,dc=example,dc=com) || ldap:///dc=examp' 'le,dc=com??sub?(manager=uid=tbrown,ou=managers,dc=exampl' 'e,dc=com)" );)') ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT gentry = Entry('cn=testgroup,%s' % DEFAULT_SUFFIX) gentry.setValues('objectclass', 'top', 'extensibleobject') gentry.setValues('cn', 'testgroup') gentry.setValues('aci', ACI_BODY) topology.standalone.add_s(gentry) return ensure_str(ACI_BODY)
def runInfProg(prog, content, verbose, prefix=None): """run a program that takes an .inf style file on stdin""" cmd = [prog] if verbose: cmd.append('-ddd') else: cmd.extend(['-l', '/dev/null']) cmd.extend(['-s', '-f', '-']) log.debug("running: %s " % cmd) if HASPOPEN: pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT) child_stdin = pipe.stdin child_stdout = pipe.stdout else: pipe = popen2.Popen4(cmd) child_stdin = pipe.tochild child_stdout = pipe.fromchild child_stdin.write(ensure_bytes(content)) child_stdin.close() if verbose: log.debug("PID %s" % pipe.pid) while pipe.poll() is None: (rr, wr, xr) = select.select([child_stdout], [], [], 1.0) if rr and len(rr) > 0: line = rr[0].readline() if not line: break if verbose: sys.stdout.write(ensure_str(line)) elif verbose: print("timed out waiting to read from pid %s : %s " % (pipe.pid, cmd)) child_stdout.close() exitCode = pipe.wait() # if verbose: log.debug("%s returned exit code %s" % (prog, exitCode)) return exitCode
def _install_ds(self, general, slapd, backends): """ Actually install the Ds from the dicts provided. You should never call this directly, as it bypasses assertions. """ # register the instance to /etc/sysconfig # We do this first so that we can trick remove-ds.pl if needed. # There may be a way to create this from template like the dse.ldif ... initconfig = "" with open("%s/dirsrv/config/template-initconfig" % slapd['sysconf_dir']) as template_init: for line in template_init.readlines(): initconfig += line.replace('{{', '{', 1).replace('}}', '}', 1).replace('-', '_') with open("%s/sysconfig/dirsrv-%s" % (slapd['sysconf_dir'], slapd['instance_name']), 'w') as f: f.write(initconfig.format( SERVER_DIR=slapd['lib_dir'], SERVERBIN_DIR=slapd['sbin_dir'], CONFIG_DIR=slapd['config_dir'], INST_DIR=slapd['inst_dir'], RUN_DIR=slapd['run_dir'], DS_ROOT='', PRODUCT_NAME='slapd', )) # Create all the needed paths # we should only need to make bak_dir, cert_dir, config_dir, db_dir, ldif_dir, lock_dir, log_dir, run_dir? schema_dir, for path in ('backup_dir', 'cert_dir', 'config_dir', 'db_dir', 'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'): if self.verbose: self.log.info("ACTION: creating %s" % slapd[path]) try: os.makedirs(slapd[path], mode=0o775) except OSError: pass os.chown(slapd[path], slapd['user_uid'], slapd['group_gid']) # Copy correct data to the paths. # Copy in the schema # This is a little fragile, make it better. # It won't matter when we move schema to usr anyway ... _ds_shutil_copytree(os.path.join(slapd['sysconf_dir'], 'dirsrv/schema'), slapd['schema_dir']) os.chown(slapd['schema_dir'], slapd['user_uid'], slapd['group_gid']) # Copy in the collation srcfile = os.path.join(slapd['sysconf_dir'], 'dirsrv/config/slapd-collations.conf') dstfile = os.path.join(slapd['config_dir'], 'slapd-collations.conf') shutil.copy2(srcfile, dstfile) os.chown(slapd['schema_dir'], slapd['user_uid'], slapd['group_gid']) # Selinux fixups? # Restorecon of paths? # Bind sockets to our type? # Create certdb in sysconfidir if self.verbose: self.log.info("ACTION: Creating certificate database is %s" % slapd['cert_dir']) # nss_create_new_database(slapd['cert_dir']) # Create dse.ldif with a temporary root password. # The template is in slapd['data_dir']/dirsrv/data/template-dse.ldif # Variables are done with %KEY%. # You could cheat and read it in, do a replace of % to { and } then use format? if self.verbose: self.log.info("ACTION: Creating dse.ldif") dse = "" with open(os.path.join(slapd['data_dir'], 'dirsrv', 'data', 'template-dse.ldif')) as template_dse: for line in template_dse.readlines(): dse += line.replace('%', '{', 1).replace('%', '}', 1) with open(os.path.join(slapd['config_dir'], 'dse.ldif'), 'w') as file_dse: file_dse.write(dse.format( schema_dir=slapd['schema_dir'], lock_dir=slapd['lock_dir'], tmp_dir=slapd['tmp_dir'], cert_dir=slapd['cert_dir'], ldif_dir=slapd['ldif_dir'], bak_dir=slapd['backup_dir'], run_dir=slapd['run_dir'], inst_dir="", log_dir=slapd['log_dir'], fqdn=general['full_machine_name'], ds_port=slapd['port'], ds_user=slapd['user'], rootdn=slapd['root_dn'], # ds_passwd=slapd['root_password'], ds_passwd=self._secure_password, # We set our own password here, so we can connect and mod. ds_suffix='', config_dir=slapd['config_dir'], db_dir=slapd['db_dir'], )) # open the connection to the instance. # Should I move this import? I think this prevents some recursion from lib389 import DirSrv ds_instance = DirSrv(self.verbose) ds_instance.containerised = self.containerised args = { SER_PORT: slapd['port'], SER_SERVERID_PROP: slapd['instance_name'], SER_ROOT_DN: slapd['root_dn'], SER_ROOT_PW: self._raw_secure_password, SER_DEPLOYED_DIR: slapd['prefix'] } ds_instance.allocate(args) # Does this work? assert(ds_instance.exists()) # Start the server ds_instance.start(timeout=60) ds_instance.open() # Create the backends as listed # Load example data if needed. for backend in backends: ds_instance.backends.create(properties=backend) # Make changes using the temp root # Change the root password finally # Complete. ds_instance.config.set('nsslapd-rootpw', ensure_str(slapd['root_password']))
def __unicode__(self): val = self._dn if self._rdn_attribute: # What if the rdn is multi value and we don't get the primary .... ARGHHH val = self.get_attr_val(self._rdn_attribute) return ensure_str(val)