def updateLdapContact(self, id, vals, cursor, uid, context): """update an existing contact with the data of OpenERP""" conn = self.connectToLdap(cursor, uid, context={}) try: old_contatc_obj = self.getLdapContact(conn, id) except ldap.NO_SUCH_OBJECT: self.saveLdapContact(id, vals, cursor, uid, context) return contact_obj = self.mappLdapObject(id, vals, cursor, uid, context) if conn.ACTIVDIR: modlist = [] for key, val in contact_obj.items(): if key in ('cn', 'uid', 'objectclass'): continue if isinstance(val, list): val = val[0] modlist.append((ldap.MOD_REPLACE, key, val)) else: modlist = ldap.modlist.modifyModlist(old_contatc_obj[1], contact_obj) try: conn.connexion.modify_s(old_contatc_obj[0], modlist) conn.connexion.unbind_s() except Exception: raise
def modify_attributes(self, dn, attributes, create=False): """ :param dn: new entry's full_dn :param attributes: attributes to be filled :param create: if create is False, the attributes will be MODIFIED, if it is true, they will be ADDED to the node :return: original ldap.modify_s returns query id, I think it's useless, therefore this method will return nothing """ if create: operation = ldap.MOD_ADD else: operation = ldap.MOD_REPLACE modlist = [] for k, v in attributes.iteritems(): if isinstance(v, list): raise (RuntimeError, "This will not work with list values") if v: modlist.append((operation, k, v)) log.debug("Modlist: %s" % modlist) try: log.debug('%s, %s' % (dn, type(dn))) self.connection.modify_s(dn, modlist) except ldap.TIMEOUT as ex: # Try once more, pass the exception to the caller if faled self.disconnect() self.connection = self.connect() self.connection.modify_s(dn, modlist) except ldap.INVALID_SYNTAX as ex: log.exception(ex) self.connection.modify_s(dn, modlist) log.debug("Modified attribute(s) of LDAP node {0}".format(dn))
def update(connection, base, data, scope=None, filter=None, attributes=None, partial=True): with helpers.ldap.SaslBindingContext( **binding_args(connection)) as context: old = search(context, base, scope, filter, attributes=None, behavior=SearchBehavior.EXPECT_ONE)[0] old_dn = old[RESULT_KEY_DN] new_dn = old_dn old_attrs = old[RESULT_KEY_ATTRIBUTES] new_attrs = validate_attributes(data) old_attrs_ci = CaseInsensitiveDict(old_attrs) new_attrs_ci = CaseInsensitiveDict(new_attrs) if len(new_attrs) != len(new_attrs_ci): raise helpers.errors.BadRequestException( 'Case collision in attribute keys') rdn_attr_key = old_dn.split(',')[0].split('=')[0] # check for rename if rdn_attr_key in old_attrs_ci and rdn_attr_key in new_attrs_ci: old_rdn = helpers.ad.format_attribute(rdn_attr_key, old_attrs_ci[rdn_attr_key]) new_rdn = helpers.ad.format_attribute(rdn_attr_key, new_attrs_ci[rdn_attr_key]) if old_rdn != new_rdn: new_rdn_formatted = '{}={}'.format(rdn_attr_key, new_rdn) new_dn = ','.join([ new_rdn_formatted if i == 0 else s for i, s in enumerate(old_dn.split(',')) ]) del old_attrs_ci[rdn_attr_key] del new_attrs_ci[rdn_attr_key] #print(new_dn) context.rename(old_dn, new_rdn_formatted) # build mod list - only delete attributes if not partial (patch) modlist = [] for k in list(new_attrs_ci) if partial else list(old_attrs_ci): if (not partial) and k in old_attrs_ci and k not in new_attrs_ci: # delete modlist.append((ldap.MOD_DELETE, k, None)) elif k not in old_attrs_ci or old_attrs_ci[k] != new_attrs_ci[k]: # update / replace modlist.append((ldap.MOD_REPLACE, k, new_attrs_ci[k])) #print(modlist) if len(modlist) > 0: context.modify(new_dn, modlist) return externalize( search(context, new_dn, scope=SCOPE_BASE, attributes=attributes, behavior=SearchBehavior.EXPECT_ONE, empty_results_error=ReloadAfterModError)[0])
def modUserGroup(self, uid, grupo, adddel): modlist = [] usuario = "uid=%s,ou=People,dc=gonzalonazareno,dc=org" % uid if adddel == "add": modlist.append((ldap.MOD_ADD, "member", usuario.encode("utf-8"))) elif adddel == "del": modlist.append( (ldap.MOD_DELETE, "member", usuario.encode("utf-8"))) else: return self.con.modify_s( "cn=%s,ou=Group,dc=gonzalonazareno,dc=org" % grupo, modlist)
def _get_modlist(self, data, modtype=ldap.MOD_REPLACE): modlist = [] for key in data.keys(): if modtype == ldap.MOD_DELETE: val = None else: val = data[key] if modtype == ldap.MOD_ADD: ntup = tuple([key, val]) else: ntup = tuple([modtype, key, val]) modlist.append(ntup) return modlist
def modify_group_members(self, group, uid_to_add = [], uid_to_delete = []): """Add and/or remove members from a group""" modlist = [] dn = "cn=%s,%s" % (group, self.__groups_ou) # Generate change list if uid_to_add != []: modlist.append((ldap.MOD_ADD, "memberUid", uid_to_add )) if uid_to_delete != []: modlist.append((ldap.MOD_DELETE, "memberUid", uid_to_delete)) self.__ldap.modify_s(dn, modlist)
def modify_obj(self, prop, prop_value, new, objectClass=None, throw_error=False): try: search_str = '({0}={1})'.format(prop, prop_value) if (objectClass != None): search_str = '(&{0}(objectClass={1}))'.format( search_str, objectClass) r = self.conn.search_s(LDAP_VIRTUE_DN, ldap.SCOPE_SUBTREE, \ search_str) if (len(r) != 1): # We only want to change it if there's no # possibility that we're referring to the wrong object. return 22 # Error EINVAL dn = r[0][0] curr = r[0][1] # modlist = ldap.modlist.modifyModlist( r[0][1], new ) modlist = [] for k in new: if (curr.get(k) == None and new.get(k) != None): modlist.append((0, k, new[k])) elif (curr.get(k) != None and new.get(k) != None and new[k] != curr[k]): modlist.append((2, k, new[k])) self.conn.modify_s(dn, modlist) return 0 # Success! except Exception as e: print("Error: {0}".format(e)) # Send error to calling function if indicated if (throw_error): raise e return None
def update(self): """ If self.dn exist, returns a callable that will update it. """ def _update(): self.connection.modify_s(self.dn, modlist) return modlist modlist = [] for (attr_name, attr_values) in self.attrs.items(): ldap_attr = LdapAttr(self.module, self.connection, self.dn, attr_name, attr_values) op = ldap_attr.update() if op: modlist.append(op) action = None if modlist: action = _update return action
def execute(*args, **kw): ask_questions = True if not conf.config_file == conf.defaults.config_file: ask_questions = False _input = {} if ask_questions: print >> sys.stderr, utils.multiline_message( _(""" Please supply a password for the LDAP administrator user 'admin', used to login to the graphical console of 389 Directory server. """) ) _input['admin_pass'] = utils.ask_question( _("Administrator password"), default=utils.generate_password(), password=True, confirm=True ) print >> sys.stderr, utils.multiline_message( _(""" Please supply a password for the LDAP Directory Manager user, which is the administrator user you will be using to at least initially log in to the Web Admin, and that Kolab uses to perform administrative tasks. """) ) _input['dirmgr_pass'] = utils.ask_question( _("Directory Manager password"), default=utils.generate_password(), password=True, confirm=True ) print >> sys.stderr, utils.multiline_message( _(""" Please choose the system user and group the service should use to run under. These should be existing, unprivileged, local system POSIX accounts with no shell. """) ) try: pw = pwd.getpwnam("dirsrv") except: _input['userid'] = utils.ask_question(_("User"), default="nobody") _input['group'] = utils.ask_question(_("Group"), default="nobody") else: _input['userid'] = utils.ask_question(_("User"), default="dirsrv") _input['group'] = utils.ask_question(_("Group"), default="dirsrv") else: _input['admin_pass'] = conf.get('ldap', 'bind_pw') _input['dirmgr_pass'] = conf.get('ldap', 'bind_pw') try: pw = pwd.getpwnam("dirsrv") except: _input['userid'] = "nobody" _input['group'] = "nobody" else: _input['userid'] = "dirsrv" _input['group'] = "dirsrv" # TODO: Verify the user and group exist. # TODO: This takes the system fqdn, domainname and hostname, rather then # the desired fqdn, domainname and hostname. # # TODO^2: This should be confirmed. if conf.fqdn: _input['fqdn'] = conf.fqdn _input['hostname'] = conf.fqdn.split('.')[0] _input['domain'] = '.'.join(conf.fqdn.split('.')[1:]) else: _input['fqdn'] = fqdn _input['hostname'] = hostname.split('.')[0] _input['domain'] = domainname _input['nodotdomain'] = _input['domain'].replace('.','_') _input['rootdn'] = utils.standard_root_dn(_input['domain']) if ask_questions: print >> sys.stderr, utils.multiline_message( _(""" This setup procedure plans to set up Kolab Groupware for the following domain name space. This domain name is obtained from the reverse DNS entry on your network interface. Please confirm this is the appropriate domain name space. """) ) answer = utils.ask_confirmation("%s" % (_input['domain'])) if not answer: positive_answer = False while not positive_answer: _input['domain'] = utils.ask_question(_("Domain name to use")) if not _input['domain'] == None and not _input['domain'] == "": positive_answer = True else: print >> sys.stderr, utils.multiline_message( _(""" Invalid input. Please try again. """) ) _input['nodotdomain'] = _input['domain'].replace('.','_') _input['rootdn'] = utils.standard_root_dn(_input['domain']) print >> sys.stderr, utils.multiline_message( _(""" The standard root dn we composed for you follows. Please confirm this is the root dn you wish to use. """) ) answer = utils.ask_confirmation("%s" % (_input['rootdn'])) if not answer: positive_answer = False while not positive_answer: _input['rootdn'] = utils.ask_question(_("Root DN to use")) if not _input['rootdn'] == None and not _input['rootdn'] == "": positive_answer = True else: print >> sys.stderr, utils.multiline_message( _(""" Invalid input. Please try again. """) ) # TODO: Loudly complain if the fqdn does not resolve back to this system. data = """ [General] FullMachineName = %(fqdn)s SuiteSpotUserID = %(userid)s SuiteSpotGroup = %(group)s AdminDomain = %(domain)s ConfigDirectoryLdapURL = ldap://%(fqdn)s:389/o=NetscapeRoot ConfigDirectoryAdminID = admin ConfigDirectoryAdminPwd = %(admin_pass)s [slapd] SlapdConfigForMC = Yes UseExistingMC = 0 ServerPort = 389 ServerIdentifier = %(hostname)s Suffix = %(rootdn)s RootDN = cn=Directory Manager RootDNPwd = %(dirmgr_pass)s ds_bename = %(nodotdomain)s AddSampleEntries = No [admin] Port = 9830 ServerAdminID = admin ServerAdminPwd = %(admin_pass)s """ % (_input) (fp, filename) = tempfile.mkstemp(dir="/tmp/") os.write(fp, data) os.close(fp) if os.path.isfile("/usr/sbin/setup-ds-admin.pl"): setup_ds_admin = "/usr/sbin/setup-ds-admin.pl" elif os.path.isfile("/usr/sbin/setup-ds"): setup_ds_admin = "/usr/sbin/setup-ds" else: log.error(_("No directory server setup tool available.")) command = [ setup_ds_admin, '--debug', '--silent', '--force', '--file=%s' % (filename) ] print >> sys.stderr, utils.multiline_message( _(""" Setup is now going to set up the 389 Directory Server. This may take a little while (during which period there is no output and no progress indication). """) ) log.info(_("Setting up 389 Directory Server")) setup_389 = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) (stdoutdata, stderrdata) = setup_389.communicate() # TODO: Get the return code and display output if not successful. log.debug(_("Setup DS stdout:"), level=8) log.debug(stdoutdata, level=8) log.debug(_("Setup DS stderr:"), level=8) log.debug(stderrdata, level=8) # TODO: Fails when ran a second time. # TODO: When fail, fail gracefully. # Find the kolab schema. It's installed as %doc in the kolab-schema package. # TODO: Chown nobody, nobody, chmod 440 schema_file = None for root, directories, filenames in os.walk('/usr/share/doc/'): for filename in filenames: if filename.startswith('kolab') and filename.endswith('.ldif') and schema_file == None: schema_file = os.path.join(root,filename) if not schema_file == None: try: shutil.copy( schema_file, '/etc/dirsrv/slapd-%s/schema/99%s' % ( _input['hostname'], os.path.basename(schema_file) ) ) schema_error = False except: log.error(_("Could not copy the LDAP extensions for Kolab")) schema_error = True else: log.error(_("Could not find the ldap Kolab schema file")) schema_error = True if os.path.isfile('/bin/systemctl'): subprocess.call(['/bin/systemctl', 'restart', 'dirsrv.target']) elif os.path.isfile('/sbin/service'): subprocess.call(['/sbin/service', 'dirsrv', 'restart']) elif os.path.isfile('/usr/sbin/service'): subprocess.call(['/usr/sbin/service','dirsrv','stop']) time.sleep(20) subprocess.call(['/usr/sbin/service','dirsrv','start']) else: log.error(_("Could not start the directory server service.")) if os.path.isfile('/bin/systemctl'): subprocess.call(['/bin/systemctl', 'enable', 'dirsrv.target']) elif os.path.isfile('/sbin/chkconfig'): subprocess.call(['/sbin/chkconfig', 'dirsrv', 'on']) elif os.path.isfile('/usr/sbin/update-rc.d'): subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv', 'defaults']) else: log.error(_("Could not configure to start on boot, the " + \ "directory server service.")) if ask_questions: print >> sys.stderr, utils.multiline_message( _(""" Please supply a Cyrus Administrator password. This password is used by Kolab to execute administrative tasks in Cyrus IMAP. You may also need the password yourself to troubleshoot Cyrus IMAP and/or perform other administrative tasks against Cyrus IMAP directly. """) ) _input['cyrus_admin_pass'] = utils.ask_question( _("Cyrus Administrator password"), default=utils.generate_password(), password=True, confirm=True ) print >> sys.stderr, utils.multiline_message( _(""" Please supply a Kolab Service account password. This account is used by various services such as Postfix, and Roundcube, as anonymous binds to the LDAP server will not be allowed. """) ) _input['kolab_service_pass'] = utils.ask_question( _("Kolab Service password"), default=utils.generate_password(), password=True, confirm=True ) else: _input['cyrus_admin_pass'] = conf.get('cyrus-imap', 'admin_password') _input['kolab_service_pass'] = conf.get('ldap', 'service_bind_pw') log.info(_("Writing out configuration to kolab.conf")) # Write out kolab configuration conf.command_set('kolab', 'primary_domain', _input['domain']) conf.command_set('ldap', 'base_dn', _input['rootdn']) conf.command_set('ldap', 'bind_dn', 'cn=Directory Manager') conf.command_set('ldap', 'bind_pw', _input['dirmgr_pass']) conf.command_set('ldap', 'service_bind_dn', 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn'])) conf.command_set('ldap', 'service_bind_pw', _input['kolab_service_pass']) fp = open(conf.defaults.config_file, "w+") conf.cfg_parser.write(fp) fp.close() log.info(_("Inserting service users into LDAP.")) # Insert service users auth = Auth(_input['domain']) auth.connect() auth._auth.connect() auth._auth._bind() dn = 'uid=%s,ou=Special Users,%s' % (conf.get('cyrus-imap', 'admin_login'), _input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top','person','inetorgperson','organizationalperson'] attrs['uid'] = conf.get('cyrus-imap', 'admin_login') attrs['givenname'] = "Cyrus" attrs['surname'] = "Administrator" attrs['cn'] = "Cyrus Administrator" attrs['userPassword'] = _input['cyrus_admin_pass'] # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) conf.command_set('cyrus-imap', 'admin_password', _input['cyrus_admin_pass']) dn = 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top','person','inetorgperson','organizationalperson'] attrs['uid'] = "kolab-service" attrs['givenname'] = "Kolab" attrs['surname'] = "Service" attrs['cn'] = "Kolab Service" attrs['userPassword'] = _input['kolab_service_pass'] attrs['nslookthroughlimit'] = '-1' attrs['nssizelimit'] = '-1' attrs['nstimelimit'] = '-1' attrs['nsidletimeout'] = '-1' # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) dn = 'ou=Resources,%s' % (_input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top','organizationalunit'] attrs['ou'] = "Resources" # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) dn = 'ou=Shared Folders,%s' % (_input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top','organizationalunit'] attrs['ou'] = "Shared Folders" # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) log.info(_("Writing out cn=kolab,cn=config")) dn = 'cn=kolab,cn=config' # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top','extensibleobject'] attrs['cn'] = "kolab" # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) auth._auth.set_entry_attribute( dn, 'aci', '(targetattr = "*") (version 3.0;acl "Kolab Services";allow (read,compare,search)(userdn = "ldap:///%s");)' % ('uid=kolab-service,ou=Special Users,%s' % (_input['rootdn'])) ) # TODO: Add kolab-admin role # TODO: Assign kolab-admin admin ACLs log.info(_("Adding domain %s to list of domains for this deployment") % (_input['domain'])) dn = "associateddomain=%s,cn=kolab,cn=config" % (_input['domain']) attrs = {} attrs['objectclass'] = ['top','domainrelatedobject'] attrs['associateddomain'] = '%s' % (_input['domain']) attrs['aci'] = '(targetattr = "*") (version 3.0;acl "Read Access for %(domain)s Users";allow (read,compare,search)(userdn = "ldap:///%(rootdn)s??sub?(objectclass=*)");)' % (_input) # Add inetdomainbasedn in case the configured root dn is not the same as the # standard root dn for the domain name configured if not _input['rootdn'] == utils.standard_root_dn(_input['domain']): attrs['objectclass'].append('inetdomain') attrs['inetdomainbasedn'] = _input['rootdn'] ldif = ldap.modlist.addModlist(attrs) auth._auth.ldap.add_s(dn, ldif) if not conf.anonymous: log.info(_("Disabling anonymous binds")) dn = "cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "nsslapd-allow-anonymous-access", "off")) auth._auth.ldap.modify_s(dn, modlist) # TODO: Ensure the uid attribute is unique # TODO^2: Consider renaming the general "attribute uniqueness to "uid attribute uniqueness" log.info(_("Enabling attribute uniqueness plugin")) dn = "cn=attribute uniqueness,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on")) auth._auth.ldap.modify_s(dn, modlist) log.info(_("Enabling referential integrity plugin")) dn = "cn=referential integrity postoperation,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on")) auth._auth.ldap.modify_s(dn, modlist) log.info(_("Enabling and configuring account policy plugin")) dn = "cn=Account Policy Plugin,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on")) modlist.append((ldap.MOD_ADD, "nsslapd-pluginarg0", "cn=config,cn=Account Policy Plugin,cn=plugins,cn=config")) auth._auth.ldap.modify_s(dn, modlist) dn = "cn=config,cn=Account Policy Plugin,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "alwaysrecordlogin", "yes")) modlist.append((ldap.MOD_ADD, "stateattrname", "lastLoginTime")) modlist.append((ldap.MOD_ADD, "altstateattrname", "createTimestamp")) auth._auth.ldap.modify_s(dn, modlist) # TODO: Add kolab-admin role log.info(_("Adding the kolab-admin role")) dn = "cn=kolab-admin,%s" % (_input['rootdn']) attrs = {} attrs['description'] = "Kolab Administrator" attrs['objectClass'] = ['top','ldapsubentry','nsroledefinition','nssimpleroledefinition','nsmanagedroledefinition'] attrs['cn'] = "kolab-admin" ldif = ldap.modlist.addModlist(attrs) auth._auth.ldap.add_s(dn, ldif) # TODO: User writeable attributes on root_dn log.info(_("Setting access control to %s") % (_input['rootdn'])) dn = _input['rootdn'] aci = [] if not schema_error: aci.append('(targetattr = "homePhone || preferredDeliveryMethod || jpegPhoto || postalAddress || carLicense || userPassword || mobile || displayName || description || labeledURI || homePostalAddress || postOfficeBox || registeredAddress || postalCode || photo || title || street || pager || o || l || initials || telephoneNumber || preferredLanguage || facsimileTelephoneNumber") (version 3.0;acl "Enable self write for common attributes";allow (read,compare,search,write)(userdn = "ldap:///self");)') else: aci.append('(targetattr = "homePhone || preferredDeliveryMethod || jpegPhoto || postalAddress || carLicense || userPassword || mobile || kolabAllowSMTPRecipient || displayName || kolabDelegate || description || labeledURI || homePostalAddress || postOfficeBox || registeredAddress || postalCode || photo || title || street || kolabInvitationPolicy || pager || o || l || initials || kolabAllowSMTPSender || telephoneNumber || preferredLanguage || facsimileTelephoneNumber") (version 3.0;acl "Enable self write for common attributes";allow (read,compare,search,write)(userdn = "ldap:///self");)') aci.append('(targetattr = "*") (version 3.0;acl "Directory Administrators Group";allow (all)(groupdn = "ldap:///cn=Directory Administrators,%(rootdn)s" or roledn = "ldap:///cn=kolab-admin,%(rootdn)s");)' % (_input)) aci.append('(targetattr="*")(version 3.0; acl "Configuration Administrators Group"; allow (all) groupdn="ldap:///cn=Configuration Administrators,ou=Groups,ou=TopologyManagement,o=NetscapeRoot";)') aci.append('(targetattr="*")(version 3.0; acl "Configuration Administrator"; allow (all) userdn="ldap:///uid=admin,ou=Administrators,ou=TopologyManagement,o=NetscapeRoot";)') aci.append('(targetattr = "*")(version 3.0; acl "SIE Group"; allow (all) groupdn = "ldap:///cn=slapd-%(hostname)s,cn=389 Directory Server,cn=Server Group,cn=%(fqdn)s,ou=%(domain)s,o=NetscapeRoot";)' %(_input)) aci.append('(targetattr = "*") (version 3.0;acl "Search Access";allow (read,compare,search)(userdn = "ldap:///all");)') modlist = [] modlist.append((ldap.MOD_REPLACE, "aci", aci)) auth._auth.ldap.modify_s(dn, modlist) if os.path.isfile('/bin/systemctl'): subprocess.call(['/bin/systemctl', 'enable', 'dirsrv-admin.service']) elif os.path.isfile('/sbin/chkconfig'): subprocess.call(['/sbin/chkconfig', 'dirsrv-admin', 'on']) elif os.path.isfile('/usr/sbin/update-rc.d'): subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv-admin', 'defaults']) else: log.error(_("Could not start and configure to start on boot, the " + \ "directory server admin service."))
def save(self): '''Method to create or modify the LDAP object in Active Directory If adOBJ is a New object then create LDAP object in Active Directory If adOBJ is not a new object then modify LDAP object in Active Directory ''' modlist = [] attrs = self.__dict__.copy() del attrs['adldap'] del attrs['adcomplete'] isNew = attrs.get('is_new',False) try: del attrs['is_new'] except: pass # if attrs.get('dn',None).value == None: # raise self.adldap.NotDNDefinied("Not DN Definied") if (attrs.get('cn',None).value == None) or (attrs.get('container',None).value == None): raise self.adldap.NotDNDefinied("CN and/or CONTAINER field can not be None") if not isNew: #is modify action if attrs['dn'].__dict__.get('is_modified',False): raise self.adldap.ForbidChangeDN("Can not change DN field. You must use CN and/or CONTAINER attribute. Remove field.") cn = False cnt = False if attrs['cn'].__dict__.get('is_modified',False): cn = attrs['cn'].value del attrs['cn'] if attrs['container'].__dict__.get('is_modified',False): cnt = attrs['container'].value del attrs['container'] for attr in attrs: modtype= ldap.MOD_REPLACE if attrs[attr].__dict__.get('is_modified',False): if attrs.get(attr,None) == None: modtype = ldap.MOD_DELETE modlist.append((modtype,attr,attrs[attr].raw)) if (attr.lower() == 'unicodepwd'): #Two times is needed for update password in AD modlist.append((modtype,attr,attrs[attr].raw)) if len(modlist) > 0: self.adldap.ldapConnection.modify_s(self.dn.value,modlist) if cn: self.adldap.ldapConnection.modrdn_s(self.dn.value,'cn='+str(cn),True) newdn = 'cn='+str(cn)+','+','.join(self.dn.value.split(',')[1:]) self.dn = newdn del self.dn.is_modified del self.cn.is_modified if cnt: self.adldap.ldapConnection.rename_s(self.dn.value,'cn='+self.cn.value, cnt) newdn = 'cn='+self.cn.value+','+cnt self.dn = newdn del self.dn.is_modified del self.container.is_modified else: cnt = attrs['container'].value del attrs['container'] add = {} try: if (self.is_enable) and (self.__dict__.get("unicodePwd",None) == None): raise Exception("Not set Password to new enable object") except self.adldap.ObjectNotHaveEnable: pass for attr in attrs: if (attr in self.newobj) and (attrs[attr].value == None): raise self.adldap.EmptyAttrNewObj("Empty attributes for new Object "+str(self.newobj)) if attrs[attr].value != None: add[attr] = attrs[attr].value addlist= ldap.modlist.addModlist(add) dn = 'CN='+attrs['cn'].value+','+cnt self.adldap.ldapConnection.add_s(dn,addlist)
def s_edit(self, parent_ou, new_data: dict={}): """Server side edition of user's information on LDAP (only if modified) Args: new_data (dict): List of properties to change. Default is `{}`. """ modlist = [] if new_data.get('login'): modlist.append(get_modify_item('samAccountName', self.login, new_data.get('login'))) modlist.append(get_modify_item('userPrincipalName', f"{self.login.decode('utf-8')}@{cm().ldap.domain}".encode('utf-8'), new_data.get('login') + f"@{cm().ldap.domain}" )) if new_data.get('description') is not None: if new_data.get('description') == "": # Empty description modlist.append((ldap.MOD_DELETE, 'description', None)) else: modlist.append(get_modify_item('description', self.description, new_data.get('description'))) if new_data.get('display_name'): modlist.append(get_modify_item('displayName', self.display_name, new_data.get('display_name'))) if new_data.get('password'): # Reset password password = new_data.get('password') modlist.append(get_modify_item('unicodePwd', None, f'"{password}"', encoding="utf-16-le" )) modlist = list(filter(None.__ne__, modlist)) # remove empty changes logger.info(f"There is {len(modlist)} changes to make on the user object.") if len(modlist) > 0: logger.trivia(modlist) con = get_ldap_connect() try: con.modify_s(self.base, modlist) logger.info(f"User {self.login} is edited.") except Exception as e: logger.error(f"Cannot edit user {self.login}: {str(e)}") return "500: Server side issue on editing user." else: logger.debug("Nothing to edit.") return get_user_in_ou(parent_ou, new_data.get('login'), as_dict=True)
def main(): usage = "usage: %prog [options]" parser = optparse.OptionParser(usage=usage, description=__doc__) parser.add_option( "-f", "--filter", help= "resync objects from master found by this filter. Default: (uid=<hostname>$)" ) parser.add_option("-r", "--remove", action="store_true", help="remove objects in local database before resync") parser.add_option("-s", "--simulate", action="store_true", help="dry run, do not remove or add") parser.add_option("-u", "--update", action="store_true", help="update/modify existing objects") opts, args = parser.parse_args() ucr = univention.config_registry.ConfigRegistry() ucr.load() base = ucr.get("ldap/base") binddn = "cn=update,%s" % base with open("/etc/ldap/rootpw.conf", "r") as fh: for line in fh: line = line.strip() if line.startswith('rootpw '): bindpw = line[7:].strip('"') break else: exit(1) if not opts.filter: opts.filter = '(uid=%s$)' % ucr['hostname'] # get local and master connection local = uldap.access(binddn=binddn, bindpw=bindpw, start_tls=0, host="localhost", port=389) if ucr.get("server/role", "") == "domaincontroller_backup": master = uldap.getAdminConnection() else: master = uldap.getMachineConnection(ldap_master=True) # delete local if opts.remove: res = local.search(base=base, filter=opts.filter) for dn, data in res: print("remove from local: %s" % (dn, )) if not opts.simulate: local.delete(dn) # resync from master res = master.search(base=base, filter=opts.filter) for dn, data in res: print("resync from master: %s" % (dn, )) local_res = local.search(base=dn) if not local_res or not opts.update: print(' ==> adding object') if not opts.simulate: local.add(dn, ldap.modlist.addModlist(data)) else: modlist = [] local_data = local_res[0][1] for key in set(data.keys()) | set(local_data.keys()): if local_data.get(key, []) != data.get(key, []): modlist.append( [key, local_data.get(key, []), data.get(key, [])]) if not modlist: print(' ==> no change') else: print(' ==> modifying object') if not opts.simulate: local.modify(dn, modlist)
def execute(*args, **kw): ask_questions = True if not conf.config_file == conf.defaults.config_file: ask_questions = False if conf.without_ldap: print >> sys.stderr, _("Skipping setup of LDAP, as specified") return _input = {} if conf.with_openldap and not conf.with_ad: conf.command_set('ldap', 'unique_attribute', 'entryuuid') fp = open(conf.defaults.config_file, "w+") conf.cfg_parser.write(fp) fp.close() return elif conf.with_ad and not conf.with_openldap: conf.command_set('ldap', 'auth_attributes', 'samaccountname') conf.command_set('ldap', 'modifytimestamp_format', '%%Y%%m%%d%%H%%M%%S.0Z') conf.command_set('ldap', 'unique_attribute', 'userprincipalname') # TODO: These attributes need to be checked conf.command_set('ldap', 'mail_attributes', 'mail') conf.command_set('ldap', 'mailserver_attributes', 'mailhost') conf.command_set('ldap', 'quota_attribute', 'mailquota') return elif conf.with_ad and conf.with_openldap: print >> sys.stderr, utils.multiline_message( _(""" You can not configure Kolab to run against OpenLDAP and Active Directory simultaneously. """)) sys.exit(1) # Pre-execution checks for path, directories, files in os.walk('/etc/dirsrv/'): for direct in directories: if direct.startswith('slapd-'): print >> sys.stderr, utils.multiline_message( _(""" It seems 389 Directory Server has an existing instance configured. This setup script does not intend to destroy or overwrite your data. Please make sure /etc/dirsrv/ and /var/lib/dirsrv/ are clean so that this setup does not have to worry. """)) sys.exit(1) _input = {} if ask_questions: print >> sys.stderr, utils.multiline_message( _(""" Please supply a password for the LDAP administrator user 'admin', used to login to the graphical console of 389 Directory server. """)) _input['admin_pass'] = utils.ask_question( _("Administrator password"), default=utils.generate_password(), password=True, confirm=True) if conf.directory_manager_pwd is not None: _input['dirmgr_pass'] = conf.directory_manager_pwd else: print >> sys.stderr, utils.multiline_message( _(""" Please supply a password for the LDAP Directory Manager user, which is the administrator user you will be using to at least initially log in to the Web Admin, and that Kolab uses to perform administrative tasks. """)) _input['dirmgr_pass'] = utils.ask_question( _("Directory Manager password"), default=utils.generate_password(), password=True, confirm=True) print >> sys.stderr, utils.multiline_message( _(""" Please choose the system user and group the service should use to run under. These should be existing, unprivileged, local system POSIX accounts with no shell. """)) try: pw = pwd.getpwnam("dirsrv") except: _input['userid'] = utils.ask_question(_("User"), default="nobody") _input['group'] = utils.ask_question(_("Group"), default="nobody") else: _input['userid'] = utils.ask_question(_("User"), default="dirsrv") _input['group'] = utils.ask_question(_("Group"), default="dirsrv") else: _input['admin_pass'] = conf.get('ldap', 'bind_pw') _input['dirmgr_pass'] = conf.get('ldap', 'bind_pw') try: pw = pwd.getpwnam("dirsrv") except: _input['userid'] = "nobody" _input['group'] = "nobody" else: _input['userid'] = "dirsrv" _input['group'] = "dirsrv" # TODO: Verify the user and group exist. # TODO: This takes the system fqdn, domainname and hostname, rather then # the desired fqdn, domainname and hostname. # # TODO^2: This should be confirmed. if conf.fqdn: _input['fqdn'] = conf.fqdn _input['hostname'] = conf.fqdn.split('.')[0] _input['domain'] = '.'.join(conf.fqdn.split('.')[1:]) else: _input['fqdn'] = fqdn _input['hostname'] = hostname.split('.')[0] _input['domain'] = domainname _input['nodotdomain'] = _input['domain'].replace('.', '_') _input['rootdn'] = utils.standard_root_dn(_input['domain']) if ask_questions: print >> sys.stderr, utils.multiline_message( _(""" This setup procedure plans to set up Kolab Groupware for the following domain name space. This domain name is obtained from the reverse DNS entry on your network interface. Please confirm this is the appropriate domain name space. """)) answer = utils.ask_confirmation("%s" % (_input['domain'])) if not answer: positive_answer = False while not positive_answer: _input['domain'] = utils.ask_question(_("Domain name to use")) if not _input['domain'] == None and not _input['domain'] == "": positive_answer = True else: print >> sys.stderr, utils.multiline_message( _(""" Invalid input. Please try again. """)) _input['nodotdomain'] = _input['domain'].replace('.', '_') _input['rootdn'] = utils.standard_root_dn(_input['domain']) print >> sys.stderr, utils.multiline_message( _(""" The standard root dn we composed for you follows. Please confirm this is the root dn you wish to use. """)) answer = utils.ask_confirmation("%s" % (_input['rootdn'])) if not answer: positive_answer = False while not positive_answer: _input['rootdn'] = utils.ask_question(_("Root DN to use")) if not _input['rootdn'] == None and not _input['rootdn'] == "": positive_answer = True else: print >> sys.stderr, utils.multiline_message( _(""" Invalid input. Please try again. """)) # TODO: Loudly complain if the fqdn does not resolve back to this system. data = """ [General] FullMachineName = %(fqdn)s SuiteSpotUserID = %(userid)s SuiteSpotGroup = %(group)s AdminDomain = %(domain)s ConfigDirectoryLdapURL = ldap://%(fqdn)s:389/o=NetscapeRoot ConfigDirectoryAdminID = admin ConfigDirectoryAdminPwd = %(admin_pass)s [slapd] SlapdConfigForMC = Yes UseExistingMC = 0 ServerPort = 389 ServerIdentifier = %(hostname)s Suffix = %(rootdn)s RootDN = cn=Directory Manager RootDNPwd = %(dirmgr_pass)s ds_bename = %(nodotdomain)s AddSampleEntries = No [admin] Port = 9830 ServerAdminID = admin ServerAdminPwd = %(admin_pass)s """ % (_input) (fp, filename) = tempfile.mkstemp(dir="/tmp/") os.write(fp, data) os.close(fp) if os.path.isfile("/usr/sbin/setup-ds-admin.pl"): setup_ds_admin = "/usr/sbin/setup-ds-admin.pl" #elif os.path.isfile("/usr/sbin/setup-ds-admin"): #setup_ds_admin = "/usr/sbin/setup-ds-admin" elif os.path.isfile("/usr/sbin/setup-ds.pl"): setup_ds_admin = "/usr/sbin/setup-ds.pl" elif os.path.isfile("/usr/sbin/setup-ds"): setup_ds_admin = "/usr/sbin/setup-ds" else: log.error(_("No directory server setup tool available.")) sys.exit(1) command = [ setup_ds_admin, '--debug', '--silent', '--force', '--file=%s' % (filename) ] print >> sys.stderr, utils.multiline_message( _(""" Setup is now going to set up the 389 Directory Server. This may take a little while (during which period there is no output and no progress indication). """)) log.info(_("Setting up 389 Directory Server")) setup_389 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdoutdata, stderrdata) = setup_389.communicate() if not setup_389.returncode == 0: print >> sys.stderr, utils.multiline_message( _(""" An error was detected in the setup procedure for 389 Directory Server. This setup will write out stderr and stdout to /var/log/kolab/setup.error.log and /var/log/kolab/setup.out.log respectively, before it exits. """)) fp = open('/var/log/kolab/setup.error.log', 'w') fp.write(stderrdata) fp.close() fp = open('/var/log/kolab/setup.out.log', 'w') fp.write(stdoutdata) fp.close() log.debug(_("Setup DS stdout:"), level=8) log.debug(stdoutdata, level=8) log.debug(_("Setup DS stderr:"), level=8) log.debug(stderrdata, level=8) if not setup_389.returncode == 0: sys.exit(1) # Find the kolab schema. It's installed as %doc in the kolab-schema package. # TODO: Chown nobody, nobody, chmod 440 schema_file = None for root, directories, filenames in os.walk('/usr/share/doc/'): for filename in filenames: if filename.startswith('kolab') and filename.endswith( '.ldif') and schema_file == None: schema_file = os.path.join(root, filename) if not schema_file == None: try: shutil.copy( schema_file, '/etc/dirsrv/slapd-%s/schema/99%s' % (_input['hostname'], os.path.basename(schema_file))) schema_error = False except: log.error(_("Could not copy the LDAP extensions for Kolab")) schema_error = True else: log.error(_("Could not find the ldap Kolab schema file")) schema_error = True if os.path.isfile('/bin/systemctl'): subprocess.call(['/bin/systemctl', 'restart', 'dirsrv.target']) time.sleep(20) elif os.path.isfile('/sbin/service'): subprocess.call(['/sbin/service', 'dirsrv', 'restart']) elif os.path.isfile('/usr/sbin/service'): subprocess.call(['/usr/sbin/service', 'dirsrv', 'stop']) time.sleep(20) subprocess.call(['/usr/sbin/service', 'dirsrv', 'start']) else: log.error(_("Could not start the directory server service.")) if os.path.isfile('/bin/systemctl'): subprocess.call(['/bin/systemctl', 'enable', 'dirsrv.target']) elif os.path.isfile('/sbin/chkconfig'): subprocess.call(['/sbin/chkconfig', 'dirsrv', 'on']) elif os.path.isfile('/usr/sbin/update-rc.d'): subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv', 'defaults']) else: log.error(_("Could not configure to start on boot, the " + \ "directory server service.")) if ask_questions: print >> sys.stderr, utils.multiline_message( _(""" Please supply a Cyrus Administrator password. This password is used by Kolab to execute administrative tasks in Cyrus IMAP. You may also need the password yourself to troubleshoot Cyrus IMAP and/or perform other administrative tasks against Cyrus IMAP directly. """)) _input['cyrus_admin_pass'] = utils.ask_question( _("Cyrus Administrator password"), default=utils.generate_password(), password=True, confirm=True) print >> sys.stderr, utils.multiline_message( _(""" Please supply a Kolab Service account password. This account is used by various services such as Postfix, and Roundcube, as anonymous binds to the LDAP server will not be allowed. """)) _input['kolab_service_pass'] = utils.ask_question( _("Kolab Service password"), default=utils.generate_password(), password=True, confirm=True) else: _input['cyrus_admin_pass'] = conf.get('cyrus-imap', 'admin_password') _input['kolab_service_pass'] = conf.get('ldap', 'service_bind_pw') log.info(_("Writing out configuration to kolab.conf")) # Write out kolab configuration conf.command_set('kolab', 'primary_domain', _input['domain']) conf.command_set('ldap', 'base_dn', _input['rootdn']) conf.command_set('ldap', 'bind_dn', 'cn=Directory Manager') conf.command_set('ldap', 'bind_pw', _input['dirmgr_pass']) conf.command_set( 'ldap', 'service_bind_dn', 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn'])) conf.command_set('ldap', 'service_bind_pw', _input['kolab_service_pass']) fp = open(conf.defaults.config_file, "w+") conf.cfg_parser.write(fp) fp.close() log.info(_("Inserting service users into LDAP.")) # Insert service users auth = Auth(_input['domain']) auth.connect() auth._auth.connect() auth._auth._bind(bind_dn='cn=Directory Manager', bind_pw=_input['dirmgr_pass']) dn = 'uid=%s,ou=Special Users,%s' % (conf.get( 'cyrus-imap', 'admin_login'), _input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = [ 'top', 'person', 'inetorgperson', 'organizationalperson' ] attrs['uid'] = conf.get('cyrus-imap', 'admin_login') attrs['givenname'] = "Cyrus" attrs['surname'] = "Administrator" attrs['cn'] = "Cyrus Administrator" attrs['userPassword'] = _input['cyrus_admin_pass'] # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) conf.command_set('cyrus-imap', 'admin_password', _input['cyrus_admin_pass']) dn = 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = [ 'top', 'person', 'inetorgperson', 'organizationalperson' ] attrs['uid'] = "kolab-service" attrs['givenname'] = "Kolab" attrs['surname'] = "Service" attrs['cn'] = "Kolab Service" attrs['userPassword'] = _input['kolab_service_pass'] attrs['nslookthroughlimit'] = '-1' attrs['nssizelimit'] = '-1' attrs['nstimelimit'] = '-1' attrs['nsidletimeout'] = '-1' # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) dn = 'ou=Resources,%s' % (_input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top', 'organizationalunit'] attrs['ou'] = "Resources" # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) dn = 'ou=Shared Folders,%s' % (_input['rootdn']) # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top', 'organizationalunit'] attrs['ou'] = "Shared Folders" # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) log.info(_("Writing out cn=kolab,cn=config")) dn = 'cn=kolab,cn=config' # A dict to help build the "body" of the object attrs = {} attrs['objectclass'] = ['top', 'extensibleobject'] attrs['cn'] = "kolab" attrs[ 'aci'] = '(targetattr = "*") (version 3.0;acl "Kolab Services";allow (read,compare,search)(userdn = "ldap:///uid=kolab-service,ou=Special Users,%s");)' % ( _input['rootdn']) # Convert our dict to nice syntax for the add-function using modlist-module ldif = ldap.modlist.addModlist(attrs) # Do the actual synchronous add-operation to the ldapserver auth._auth.ldap.add_s(dn, ldif) log.info( _("Adding domain %s to list of domains for this deployment") % (_input['domain'])) dn = "associateddomain=%s,cn=kolab,cn=config" % (_input['domain']) attrs = {} attrs['objectclass'] = ['top', 'domainrelatedobject'] attrs['associateddomain'] = [ '%s' % (_input['domain']), '%s' % (_input['fqdn']), 'localhost.localdomain', 'localhost' ] # De-duplicate attribute values before attempting to insert the object (#2205) attrs['associateddomain'] = list(set(attrs['associateddomain'])) attrs['associateddomain'].pop(attrs['associateddomain'].index( _input['domain'])) attrs['associateddomain'] = [_input['domain']] + attrs['associateddomain'] attrs[ 'aci'] = '(targetattr = "*") (version 3.0;acl "Read Access for %(domain)s Users";allow (read,compare,search)(userdn = "ldap:///%(rootdn)s??sub?(objectclass=*)");)' % ( _input) # Add inetdomainbasedn in case the configured root dn is not the same as the # standard root dn for the domain name configured if not _input['rootdn'] == utils.standard_root_dn(_input['domain']): attrs['objectclass'].append('inetdomain') attrs['inetdomainbasedn'] = _input['rootdn'] ldif = ldap.modlist.addModlist(attrs) auth._auth.ldap.add_s(dn, ldif) if not conf.anonymous: log.info(_("Disabling anonymous binds")) dn = "cn=config" modlist = [] modlist.append( (ldap.MOD_REPLACE, "nsslapd-allow-anonymous-access", "off")) auth._auth.ldap.modify_s(dn, modlist) # TODO: Ensure the uid attribute is unique # TODO^2: Consider renaming the general "attribute uniqueness to "uid attribute uniqueness" log.info(_("Enabling attribute uniqueness plugin")) dn = "cn=attribute uniqueness,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on")) auth._auth.ldap.modify_s(dn, modlist) log.info(_("Enabling referential integrity plugin")) dn = "cn=referential integrity postoperation,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on")) auth._auth.ldap.modify_s(dn, modlist) log.info(_("Enabling and configuring account policy plugin")) dn = "cn=Account Policy Plugin,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on")) modlist.append((ldap.MOD_ADD, "nsslapd-pluginarg0", "cn=config,cn=Account Policy Plugin,cn=plugins,cn=config")) auth._auth.ldap.modify_s(dn, modlist) dn = "cn=config,cn=Account Policy Plugin,cn=plugins,cn=config" modlist = [] modlist.append((ldap.MOD_REPLACE, "alwaysrecordlogin", "yes")) modlist.append((ldap.MOD_ADD, "stateattrname", "lastLoginTime")) modlist.append((ldap.MOD_ADD, "altstateattrname", "createTimestamp")) auth._auth.ldap.modify_s(dn, modlist) # Add kolab-admin role log.info(_("Adding the kolab-admin role")) dn = "cn=kolab-admin,%s" % (_input['rootdn']) attrs = {} attrs['description'] = "Kolab Administrator" attrs['objectClass'] = [ 'top', 'ldapsubentry', 'nsroledefinition', 'nssimpleroledefinition', 'nsmanagedroledefinition' ] attrs['cn'] = "kolab-admin" ldif = ldap.modlist.addModlist(attrs) auth._auth.ldap.add_s(dn, ldif) # User writeable attributes on root_dn log.info(_("Setting access control to %s") % (_input['rootdn'])) dn = _input['rootdn'] aci = [] if schema_error: aci.append( '(targetattr = "carLicense || description || displayName || facsimileTelephoneNumber || homePhone || homePostalAddress || initials || jpegPhoto || l || labeledURI || mobile || o || pager || photo || postOfficeBox || postalAddress || postalCode || preferredDeliveryMethod || preferredLanguage || registeredAddress || roomNumber || secretary || seeAlso || st || street || telephoneNumber || telexNumber || title || userCertificate || userPassword || userSMIMECertificate || x500UniqueIdentifier") (version 3.0; acl "Enable self write for common attributes"; allow (read,compare,search,write)(userdn = "ldap:///self");)' ) else: aci.append( '(targetattr = "carLicense || description || displayName || facsimileTelephoneNumber || homePhone || homePostalAddress || initials || jpegPhoto || l || labeledURI || mobile || o || pager || photo || postOfficeBox || postalAddress || postalCode || preferredDeliveryMethod || preferredLanguage || registeredAddress || roomNumber || secretary || seeAlso || st || street || telephoneNumber || telexNumber || title || userCertificate || userPassword || userSMIMECertificate || x500UniqueIdentifier || kolabDelegate || kolabInvitationPolicy || kolabAllowSMTPSender") (version 3.0; acl "Enable self write for common attributes"; allow (read,compare,search,write)(userdn = "ldap:///self");)' ) aci.append( '(targetattr = "*") (version 3.0;acl "Directory Administrators Group";allow (all)(groupdn = "ldap:///cn=Directory Administrators,%(rootdn)s" or roledn = "ldap:///cn=kolab-admin,%(rootdn)s");)' % (_input)) aci.append( '(targetattr="*")(version 3.0; acl "Configuration Administrators Group"; allow (all) groupdn="ldap:///cn=Configuration Administrators,ou=Groups,ou=TopologyManagement,o=NetscapeRoot";)' ) aci.append( '(targetattr="*")(version 3.0; acl "Configuration Administrator"; allow (all) userdn="ldap:///uid=admin,ou=Administrators,ou=TopologyManagement,o=NetscapeRoot";)' ) aci.append( '(targetattr = "*")(version 3.0; acl "SIE Group"; allow (all) groupdn = "ldap:///cn=slapd-%(hostname)s,cn=389 Directory Server,cn=Server Group,cn=%(fqdn)s,ou=%(domain)s,o=NetscapeRoot";)' % (_input)) aci.append( '(targetattr != "userPassword") (version 3.0;acl "Search Access";allow (read,compare,search)(userdn = "ldap:///all");)' ) modlist = [] modlist.append((ldap.MOD_REPLACE, "aci", aci)) auth._auth.ldap.modify_s(dn, modlist) if os.path.isfile('/bin/systemctl'): if not os.path.isfile('/usr/lib/systemd/system/dirsrv-admin.service'): log.info(_("directory server admin service not available")) else: subprocess.call( ['/bin/systemctl', 'enable', 'dirsrv-admin.service']) elif os.path.isfile('/sbin/chkconfig'): subprocess.call(['/sbin/chkconfig', 'dirsrv-admin', 'on']) elif os.path.isfile('/usr/sbin/update-rc.d'): subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv-admin', 'defaults']) else: log.error(_("Could not start and configure to start on boot, the " + \ "directory server admin service."))
def main(): usage = "usage: %prog [options]" parser = optparse.OptionParser(usage=usage, description=__doc__) parser.add_option( "-f", "--filter", help= "resync objects from master found by this filter. Default: (uid=<hostname>$)" ) parser.add_option("-r", "--remove", action="store_true", help="remove objects in local database before resync") parser.add_option("-s", "--simulate", action="store_true", help="dry run, do not remove or add") parser.add_option("-u", "--update", action="store_true", help="update/modify existing objects") opts, args = parser.parse_args() ucr = univention.config_registry.ConfigRegistry() ucr.load() base = ucr.get("ldap/base") server_role = ucr.get("server/role", "") if server_role == 'domaincontroller_master': print('local ldap is master server, nothing todo') return if server_role not in [ 'domaincontroller_backup', 'domaincontroller_slave' ]: print( 'server role ("{}") has no ldap, nothing todo'.format(server_role)) return if not opts.filter: opts.filter = '(uid=%s$)' % ucr['hostname'] # get local and master connection local = uldap.getRootDnConnection() if server_role == "domaincontroller_backup": master = uldap.getAdminConnection() else: master = uldap.getMachineConnection(ldap_master=True) # delete local if opts.remove: res = local.search(base=base, filter=opts.filter) if not res: print('object does not exist local') for dn, data in res: print("remove from local: %s" % (dn, )) if not opts.simulate: local.delete(dn) # resync from master res = master.search(base=base, filter=opts.filter) if not res: print('object does not exist on master') for dn, data in res: print("resync from master: %s" % (dn, )) try: local_res = local.search(base=dn) except ldap.NO_SUCH_OBJECT: local_res = None if local_res and opts.remove and opts.simulate: local_res = None if not local_res and not opts.update: print(' ==> adding object') if not opts.simulate: local.add(dn, ldap.modlist.addModlist(data)) elif not local_res and opts.update: print(' ==> object does not exist, can not update') elif local_res and opts.update: modlist = [] local_data = local_res[0][1] for key in set(data.keys()) | set(local_data.keys()): if set(local_data.get(key, [])).symmetric_difference( set(data.get(key, []))): modlist.append( [key, local_data.get(key, []), data.get(key, [])]) if not modlist: print(' ==> no change') else: print(' ==> modifying object') if not opts.simulate: local.modify(dn, modlist) elif local_res and not opts.update: print(' ==> object does exist, can not create')