def init(self): # Check to see that this 'existing' LDAP backend in fact exists ldapi_db = Ldb(self.ldapi_uri) ldapi_db.search(base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)") # For now, assume existing backends at least emulate OpenLDAP self.ldap_backend_type = "openldap"
def init(self): from samba.provision import ProvisioningError # we will shortly start slapd with ldapi for final provisioning. first # check with ldapsearch -> rootDSE via self.ldap_uri if another # instance of slapd is already running try: ldapi_db = Ldb(self.ldap_uri) ldapi_db.search(base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)") try: f = open(self.slapd_pid, "r") except IOError as err: if err != errno.ENOENT: raise else: try: p = f.read() finally: f.close() self.logger.info("Check for slapd process with PID: %s and terminate it manually." % p) raise SlapdAlreadyRunning(self.ldap_uri) except LdbError: # XXX: We should never be catching all Ldb errors pass # Try to print helpful messages when the user has not specified the # path to slapd if self.slapd_path is None: raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!") if not os.path.exists(self.slapd_path): self.logger.warning("Path (%s) to slapd does not exist!", self.slapd_path) if not os.path.isdir(self.ldapdir): os.makedirs(self.ldapdir, 0o700) # Put the LDIF of the schema into a database so we can search on # it to generate schema-dependent configurations in Fedora DS and # OpenLDAP schemadb_path = os.path.join(self.ldapdir, "schema-tmp.ldb") try: os.unlink(schemadb_path) except OSError: pass self.schema.write_to_tmp_ldb(schemadb_path) self.credentials = Credentials() self.credentials.guess(self.lp) # Kerberos to an ldapi:// backend makes no sense (we also force EXTERNAL) self.credentials.set_kerberos_state(DONT_USE_KERBEROS) self.credentials.set_username("samba-admin") self.credentials.set_password(self.ldapadminpass) self.credentials.set_forced_sasl_mech("EXTERNAL") self.provision()
def start(self): from samba.provision import ProvisioningError self.slapd_command_escaped = "\'" + "\' \'".join( self.slapd_command) + "\'" ldap_backend_script = os.path.join(self.ldapdir, "ldap_backend_startup.sh") f = open(ldap_backend_script, 'w') try: f.write("#!/bin/sh\n" + self.slapd_command_escaped + " $@\n") finally: f.close() os.chmod(ldap_backend_script, 0o755) # Now start the slapd, so we can provision onto it. We keep the # subprocess context around, to kill this off at the successful # end of the script self.slapd = subprocess.Popen( self.slapd_provision_command, close_fds=True, shell=False) count = 0 while self.slapd.poll() is None: # Wait until the socket appears try: time.sleep(1) ldapi_db = Ldb( self.ldap_uri, lp=self.lp, credentials=self.credentials) ldapi_db.search( base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)") # If we have got here, then we must have a valid connection to # the LDAP server! return except LdbError: count = count + 1 if count > 15: self.logger.error( "Could not connect to slapd started with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'") raise ProvisioningError( "slapd never accepted a connection within 15 seconds of starting" ) self.logger.error("Could not start slapd with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'") raise ProvisioningError( "slapd died before we could make a connection to it")
def autenticacion(creds, lp): """ Cumple con la idea de inyección, así que debería ser testeable """ try: ldap_conn = Ldb('ldap://localhost', lp=lp, credentials=creds) domain_dn = ldap_conn.get_default_basedn() search_filter='sAMAccountName={0}'.format(creds.get_username()) # NOTA: No intentes usar searchone para este caso específico. Dn resulta ser una clase no iterable busqueda = ldap_conn.search(base=domain_dn, scope=SCOPE_SUBTREE, expression=search_filter, attrs=['dn', 'memberOf', 'displayName']) user_dn = busqueda[0].dn sesion = user_session(ldap_conn, lp_ctx=lp, dn=user_dn, session_info_flags=session_info_flags) # Este punto podría ser importante para la idea de login token = sesion.security_token except LdbError as e: log.warning("Error LDB: %s" % e) return False; except IndexError as e: log.warning("El usuario %s no existe" % creds.get_username()) return False; except Exception as e: log.warning("Error no contemplado %s " % e) return False; return busqueda
def delta_update_basesamdb(refsampath, sampath, creds, session, lp, message): """Update the provision container db: sam.ldb This function is aimed for alpha9 and newer; :param refsampath: Path to the samdb in the reference provision :param sampath: Path to the samdb in the upgraded provision :param creds: Credential used for openning LDB files :param session: Session to use for openning LDB files :param lp: A loadparam object :return: A msg_diff object with the difference between the @ATTRIBUTES of the current provision and the reference provision """ message(SIMPLE, "Update base samdb by searching difference with reference one") refsam = Ldb(refsampath, session_info=session, credentials=creds, lp=lp, options=["modules:"]) sam = Ldb(sampath, session_info=session, credentials=creds, lp=lp, options=["modules:"]) empty = ldb.Message() deltaattr = None reference = refsam.search(expression="") for refentry in reference: entry = sam.search(expression="distinguishedName=%s" % refentry["dn"], scope=SCOPE_SUBTREE) if not len(entry): delta = sam.msg_diff(empty, refentry) message(CHANGE, "Adding %s to sam db" % str(refentry.dn)) if str(refentry.dn) == "@PROVISION" and\ delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE): delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE) delta.dn = refentry.dn sam.add(delta) else: delta = sam.msg_diff(entry[0], refentry) if str(refentry.dn) == "@ATTRIBUTES": deltaattr = sam.msg_diff(refentry, entry[0]) if str(refentry.dn) == "@PROVISION" and\ delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE): delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE) if len(delta.items()) > 1: delta.dn = refentry.dn sam.modify(delta) return deltaattr
def newuser(lp, creds, username=None): """extend user record with OpenChange settings. :param lp: Loadparm context :param creds: Credentials context :param username: Name of user to extend """ names = guess_names_from_smbconf(lp, None, None) db = Ldb(url=get_ldb_url(lp, creds, names), session_info=system_session(), credentials=creds, lp=lp) user_dn = get_user_dn(db, "CN=Users,%s" % names.domaindn, username) if user_dn: extended_user = """ dn: %(user_dn)s changetype: modify add: mailNickName mailNickname: %(username)s add: homeMDB homeMDB: CN=Mailbox Store (%(netbiosname)s),CN=First Storage Group,CN=InformationStore,CN=%(netbiosname)s,CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=%(firstorg)s,CN=Microsoft Exchange,CN=Services,CN=Configuration,%(domaindn)s add: homeMTA homeMTA: CN=Mailbox Store (%(netbiosname)s),CN=First Storage Group,CN=InformationStore,CN=%(netbiosname)s,CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=%(firstorg)s,CN=Microsoft Exchange,CN=Services,CN=Configuration,%(domaindn)s add: legacyExchangeDN legacyExchangeDN: /o=%(firstorg)s/ou=First Administrative Group/cn=Recipients/cn=%(username)s add: proxyAddresses proxyAddresses: =EX:/o=%(firstorg)s/ou=First Administrative Group/cn=Recipients/cn=%(username)s proxyAddresses: smtp:postmaster@%(dnsdomain)s proxyAddresses: X400:c=US;a= ;p=First Organizati;o=Exchange;s=%(username)s proxyAddresses: SMTP:%(username)s@%(dnsdomain)s replace: msExchUserAccountControl msExchUserAccountControl: 0 """ ldif_value = extended_user % {"user_dn": user_dn, "username": username, "netbiosname": names.netbiosname, "firstorg": names.firstorg, "domaindn": names.domaindn, "dnsdomain": names.dnsdomain} db.modify_ldif(ldif_value) res = db.search(base=user_dn, scope=SCOPE_BASE, attrs=["*"]) if len(res) == 1: record = res[0] else: raise Exception, \ "this should never happen as we just modified the record..." record_keys = map(lambda x: x.lower(), record.keys()) if "displayname" not in record_keys: extended_user = "******" % (user_dn, username) db.modify_ldif(extended_user) if "mail" not in record_keys: extended_user = "******" % (user_dn, username, names.dnsdomain) db.modify_ldif(extended_user) print "[+] User %s extended and enabled" % username else: print "[!] User '%s' not found" % username
class OpenchangeDBWithLDB(OpenchangeDB): def __init__(self, uri): self.ldb = Ldb(uri) def get_calendar_uri(self, usercn, email): base_dn = "CN=%s,%s" % (usercn, config["samba"]["oc_user_basedn"]) ldb_filter = "(&(objectClass=systemfolder)(PidTagContainerClass=IPF.Appointment)(MAPIStoreURI=*))" res = self.ldb.search(base=base_dn, scope=ldb.SCOPE_SUBTREE, expression=ldb_filter, attrs=["MAPIStoreURI"]) return [str(res[x]["MAPIStoreURI"][0]) for x in xrange(len(res))]
def init(self): #Check to see that this 'existing' LDAP backend in fact exists ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials) search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)") # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied # This caused them to be set into the long-term database later in the script. self.secrets_credentials = self.credentials self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP
def run(self, secret, sambaopts=None, credopts=None, versionopts=None): lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) url = lp.get("secrets database") secretsdb = Ldb(url=url, session_info=system_session(), credentials=creds, lp=lp) result = secretsdb.search(attrs=["secret"], expression="(&(objectclass=primaryDomain)(samaccountname=%s))" % secret) if len(result) != 1: raise CommandError("search returned %d records, expected 1" % len(result)) self.outf.write("%s\n" % result[0]["secret"])
def run(self, secret, sambaopts=None, credopts=None, versionopts=None): lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) name = lp.get("secrets database") path = lp.get("private dir") url = os.path.join(path, name) if not os.path.exists(url): raise CommandError("secret database not found at %s " % url) secretsdb = Ldb(url=url, session_info=system_session(), credentials=creds, lp=lp) result = secretsdb.search( attrs=["secret"], expression="(&(objectclass=primaryDomain)(samaccountname=%s))" % ldb.binary_encode(secret) ) if len(result) != 1: raise CommandError("search returned %d records, expected 1" % len(result)) self.outf.write("%s\n" % result[0]["secret"])
def init(self): # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri # if another instance of slapd is already running try: ldapi_db = Ldb(self.ldapi_uri) search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)"); try: f = open(self.paths.slapdpid, "r") p = f.read() f.close() self.message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.") except: pass raise ProvisioningError("Warning: Another slapd Instance seems already running on this host, listening to " + self.ldapi_uri + ". Please shut it down before you continue. ") except LdbError, e: pass
def start(self): self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'" open(self.paths.ldapdir + "/ldap_backend_startup.sh", 'w').write("#!/bin/sh\n" + self.slapd_command_escaped + "\n") # Now start the slapd, so we can provision onto it. We keep the # subprocess context around, to kill this off at the successful # end of the script self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False) while self.slapd.poll() is None: # Wait until the socket appears try: ldapi_db = Ldb(self.ldapi_uri, lp=self.lp, credentials=self.credentials) search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)") # If we have got here, then we must have a valid connection to the LDAP server! return except LdbError, e: time.sleep(1) pass
def post_setup(self): ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials) # delete default SASL mappings res = ldapi_db.search(expression="(!(cn=samba-admin mapping))", base="cn=mapping,cn=sasl,cn=config", scope=SCOPE_ONELEVEL, attrs=["dn"]) # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket) for i in range (0, len(res)): dn = str(res[i]["dn"]) ldapi_db.delete(dn) aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % self.sambadn m = ldb.Message() m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci") m.dn = ldb.Dn(ldapi_db, self.names.domaindn) ldapi_db.modify(m) m.dn = ldb.Dn(ldapi_db, self.names.configdn) ldapi_db.modify(m) m.dn = ldb.Dn(ldapi_db, self.names.schemadn) ldapi_db.modify(m)
objectclass = None def uniq_list(alist): """return a unique list""" set = {} return [set.setdefault(e,e) for e in alist if e not in set] lp_ctx = sambaopts.get_loadparm() creds = credopts.get_credentials(lp_ctx) db = Ldb(url, credentials=creds, lp=lp_ctx, options=["modules:paged_searches"]) # get the rootDSE res = db.search(base="", expression="", scope=ldb.SCOPE_BASE, attrs=["schemaNamingContext"]) rootDse = res[0] schema_base = rootDse["schemaNamingContext"][0] def possible_inferiors_search(db, oc): """return the possible inferiors via a search for the possibleInferiors attribute""" res = db.search(base=schema_base, expression=("ldapDisplayName=%s" % oc), attrs=["possibleInferiors"]) poss=[] if len(res) == 0 or res[0].get("possibleInferiors") is None: return poss for item in res[0]["possibleInferiors"]:
class MapTestCase(MapBaseTestCase): def setUp(self): super(MapTestCase, self).setUp() ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) ldb.set_opaque("skip_allocate_sids", "true"); ldif = read_datafile("provision_samba3sam.ldif") ldb.add_ldif(self.samba4.subst(ldif)) self.setup_modules(ldb, self.samba3, self.samba4) del ldb self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) self.ldb.set_opaque("skip_allocate_sids", "true"); def test_map_search(self): """Running search tests on mapped data.""" self.samba3.db.add({ "dn": "sambaDomainName=TESTS," + self.samba3.basedn, "objectclass": ["sambaDomain", "top"], "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739", "sambaNextRid": "2000", "sambaDomainName": "TESTS" }) # Add a set of split records self.ldb.add_ldif(""" dn: """+ self.samba4.dn("cn=Domain Users") + """ objectClass: group cn: Domain Users objectSid: S-1-5-21-4231626423-2410014848-2360679739-513 """) # Add a set of split records self.ldb.add_ldif(""" dn: """+ self.samba4.dn("cn=X") + """ objectClass: user cn: X codePage: x revision: x dnsHostName: x nextRid: y lastLogon: x description: x objectSid: S-1-5-21-4231626423-2410014848-2360679739-1052 """) self.ldb.add({ "dn": self.samba4.dn("cn=Y"), "objectClass": "top", "cn": "Y", "codePage": "x", "revision": "x", "dnsHostName": "y", "nextRid": "y", "lastLogon": "y", "description": "x"}) self.ldb.add({ "dn": self.samba4.dn("cn=Z"), "objectClass": "top", "cn": "Z", "codePage": "x", "revision": "y", "dnsHostName": "z", "nextRid": "y", "lastLogon": "z", "description": "y"}) # Add a set of remote records self.samba3.db.add({ "dn": self.samba3.dn("cn=A"), "objectClass": "posixAccount", "cn": "A", "sambaNextRid": "x", "sambaBadPasswordCount": "x", "sambaLogonTime": "x", "description": "x", "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739-1052", "sambaPrimaryGroupSID": "S-1-5-21-4231626423-2410014848-2360679739-512"}) self.samba3.db.add({ "dn": self.samba3.dn("cn=B"), "objectClass": "top", "cn": "B", "sambaNextRid": "x", "sambaBadPasswordCount": "x", "sambaLogonTime": "y", "description": "x"}) self.samba3.db.add({ "dn": self.samba3.dn("cn=C"), "objectClass": "top", "cn": "C", "sambaNextRid": "x", "sambaBadPasswordCount": "y", "sambaLogonTime": "z", "description": "y"}) # Testing search by DN # Search remote record by local DN dn = self.samba4.dn("cn=A") res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") # Search remote record by remote DN dn = self.samba3.dn("cn=A") res = self.samba3.db.search(dn, scope=SCOPE_BASE, attrs=["dnsHostName", "lastLogon", "sambaLogonTime"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertTrue(not "dnsHostName" in res[0]) self.assertTrue(not "lastLogon" in res[0]) self.assertEquals(str(res[0]["sambaLogonTime"]), "x") # Search split record by local DN dn = self.samba4.dn("cn=X") res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["dnsHostName"]), "x") self.assertEquals(str(res[0]["lastLogon"]), "x") # Search split record by remote DN dn = self.samba3.dn("cn=X") res = self.samba3.db.search(dn, scope=SCOPE_BASE, attrs=["dnsHostName", "lastLogon", "sambaLogonTime"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertTrue(not "dnsHostName" in res[0]) self.assertTrue(not "lastLogon" in res[0]) self.assertEquals(str(res[0]["sambaLogonTime"]), "x") # Testing search by attribute # Search by ignored attribute res = self.ldb.search(expression="(revision=x)", scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[0]["dnsHostName"]), "x") self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[1]["dnsHostName"]), "y") self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by kept attribute res = self.ldb.search(expression="(description=y)", scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "z") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[1]["dnsHostName"]), "z") self.assertEquals(str(res[1]["lastLogon"]), "z") # Search by renamed attribute res = self.ldb.search(expression="(badPwdCount=x)", scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by converted attribute # TODO: # Using the SID directly in the parse tree leads to conversion # errors, letting the search fail with no results. #res = self.ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-1052)", scope=SCOPE_DEFAULT, attrs) res = self.ldb.search(expression="(objectSid=*)", base=None, scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon", "objectSid"]) self.assertEquals(len(res), 4) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[1]["dnsHostName"]), "x") self.assertEquals(str(res[1]["lastLogon"]), "x") self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-1052", res[1]["objectSid"]) self.assertTrue("objectSid" in res[1]) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-1052", res[0]["objectSid"]) self.assertTrue("objectSid" in res[0]) # Search by generated attribute # In most cases, this even works when the mapping is missing # a `convert_operator' by enumerating the remote db. res = self.ldb.search(expression="(primaryGroupID=512)", attrs=["dnsHostName", "lastLogon", "primaryGroupID"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[0]["primaryGroupID"]), "512") # Note that Xs "objectSid" seems to be fine in the previous search for # "objectSid"... #res = ldb.search(expression="(primaryGroupID=*)", NULL, ldb. SCOPE_DEFAULT, attrs) #print len(res) + " results found" #for i in range(len(res)): # for (obj in res[i]) { # print obj + ": " + res[i][obj] # } # print "---" # # Search by remote name of renamed attribute */ res = self.ldb.search(expression="(sambaBadPasswordCount=*)", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 0) # Search by objectClass attrs = ["dnsHostName", "lastLogon", "objectClass"] res = self.ldb.search(expression="(objectClass=user)", attrs=attrs) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[0]["objectClass"][0]), "user") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[1]["dnsHostName"]), "x") self.assertEquals(str(res[1]["lastLogon"]), "x") self.assertEquals(str(res[1]["objectClass"][0]), "user") # Prove that the objectClass is actually used for the search res = self.ldb.search(expression="(|(objectClass=user)(badPwdCount=x))", attrs=attrs) self.assertEquals(len(res), 3) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(res[0]["objectClass"][0], "user") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(set(res[1]["objectClass"]), set(["top"])) self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[2]["dnsHostName"]), "x") self.assertEquals(str(res[2]["lastLogon"]), "x") self.assertEquals(str(res[2]["objectClass"][0]), "user") # Testing search by parse tree # Search by conjunction of local attributes res = self.ldb.search(expression="(&(codePage=x)(revision=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[0]["dnsHostName"]), "x") self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[1]["dnsHostName"]), "y") self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by conjunction of remote attributes res = self.ldb.search(expression="(&(lastLogon=x)(description=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[1]["dnsHostName"]), "x") self.assertEquals(str(res[1]["lastLogon"]), "x") # Search by conjunction of local and remote attribute res = self.ldb.search(expression="(&(codePage=x)(description=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[0]["dnsHostName"]), "x") self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[1]["dnsHostName"]), "y") self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by conjunction of local and remote attribute w/o match attrs = ["dnsHostName", "lastLogon"] res = self.ldb.search(expression="(&(codePage=x)(nextRid=x))", attrs=attrs) self.assertEquals(len(res), 0) res = self.ldb.search(expression="(&(revision=x)(lastLogon=z))", attrs=attrs) self.assertEquals(len(res), 0) # Search by disjunction of local attributes res = self.ldb.search(expression="(|(revision=x)(dnsHostName=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[0]["dnsHostName"]), "x") self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[1]["dnsHostName"]), "y") self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by disjunction of remote attributes res = self.ldb.search(expression="(|(badPwdCount=x)(lastLogon=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 3) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertFalse("dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertFalse("dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[2]["dnsHostName"]), "x") self.assertEquals(str(res[2]["lastLogon"]), "x") # Search by disjunction of local and remote attribute res = self.ldb.search(expression="(|(revision=x)(lastLogon=y))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 3) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) self.assertFalse("dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[1]["dnsHostName"]), "x") self.assertEquals(str(res[1]["lastLogon"]), "x") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[2]["dnsHostName"]), "y") self.assertEquals(str(res[2]["lastLogon"]), "y") # Search by disjunction of local and remote attribute w/o match res = self.ldb.search(expression="(|(codePage=y)(nextRid=z))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 0) # Search by negated local attribute res = self.ldb.search(expression="(!(revision=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated remote attribute res = self.ldb.search(expression="(!(description=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 4) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "z") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[1]["dnsHostName"]), "z") self.assertEquals(str(res[1]["lastLogon"]), "z") # Search by negated conjunction of local attributes res = self.ldb.search(expression="(!(&(codePage=x)(revision=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated conjunction of remote attributes res = self.ldb.search(expression="(!(&(lastLogon=x)(description=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "z") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[2]["dnsHostName"]), "y") self.assertEquals(str(res[2]["lastLogon"]), "y") self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated conjunction of local and remote attribute res = self.ldb.search(expression="(!(&(codePage=x)(description=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated disjunction of local attributes res = self.ldb.search(expression="(!(|(revision=x)(dnsHostName=x)))", attrs=["dnsHostName", "lastLogon"]) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated disjunction of remote attributes res = self.ldb.search(expression="(!(|(badPwdCount=x)(lastLogon=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 5) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "z") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) self.assertEquals(str(res[1]["dnsHostName"]), "y") self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[2]["dnsHostName"]), "z") self.assertEquals(str(res[2]["lastLogon"]), "z") # Search by negated disjunction of local and remote attribute res = self.ldb.search(expression="(!(|(revision=x)(lastLogon=y)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 5) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "z") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[2]["dnsHostName"]), "z") self.assertEquals(str(res[2]["lastLogon"]), "z") # Search by complex parse tree res = self.ldb.search(expression="(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 7) res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "y") self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") self.assertEquals(str(res[3].dn), self.samba4.dn("cn=X")) self.assertEquals(str(res[3]["dnsHostName"]), "x") self.assertEquals(str(res[3]["lastLogon"]), "x") self.assertEquals(str(res[4].dn), self.samba4.dn("cn=Z")) self.assertEquals(str(res[4]["dnsHostName"]), "z") self.assertEquals(str(res[4]["lastLogon"]), "z") # Clean up dns = [self.samba4.dn("cn=%s" % n) for n in ["A","B","C","X","Y","Z"]] for dn in dns: self.ldb.delete(dn) def test_map_modify_local(self): """Modification of local records.""" # Add local record dn = "cn=test,dc=idealx,dc=org" self.ldb.add({"dn": dn, "cn": "test", "foo": "bar", "revision": "1", "description": "test"}) # Check it's there attrs = ["foo", "revision", "description"] res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["foo"]), "bar") self.assertEquals(str(res[0]["revision"]), "1") self.assertEquals(str(res[0]["description"]), "test") # Check it's not in the local db res = self.samba4.db.search(expression="(cn=test)", scope=SCOPE_DEFAULT, attrs=attrs) self.assertEquals(len(res), 0) # Check it's not in the remote db res = self.samba3.db.search(expression="(cn=test)", scope=SCOPE_DEFAULT, attrs=attrs) self.assertEquals(len(res), 0) # Modify local record ldif = """ dn: """ + dn + """ replace: foo foo: baz replace: description description: foo """ self.ldb.modify_ldif(ldif) # Check in local db res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["foo"]), "baz") self.assertEquals(str(res[0]["revision"]), "1") self.assertEquals(str(res[0]["description"]), "foo") # Rename local record dn2 = "cn=toast,dc=idealx,dc=org" self.ldb.rename(dn, dn2) # Check in local db res = self.ldb.search(dn2, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["foo"]), "baz") self.assertEquals(str(res[0]["revision"]), "1") self.assertEquals(str(res[0]["description"]), "foo") # Delete local record self.ldb.delete(dn2) # Check it's gone res = self.ldb.search(dn2, scope=SCOPE_BASE) self.assertEquals(len(res), 0) def test_map_modify_remote_remote(self): """Modification of remote data of remote records""" # Add remote record dn = self.samba4.dn("cn=test") dn2 = self.samba3.dn("cn=test") self.samba3.db.add({"dn": dn2, "cn": "test", "description": "foo", "sambaBadPasswordCount": "3", "sambaNextRid": "1001"}) # Check it's there res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=["description", "sambaBadPasswordCount", "sambaNextRid"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["description"]), "foo") self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "3") self.assertEquals(str(res[0]["sambaNextRid"]), "1001") # Check in mapped db attrs = ["description", "badPwdCount", "nextRid"] res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs, expression="") self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["description"]), "foo") self.assertEquals(str(res[0]["badPwdCount"]), "3") self.assertEquals(str(res[0]["nextRid"]), "1001") # Check in local db res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 0) # Modify remote data of remote record ldif = """ dn: """ + dn + """ replace: description description: test replace: badPwdCount badPwdCount: 4 """ self.ldb.modify_ldif(ldif) # Check in mapped db res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=["description", "badPwdCount", "nextRid"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["badPwdCount"]), "4") self.assertEquals(str(res[0]["nextRid"]), "1001") # Check in remote db res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=["description", "sambaBadPasswordCount", "sambaNextRid"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4") self.assertEquals(str(res[0]["sambaNextRid"]), "1001") # Rename remote record dn2 = self.samba4.dn("cn=toast") self.ldb.rename(dn, dn2) # Check in mapped db dn = dn2 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=["description", "badPwdCount", "nextRid"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["badPwdCount"]), "4") self.assertEquals(str(res[0]["nextRid"]), "1001") # Check in remote db dn2 = self.samba3.dn("cn=toast") res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=["description", "sambaBadPasswordCount", "sambaNextRid"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4") self.assertEquals(str(res[0]["sambaNextRid"]), "1001") # Delete remote record self.ldb.delete(dn) # Check in mapped db that it's removed res = self.ldb.search(dn, scope=SCOPE_BASE) self.assertEquals(len(res), 0) # Check in remote db res = self.samba3.db.search(dn2, scope=SCOPE_BASE) self.assertEquals(len(res), 0) def test_map_modify_remote_local(self): """Modification of local data of remote records""" # Add remote record (same as before) dn = self.samba4.dn("cn=test") dn2 = self.samba3.dn("cn=test") self.samba3.db.add({"dn": dn2, "cn": "test", "description": "foo", "sambaBadPasswordCount": "3", "sambaNextRid": "1001"}) # Modify local data of remote record ldif = """ dn: """ + dn + """ add: revision revision: 1 replace: description description: test """ self.ldb.modify_ldif(ldif) # Check in mapped db attrs = ["revision", "description"] res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["revision"]), "1") # Check in remote db res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["description"]), "test") self.assertTrue(not "revision" in res[0]) # Check in local db res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertTrue(not "description" in res[0]) self.assertEquals(str(res[0]["revision"]), "1") # Delete (newly) split record self.ldb.delete(dn) def test_map_modify_split(self): """Testing modification of split records""" # Add split record dn = self.samba4.dn("cn=test") dn2 = self.samba3.dn("cn=test") self.ldb.add({ "dn": dn, "cn": "test", "description": "foo", "badPwdCount": "3", "nextRid": "1001", "revision": "1"}) # Check it's there attrs = ["description", "badPwdCount", "nextRid", "revision"] res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["description"]), "foo") self.assertEquals(str(res[0]["badPwdCount"]), "3") self.assertEquals(str(res[0]["nextRid"]), "1001") self.assertEquals(str(res[0]["revision"]), "1") # Check in local db res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertTrue(not "description" in res[0]) self.assertTrue(not "badPwdCount" in res[0]) self.assertTrue(not "nextRid" in res[0]) self.assertEquals(str(res[0]["revision"]), "1") # Check in remote db attrs = ["description", "sambaBadPasswordCount", "sambaNextRid", "revision"] res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["description"]), "foo") self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "3") self.assertEquals(str(res[0]["sambaNextRid"]), "1001") self.assertTrue(not "revision" in res[0]) # Modify of split record ldif = """ dn: """ + dn + """ replace: description description: test replace: badPwdCount badPwdCount: 4 replace: revision revision: 2 """ self.ldb.modify_ldif(ldif) # Check in mapped db attrs = ["description", "badPwdCount", "nextRid", "revision"] res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["badPwdCount"]), "4") self.assertEquals(str(res[0]["nextRid"]), "1001") self.assertEquals(str(res[0]["revision"]), "2") # Check in local db res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertTrue(not "description" in res[0]) self.assertTrue(not "badPwdCount" in res[0]) self.assertTrue(not "nextRid" in res[0]) self.assertEquals(str(res[0]["revision"]), "2") # Check in remote db attrs = ["description", "sambaBadPasswordCount", "sambaNextRid", "revision"] res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4") self.assertEquals(str(res[0]["sambaNextRid"]), "1001") self.assertTrue(not "revision" in res[0]) # Rename split record dn2 = self.samba4.dn("cn=toast") self.ldb.rename(dn, dn2) # Check in mapped db dn = dn2 attrs = ["description", "badPwdCount", "nextRid", "revision"] res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["badPwdCount"]), "4") self.assertEquals(str(res[0]["nextRid"]), "1001") self.assertEquals(str(res[0]["revision"]), "2") # Check in local db res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn) self.assertTrue(not "description" in res[0]) self.assertTrue(not "badPwdCount" in res[0]) self.assertTrue(not "nextRid" in res[0]) self.assertEquals(str(res[0]["revision"]), "2") # Check in remote db dn2 = self.samba3.dn("cn=toast") res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=["description", "sambaBadPasswordCount", "sambaNextRid", "revision"]) self.assertEquals(len(res), 1) self.assertEquals(str(res[0].dn), dn2) self.assertEquals(str(res[0]["description"]), "test") self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4") self.assertEquals(str(res[0]["sambaNextRid"]), "1001") self.assertTrue(not "revision" in res[0]) # Delete split record self.ldb.delete(dn) # Check in mapped db res = self.ldb.search(dn, scope=SCOPE_BASE) self.assertEquals(len(res), 0) # Check in local db res = self.samba4.db.search(dn, scope=SCOPE_BASE) self.assertEquals(len(res), 0) # Check in remote db res = self.samba3.db.search(dn2, scope=SCOPE_BASE) self.assertEquals(len(res), 0)
class Samba3SamTestCase(MapBaseTestCase): def setUp(self): super(Samba3SamTestCase, self).setUp() ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) ldb.set_opaque("skip_allocate_sids", "true"); self.samba3.setup_data("samba3.ldif") ldif = read_datafile("provision_samba3sam.ldif") ldb.add_ldif(self.samba4.subst(ldif)) self.setup_modules(ldb, self.samba3, self.samba4) del ldb self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) self.ldb.set_opaque("skip_allocate_sids", "true"); def test_search_non_mapped(self): """Looking up by non-mapped attribute""" msg = self.ldb.search(expression="(cn=Administrator)") self.assertEquals(len(msg), 1) self.assertEquals(msg[0]["cn"], "Administrator") def test_search_non_mapped(self): """Looking up by mapped attribute""" msg = self.ldb.search(expression="(name=Backup Operators)") self.assertEquals(len(msg), 1) self.assertEquals(str(msg[0]["name"]), "Backup Operators") def test_old_name_of_renamed(self): """Looking up by old name of renamed attribute""" msg = self.ldb.search(expression="(displayName=Backup Operators)") self.assertEquals(len(msg), 0) def test_mapped_containing_sid(self): """Looking up mapped entry containing SID""" msg = self.ldb.search(expression="(cn=Replicator)") self.assertEquals(len(msg), 1) self.assertEquals(str(msg[0].dn), "cn=Replicator,ou=Groups,dc=vernstok,dc=nl") self.assertTrue("objectSid" in msg[0]) self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-1052", msg[0]["objectSid"]) oc = set(msg[0]["objectClass"]) self.assertEquals(oc, set(["group"])) def test_search_by_objclass(self): """Looking up by objectClass""" msg = self.ldb.search(expression="(|(objectClass=user)(cn=Administrator))") self.assertEquals(set([str(m.dn) for m in msg]), set(["unixName=Administrator,ou=Users,dc=vernstok,dc=nl", "unixName=nobody,ou=Users,dc=vernstok,dc=nl"])) def test_s3sam_modify(self): # Adding a record that will be fallbacked self.ldb.add({ "dn": "cn=Foo", "foo": "bar", "blah": "Blie", "cn": "Foo", "showInAdvancedViewOnly": "TRUE"}) # Checking for existence of record (local) # TODO: This record must be searched in the local database, which is # currently only supported for base searches # msg = ldb.search(expression="(cn=Foo)", ['foo','blah','cn','showInAdvancedViewOnly')] # TODO: Actually, this version should work as well but doesn't... # # msg = self.ldb.search(expression="(cn=Foo)", base="cn=Foo", scope=SCOPE_BASE, attrs=['foo','blah','cn','showInAdvancedViewOnly']) self.assertEquals(len(msg), 1) self.assertEquals(str(msg[0]["showInAdvancedViewOnly"]), "TRUE") self.assertEquals(str(msg[0]["foo"]), "bar") self.assertEquals(str(msg[0]["blah"]), "Blie") # Adding record that will be mapped self.ldb.add({"dn": "cn=Niemand,cn=Users,dc=vernstok,dc=nl", "objectClass": "user", "unixName": "bin", "sambaUnicodePwd": "geheim", "cn": "Niemand"}) # Checking for existence of record (remote) msg = self.ldb.search(expression="(unixName=bin)", attrs=['unixName','cn','dn', 'sambaUnicodePwd']) self.assertEquals(len(msg), 1) self.assertEquals(str(msg[0]["cn"]), "Niemand") self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim") # Checking for existence of record (local && remote) msg = self.ldb.search(expression="(&(unixName=bin)(sambaUnicodePwd=geheim))", attrs=['unixName','cn','dn', 'sambaUnicodePwd']) self.assertEquals(len(msg), 1) # TODO: should check with more records self.assertEquals(str(msg[0]["cn"]), "Niemand") self.assertEquals(str(msg[0]["unixName"]), "bin") self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim") # Checking for existence of record (local || remote) msg = self.ldb.search(expression="(|(unixName=bin)(sambaUnicodePwd=geheim))", attrs=['unixName','cn','dn', 'sambaUnicodePwd']) #print "got %d replies" % len(msg) self.assertEquals(len(msg), 1) # TODO: should check with more records self.assertEquals(str(msg[0]["cn"]), "Niemand") self.assertEquals(str(msg[0]["unixName"]), "bin") self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim") # Checking for data in destination database msg = self.samba3.db.search(expression="(cn=Niemand)") self.assertTrue(len(msg) >= 1) self.assertEquals(str(msg[0]["sambaSID"]), "S-1-5-21-4231626423-2410014848-2360679739-2001") self.assertEquals(str(msg[0]["displayName"]), "Niemand") # Adding attribute... self.ldb.modify_ldif(""" dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl changetype: modify add: description description: Blah """) # Checking whether changes are still there... msg = self.ldb.search(expression="(cn=Niemand)") self.assertTrue(len(msg) >= 1) self.assertEquals(str(msg[0]["cn"]), "Niemand") self.assertEquals(str(msg[0]["description"]), "Blah") # Modifying attribute... self.ldb.modify_ldif(""" dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl changetype: modify replace: description description: Blie """) # Checking whether changes are still there... msg = self.ldb.search(expression="(cn=Niemand)") self.assertTrue(len(msg) >= 1) self.assertEquals(str(msg[0]["description"]), "Blie") # Deleting attribute... self.ldb.modify_ldif(""" dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl changetype: modify delete: description """) # Checking whether changes are no longer there... msg = self.ldb.search(expression="(cn=Niemand)") self.assertTrue(len(msg) >= 1) self.assertTrue(not "description" in msg[0]) # Renaming record... self.ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl", "cn=Niemand2,cn=Users,dc=vernstok,dc=nl") # Checking whether DN has changed... msg = self.ldb.search(expression="(cn=Niemand2)") self.assertEquals(len(msg), 1) self.assertEquals(str(msg[0].dn), "cn=Niemand2,cn=Users,dc=vernstok,dc=nl") # Deleting record... self.ldb.delete("cn=Niemand2,cn=Users,dc=vernstok,dc=nl") # Checking whether record is gone... msg = self.ldb.search(expression="(cn=Niemand2)") self.assertEquals(len(msg), 0)
class LDAPBase(object): def __init__(self, host, creds, lp, two=False, quiet=False, descriptor=False, sort_aces=False, verbose=False, view="section", base="", scope="SUB"): ldb_options = [] samdb_url = host if not "://" in host: if os.path.isfile(host): samdb_url = "tdb://%s" % host else: samdb_url = "ldap://%s" % host # use 'paged_search' module when connecting remotely if samdb_url.lower().startswith("ldap://"): ldb_options = ["modules:paged_searches"] self.ldb = Ldb(url=samdb_url, credentials=creds, lp=lp, options=ldb_options) self.search_base = base self.search_scope = scope self.two_domains = two self.quiet = quiet self.descriptor = descriptor self.sort_aces = sort_aces self.view = view self.verbose = verbose self.host = host self.base_dn = str(self.ldb.get_default_basedn()) self.root_dn = str(self.ldb.get_root_basedn()) self.config_dn = str(self.ldb.get_config_basedn()) self.schema_dn = str(self.ldb.get_schema_basedn()) self.domain_netbios = self.find_netbios() self.server_names = self.find_servers() self.domain_name = re.sub("[Dd][Cc]=", "", self.base_dn).replace(",", ".") self.domain_sid = self.find_domain_sid() self.get_guid_map() self.get_sid_map() # # Log some domain controller specific place-holers that are being used # when compare content of two DCs. Uncomment for DEBUG purposes. if self.two_domains and not self.quiet: self.outf.write("\n* Place-holders for %s:\n" % self.host) self.outf.write(4*" " + "${DOMAIN_DN} => %s\n" % self.base_dn) self.outf.write(4*" " + "${DOMAIN_NETBIOS} => %s\n" % self.domain_netbios) self.outf.write(4*" " + "${SERVER_NAME} => %s\n" % self.server_names) self.outf.write(4*" " + "${DOMAIN_NAME} => %s\n" % self.domain_name) def find_domain_sid(self): res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE) return ndr_unpack(security.dom_sid,res[0]["objectSid"][0]) def find_servers(self): """ """ res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn, \ scope=SCOPE_SUBTREE, expression="(objectClass=computer)", attrs=["cn"]) assert len(res) > 0 srv = [] for x in res: srv.append(x["cn"][0]) return srv def find_netbios(self): res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn, \ scope=SCOPE_SUBTREE, attrs=["nETBIOSName"]) assert len(res) > 0 for x in res: if "nETBIOSName" in x.keys(): return x["nETBIOSName"][0] def object_exists(self, object_dn): res = None try: res = self.ldb.search(base=object_dn, scope=SCOPE_BASE) except LdbError, (enum, estr): if enum == ERR_NO_SUCH_OBJECT: return False raise return len(res) == 1
opts = parser.parse_args()[0] lp = sambaopts.get_loadparm() smbconf = lp.configfile if not opts.database: print "Parameter database is mandatory" sys.exit(1) creds = credopts.get_credentials(lp) creds.set_kerberos_state(DONT_USE_KERBEROS) session = system_session() empty = ldb.Message() newname="%s.new"%(opts.database) if os.path.exists(newname): os.remove(newname) old_ldb = Ldb(opts.database, session_info=session, credentials=creds,lp=lp) new_ldb = Ldb(newname,session_info=session, credentials=creds,lp=lp) new_ldb.transaction_start() res = old_ldb.search(expression="(dn=*)",base="", scope=SCOPE_SUBTREE) for i in range(0,len(res)): if str(res[i].dn) == "@BASEINFO": continue if str(res[i].dn).startswith("@INDEX:"): continue delta = new_ldb.msg_diff(empty,res[i]) delta.dn = res[i].dn delta.remove("distinguishedName") new_ldb.add(delta) new_ldb.transaction_commit()
class LDAPBase(object): def __init__(self, host, creds, lp, two=False, quiet=False, descriptor=False, sort_aces=False, verbose=False, view="section", base="", scope="SUB", outf=sys.stdout, errf=sys.stderr, skip_missing_dn=True): ldb_options = [] samdb_url = host if not "://" in host: if os.path.isfile(host): samdb_url = "tdb://%s" % host else: samdb_url = "ldap://%s" % host # use 'paged_search' module when connecting remotely if samdb_url.lower().startswith("ldap://"): ldb_options = ["modules:paged_searches"] self.outf = outf self.errf = errf self.ldb = Ldb(url=samdb_url, credentials=creds, lp=lp, options=ldb_options) self.search_base = base self.search_scope = scope self.two_domains = two self.quiet = quiet self.descriptor = descriptor self.sort_aces = sort_aces self.view = view self.verbose = verbose self.host = host self.skip_missing_dn = skip_missing_dn self.base_dn = str(self.ldb.get_default_basedn()) self.root_dn = str(self.ldb.get_root_basedn()) self.config_dn = str(self.ldb.get_config_basedn()) self.schema_dn = str(self.ldb.get_schema_basedn()) self.domain_netbios = self.find_netbios() self.server_names = self.find_servers() self.domain_name = re.sub("[Dd][Cc]=", "", self.base_dn).replace(",", ".") self.domain_sid = self.find_domain_sid() self.get_sid_map() # # Log some domain controller specific place-holers that are being used # when compare content of two DCs. Uncomment for DEBUG purposes. if self.two_domains and not self.quiet: self.outf.write("\n* Place-holders for %s:\n" % self.host) self.outf.write(4*" " + "${DOMAIN_DN} => %s\n" % self.base_dn) self.outf.write(4*" " + "${DOMAIN_NETBIOS} => %s\n" % self.domain_netbios) self.outf.write(4*" " + "${SERVER_NAME} => %s\n" % self.server_names) self.outf.write(4*" " + "${DOMAIN_NAME} => %s\n" % self.domain_name) def find_domain_sid(self): res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE) return ndr_unpack(security.dom_sid,res[0]["objectSid"][0]) def find_servers(self): """ """ res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn, scope=SCOPE_SUBTREE, expression="(objectClass=computer)", attrs=["cn"]) assert len(res) > 0 srv = [] for x in res: srv.append(x["cn"][0]) return srv def find_netbios(self): res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn, scope=SCOPE_SUBTREE, attrs=["nETBIOSName"]) assert len(res) > 0 for x in res: if "nETBIOSName" in x.keys(): return x["nETBIOSName"][0] def object_exists(self, object_dn): res = None try: res = self.ldb.search(base=object_dn, scope=SCOPE_BASE) except LdbError as e: (enum, estr) = e.args if enum == ERR_NO_SUCH_OBJECT: return False raise return len(res) == 1 def delete_force(self, object_dn): try: self.ldb.delete(object_dn) except Ldb.LdbError as e: assert "No such object" in str(e) def get_attribute_name(self, key): """ Returns the real attribute name It resolved ranged results e.g. member;range=0-1499 """ r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$") m = r.match(key) if m is None: return key return m.group(1) def get_attribute_values(self, object_dn, key, vals): """ Returns list with all attribute values It resolved ranged results e.g. member;range=0-1499 """ r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$") m = r.match(key) if m is None: # no range, just return the values return vals attr = m.group(1) hi = int(m.group(3)) # get additional values in a loop # until we get a response with '*' at the end while True: n = "%s;range=%d-*" % (attr, hi + 1) res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=[n]) assert len(res) == 1 res = dict(res[0]) del res["dn"] fm = None fvals = None for key in res.keys(): m = r.match(key) if m is None: continue if m.group(1) != attr: continue fm = m fvals = list(res[key]) break if fm is None: break vals.extend(fvals) if fm.group(3) == "*": # if we got "*" we're done break assert int(fm.group(2)) == hi + 1 hi = int(fm.group(3)) return vals def get_attributes(self, object_dn): """ Returns dict with all default visible attributes """ res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["*"]) assert len(res) == 1 res = dict(res[0]) # 'Dn' element is not iterable and we have it as 'distinguishedName' del res["dn"] for key in res.keys(): vals = list(res[key]) del res[key] name = self.get_attribute_name(key) res[name] = self.get_attribute_values(object_dn, key, vals) return res def get_descriptor_sddl(self, object_dn): res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["nTSecurityDescriptor"]) desc = res[0]["nTSecurityDescriptor"][0] desc = ndr_unpack(security.descriptor, desc) return desc.as_sddl(self.domain_sid) def guid_as_string(self, guid_blob): """ Translate binary representation of schemaIDGUID to standard string representation. @gid_blob: binary schemaIDGUID """ blob = "%s" % guid_blob stops = [4, 2, 2, 2, 6] index = 0 res = "" x = 0 while x < len(stops): tmp = "" y = 0 while y < stops[x]: c = hex(ord(blob[index])).replace("0x", "") c = [None, "0" + c, c][len(c)] if 2 * index < len(blob): tmp = c + tmp else: tmp += c index += 1 y += 1 res += tmp + " " x += 1 assert index == len(blob) return res.strip().replace(" ", "-") def get_sid_map(self): """ Build dictionary that maps GUID to 'name' attribute found in Schema or Extended-Rights. """ self.sid_map = {} res = self.ldb.search(base=self.base_dn, expression="(objectSid=*)", scope=SCOPE_SUBTREE, attrs=["objectSid", "sAMAccountName"]) for item in res: try: self.sid_map["%s" % ndr_unpack(security.dom_sid, item["objectSid"][0])] = item["sAMAccountName"][0] except KeyError: pass
def checkusage(names, lp, creds): """Checks whether this server is already provisioned and is being used. :param names: provision names object. :param lp: Loadparm context :param creds: Credentials Context """ samdb = get_local_samdb(names, lp, creds) try: config_dn = samdb.get_config_basedn() mapi_servers = samdb.search( base=config_dn, scope=ldb.SCOPE_SUBTREE, expression="(&(objectClass=msExchExchangeServer)(cn=%s))" % names.netbiosname) server_uses = [] if len(mapi_servers) == 0: # The server is not provisioned. raise NotProvisionedError if len(mapi_servers) > 1: # Check if we are the primary folder store server. our_siteFolderName = "CN=Public Folder Store (%s),CN=First Storage Group,CN=InformationStore,CN=%s,CN=Servers,CN=%s,CN=AdministrativeGroups,%s" % (names.netbiosname, names.netbiosname, names.firstou, names.firstorgdn) dn = "CN=%s,CN=Administrative Groups,%s" % (names.firstou, names.firstorgdn) ret = samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=['siteFolderServer']) assert len(ret) == 1 siteFolderName = ret[0]["siteFolderServer"][0] if our_siteFolderName.lower() == siteFolderName.lower(): server_uses.append("primary folder store server") # Check if we are the primary receipt update service our_addressListServiceLink = "CN=%s,CN=Servers,CN=%s,CN=Administrative Groups,%s" % (names.netbiosname, names.firstou, names.firstorgdn) dn = "CN=Recipient Update Service (%s),CN=Recipient Update Services,CN=Address Lists Container,%s" % (names.domain, names.firstorgdn) ret = samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=['msExchAddressListServiceLink']) assert len(ret) == 1 addressListServiceLink = ret[0]['msExchAddressListServiceLink'][0] if our_addressListServiceLink.lower() == addressListServiceLink.lower(): server_uses.append("primary receipt update service server") # Check if we handle any mailbox. db = Ldb( url=get_ldb_url(lp, creds, names), session_info=system_session(), credentials=creds, lp=lp) our_mailbox_store = "CN=Mailbox Store (%s),CN=First Storage Group,CN=InformationStore,CN=%s,CN=Servers,CN=%s,CN=Administrative Groups,%s" % (names.netbiosname, names.netbiosname, names.firstou, names.firstorgdn) mailboxes = db.search( base=names.domaindn, scope=ldb.SCOPE_SUBTREE, expression="(homeMDB=*)") mailboxes_handled = 0 for user_mailbox in mailboxes: if (user_mailbox['homeMDB'][0] == our_mailbox_store and user_mailbox['msExchUserAccountControl'][0] != '2'): mailboxes_handled += 1 if mailboxes_handled > 0: server_uses.append("handling %d mailboxes" % mailboxes_handled) return server_uses except LdbError, ldb_error: print >> sys.stderr, "[!] error while checking whether this server is being used (%d): %s" % ldb_error.args raise ldb_error
def newuser(names, lp, creds, username=None, mail=None): """extend user record with OpenChange settings. :param lp: Loadparm context :param creds: Credentials context :param names: provision names object. :param username: Name of user to extend :param mail: The user email address. If not specified, it will be set to <samAccountName>@<dnsdomain> """ db = Ldb(url=get_ldb_url(lp, creds, names), session_info=system_session(), credentials=creds, lp=lp) user_dn = get_user_dn(db, "CN=Users,%s" % names.domaindn, username) if user_dn: if mail: smtp_user = mail else: smtp_user = username if '@' not in smtp_user: smtp_user += '@%s' % names.dnsdomain mail_domain = names.dnsdomain else: mail_domain = smtp_user.split('@')[1] extended_user = """ dn: %(user_dn)s changetype: modify add: mailNickName mailNickname: %(username)s add: homeMDB homeMDB: CN=Mailbox Store (%(netbiosname)s),CN=First Storage Group,CN=InformationStore,CN=%(netbiosname)s,CN=Servers,CN=%(firstou)s,CN=Administrative Groups,CN=%(firstorg)s,CN=Microsoft Exchange,CN=Services,CN=Configuration,%(domaindn)s add: homeMTA homeMTA: CN=Mailbox Store (%(netbiosname)s),CN=First Storage Group,CN=InformationStore,CN=%(netbiosname)s,CN=Servers,CN=%(firstou)s,CN=Administrative Groups,CN=%(firstorg)s,CN=Microsoft Exchange,CN=Services,CN=Configuration,%(domaindn)s add: legacyExchangeDN legacyExchangeDN: /o=%(firstorg)s/ou=%(firstou)s/cn=Recipients/cn=%(username)s add: proxyAddresses proxyAddresses: =EX:/o=%(firstorg)s/ou=%(firstou)s/cn=Recipients/cn=%(username)s proxyAddresses: smtp:postmaster@%(mail_domain)s proxyAddresses: X400:c=US;a= ;p=%(firstorg_x400)s;o=%(firstou_x400)s;s=%(username)s proxyAddresses: SMTP:%(smtp_user)s replace: msExchUserAccountControl msExchUserAccountControl: 0 """ ldif_value = extended_user % {"user_dn": user_dn, "username": username, "netbiosname": names.netbiosname, "firstorg": names.firstorg, "firstorg_x400": names.firstorg[:16], "firstou": names.firstou, "firstou_x400": names.firstou[:64], "domaindn": names.domaindn, "dnsdomain": names.dnsdomain, "smtp_user": smtp_user, "mail_domain": mail_domain} db.modify_ldif(ldif_value) res = db.search(base=user_dn, scope=SCOPE_BASE, attrs=["*"]) if len(res) == 1: record = res[0] else: raise Exception("this should never happen as we just modified the record...") record_keys = map(lambda x: x.lower(), record.keys()) if "displayname" not in record_keys: extended_user = "******" % (user_dn, username) db.modify_ldif(extended_user) if "mail" not in record_keys: extended_user = "******" % (user_dn, smtp_user) db.modify_ldif(extended_user) print "[+] User %s extended and enabled" % username else: print "[!] User '%s' not found" % username
class OpenChangeDBWithLdbBackend(object): """The OpenChange database.""" def __init__(self, url): self.url = url self.ldb = Ldb(self.url) self.nttime = samba.unix2nttime(int(time.time())) def reopen(self): self.ldb = Ldb(self.url) def remove(self): """Remove an existing OpenChangeDB file.""" if os.path.exists(self.url): os.remove(self.url) self.reopen() def setup(self, names=None): self.ldb.add_ldif(""" dn: @OPTIONS checkBaseOnSearch: TRUE dn: @INDEXLIST @IDXATTR: cn dn: @ATTRIBUTES cn: CASE_INSENSITIVE dn: CASE_INSENSITIVE """) self.reopen() if names: self.add_rootDSE(names.ocserverdn, names.firstorg, names.firstou) def add_rootDSE(self, ocserverdn, firstorg, firstou): self.ldb.add({"dn": "@ROOTDSE", "defaultNamingContext": "CN=%s,CN=%s,%s" % (firstou, firstorg, ocserverdn), "rootDomainNamingContext": ocserverdn, "vendorName": "OpenChange Team (http://www.openchange.org)"}) def add_server(self, names): self.ldb.add({"dn": names.ocserverdn, "objectClass": ["top", "server"], "cn": names.netbiosname, "GlobalCount": "1", "ChangeNumber": "1", "ReplicaID": "1"}) self.ldb.add({"dn": "CN=%s,%s" % (names.firstorg, names.ocserverdn), "objectClass": ["top", "org"], "cn": names.firstorg}) self.ldb.add({"dn": "CN=%s,CN=%s,%s" % (names.firstou, names.firstorg, names.ocserverdn), "objectClass": ["top", "ou"], "cn": names.firstou}) def add_root_public_folder(self, dn, fid, change_num, SystemIdx, childcount): self.ldb.add({"dn": dn, "objectClass": ["publicfolder"], "cn": fid, "PidTagFolderId": fid, "PidTagChangeNumber": change_num, "PidTagDisplayName": "Public Folder Root", "PidTagCreationTime": "%d" % self.nttime, "PidTagLastModificationTime": "%d" % self.nttime, "PidTagSubFolders": str(childcount != 0).upper(), "PidTagFolderChildCount": str(childcount), "SystemIdx": str(SystemIdx)}) def add_sub_public_folder(self, dn, parentfid, fid, change_num, name, SystemIndex, childcount): self.ldb.add({"dn": dn, "objectClass": ["publicfolder"], "cn": fid, "PidTagFolderId": fid, "PidTagParentFolderId": parentfid, "PidTagChangeNumber": change_num, "PidTagDisplayName": name, "PidTagCreationTime": "%d" % self.nttime, "PidTagLastModificationTime": "%d" % self.nttime, "PidTagAttributeHidden": str(0), "PidTagAttributeReadOnly": str(0), "PidTagAttributeSystem": str(0), "PidTagContainerClass": "IPF.Note (check this)", "PidTagSubFolders": str(childcount != 0).upper(), "PidTagFolderChildCount": str(childcount), "FolderType": str(1), "SystemIdx": str(SystemIndex)}) def add_one_public_folder(self, parent_fid, path, children, SystemIndex, names, dn_prefix = None): name = path[-1] GlobalCount = self.get_message_GlobalCount(names.netbiosname) ChangeNumber = self.get_message_ChangeNumber(names.netbiosname) ReplicaID = self.get_message_ReplicaID(names.netbiosname) if dn_prefix is None: dn_prefix = "CN=publicfolders,CN=%s,CN=%s,%s" % (names.firstou, names.firstorg, names.ocserverdn) fid = gen_mailbox_folder_fid(GlobalCount, ReplicaID) dn = "CN=%s,%s" % (fid, dn_prefix) change_num = gen_mailbox_folder_fid(ChangeNumber, ReplicaID) childcount = len(children) print "\t* %-40s: 0x%.16x (%s)" % (name, int(fid, 10), fid) if parent_fid == 0: self.add_root_public_folder(dn, fid, change_num, SystemIndex, childcount) else: self.add_sub_public_folder(dn, parent_fid, fid, change_num, name, SystemIndex, childcount) GlobalCount += 1 self.set_message_GlobalCount(names.netbiosname, GlobalCount=GlobalCount) ChangeNumber += 1 self.set_message_ChangeNumber(names.netbiosname, ChangeNumber=ChangeNumber) for name, grandchildren in children.iteritems(): self.add_one_public_folder(fid, path + (name,), grandchildren[0], grandchildren[1], names, dn) def add_public_folders(self, names): pfstoreGUID = str(uuid.uuid4()) self.ldb.add({"dn": "CN=publicfolders,CN=%s,CN=%s,%s" % (names.firstou, names.firstorg, names.ocserverdn), "objectClass": ["container"], "cn": "publicfolders", "StoreGUID": pfstoreGUID, "ReplicaID": str(1)}) public_folders = _public_folders_meta(names) self.add_one_public_folder(0, ("Public Folder Root",), public_folders[0], public_folders[1], names) def lookup_server(self, cn, attributes=[]): # Step 1. Search Server object filter = "(&(objectClass=server)(cn=%s))" % cn res = self.ldb.search("", scope=ldb.SCOPE_SUBTREE, expression=filter, attrs=attributes) if len(res) != 1: raise NoSuchServer(cn) return res[0] def lookup_mailbox_user(self, server, username, attributes=[]): """Check if a user already exists in openchange database. :param server: Server object name :param username: Username object :return: LDB Object of the user """ server_dn = self.lookup_server(server, []).dn # Step 2. Search User object filter = "(&(objectClass=mailbox)(cn=%s))" % (username) return self.ldb.search(server_dn, scope=ldb.SCOPE_SUBTREE, expression=filter, attrs=attributes) def lookup_public_folder(self, server, displayname, attributes=[]): """Retrieve the record for a public folder matching a specific display name :param server: Server Object Name :param displayname: Display Name of the Folder :param attributes: Requested Attributes :return: LDB Object of the Folder """ server_dn = self.lookup_server(server, []).dn filter = "(&(objectClass=publicfolder)(PidTagDisplayName=%s))" % (displayname) return self.ldb.search(server_dn, scope=ldb.SCOPE_SUBTREE, expression=filter, attrs=attributes) def get_message_attribute(self, server, attribute): """Retrieve attribute value from given message database (server). :param server: Server object name """ return int(self.lookup_server(server, [attribute])[attribute][0], 10) def get_message_ReplicaID(self, server): """Retrieve current mailbox Replica ID for given message database (server). :param server: Server object name """ return self.get_message_attribute(server, "ReplicaID") def get_message_GlobalCount(self, server): """Retrieve current mailbox Global Count for given message database (server). :param server: Server object name """ return self.get_message_attribute(server, "GlobalCount") def set_message_GlobalCount(self, server, GlobalCount): """Update current mailbox GlobalCount for given message database (server). :param server: Server object name :param index: Mailbox new GlobalCount value """ server_dn = self.lookup_server(server, []).dn newGlobalCount = """ dn: %s changetype: modify replace: GlobalCount GlobalCount: %d """ % (server_dn, GlobalCount) self.ldb.transaction_start() try: self.ldb.modify_ldif(newGlobalCount) finally: self.ldb.transaction_commit() def get_message_ChangeNumber(self, server): """Retrieve current mailbox Global Count for given message database (server). :param server: Server object name """ return self.get_message_attribute(server, "ChangeNumber") def set_message_ChangeNumber(self, server, ChangeNumber): """Update current mailbox ChangeNumber for given message database (server). :param server: Server object name :param index: Mailbox new ChangeNumber value """ server_dn = self.lookup_server(server, []).dn newChangeNumber = """ dn: %s changetype: modify replace: ChangeNumber ChangeNumber: %d """ % (server_dn, ChangeNumber) self.ldb.transaction_start() try: self.ldb.modify_ldif(newChangeNumber) finally: self.ldb.transaction_commit()
print "highest usn {0!s}".format(cookie.blob.highwatermark.highest_usn) print "tmp higest usn {0!s}".format(cookie.blob.highwatermark.tmp_highest_usn) print "reserved usn {0!s}".format(cookie.blob.highwatermark.reserved_usn) if cookie.blob.extra_length >0: print "highest usn in extra {0!s}".format(cookie.blob.extra.ctr.cursors[0].highest_usn) return cookie remote_ldb= Ldb("ldap://" + opts.host + ":389", credentials=creds, lp=lp) tab = [] if opts.b: base = opts.b else: base = None guid = None (msgs, ctrls) = remote_ldb.search(expression="(samaccountname=administrator)", base=base, attrs=["objectClass"], controls=["dirsync:1:1:50"]) if (len(ctrls)): for ctl in ctrls: arr = ctl.split(':') if arr[0] == 'dirsync': cookie = ndr_unpack(drsblobs.ldapControlDirSyncCookie, base64.b64decode(arr[3])) guid = cookie.blob.guid1 pass if not guid: print "No dirsync control ... strange" sys.exit(1) print "" print "Getting first guest without any cookie" (msgs, ctrls) = remote_ldb.searchex(expression="(samaccountname=guest)", base=base, attrs=["objectClass"], controls=["dirsync:1:1:50"]) cookie = None
opts = parser.parse_args()[0] lp = sambaopts.get_loadparm() smbconf = lp.configfile if not opts.database: print "Parameter database is mandatory" sys.exit(1) creds = credopts.get_credentials(lp) creds.set_kerberos_state(DONT_USE_KERBEROS) session = system_session() empty = ldb.Message() newname = "%s.new" % (opts.database) if os.path.exists(newname): os.remove(newname) old_ldb = Ldb(opts.database, session_info=session, credentials=creds, lp=lp) new_ldb = Ldb(newname, session_info=session, credentials=creds, lp=lp) new_ldb.transaction_start() res = old_ldb.search(expression="(dn=*)", base="", scope=SCOPE_SUBTREE) for i in range(0, len(res)): if str(res[i].dn) == "@BASEINFO": continue if str(res[i].dn).startswith("@INDEX:"): continue delta = new_ldb.msg_diff(empty, res[i]) delta.dn = res[i].dn delta.remove("distinguishedName") new_ldb.add(delta) new_ldb.transaction_commit()