dissect.database 1.1.dev9__tar.gz → 1.1.dev11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dissect_database-1.1.dev9/dissect.database.egg-info → dissect_database-1.1.dev11}/PKG-INFO +1 -1
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/index.py +1 -1
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/database.py +16 -2
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/ntds.py +1 -1
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/object.py +10 -5
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/query.py +4 -5
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/schema.py +200 -52
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/util.py +48 -113
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11/dissect.database.egg-info}/PKG-INFO +1 -1
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/test_util.py +6 -3
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/COPYRIGHT +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/LICENSE +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/MANIFEST.in +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/README.md +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/c_db.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/c_db.pyi +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/db.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/tools/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/tools/c_rpm.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/tools/c_rpm.pyi +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/bsd/tools/rpm.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/btree.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/c_ese.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/c_ese.pyi +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/compression.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/cursor.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ese.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/exception.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/lcmapstring.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/c_ds.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/c_ds.pyi +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/c_pek.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/c_pek.pyi +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/c_sd.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/c_sd.pyi +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/applicationsettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/attributeschema.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/builtindomain.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/certificationauthority.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/classschema.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/classstore.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/computer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/configuration.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/container.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/controlaccessright.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/crldistributionpoint.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/crossref.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/crossrefcontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/dfsconfiguration.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/displayspecifier.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/dmd.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/dnsnode.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/dnszone.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/domain.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/domaindns.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/domainpolicy.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/dsuisettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/filelinktracking.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/foreignsecurityprincipal.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/group.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/grouppolicycontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/infrastructureupdate.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/intersitetransport.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/intersitetransportcontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ipsecbase.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ipsecfilter.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ipsecisakmppolicy.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ipsecnegotiationpolicy.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ipsecnfa.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ipsecpolicy.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/leaf.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/linktrackobjectmovetable.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/linktrackvolumetable.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/locality.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/lostandfound.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msauthz_centralaccesspolicies.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msauthz_centralaccessrules.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_content.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_contentset.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_globalsettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_localsettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_member.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_replicationgroup.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_subscriber.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_subscription.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdfsr_topology.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msdns_serversettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_authnpolicies.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_authnpolicysilos.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_claimstransformationpolicies.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_claimtype.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_claimtypepropertybase.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_claimtypes.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_optionalfeature.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_passwordsettingscontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_quotacontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_resourceproperties.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_resourceproperty.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_resourcepropertylist.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_shadowprincipalcontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msds_valuetype.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msimaging_psps.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/mskds_provserverconfiguration.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msmqenterprisesettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/mspki_enterpriseoid.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/mspki_privatekeyrecoveryagent.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/msspp_activationobjectscontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/mstpm_informationobjectscontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ntdsconnection.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ntdsdsa.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ntdsservice.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ntdssitesettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ntfrssettings.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/organizationalperson.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/organizationalunit.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/person.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/physicallocation.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/pkicertificatetemplate.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/pkienrollmentservice.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/querypolicy.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ridmanager.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/ridset.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/rpccontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/rrasadministrationdictionary.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/samserver.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/secret.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/securityobject.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/server.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/serverscontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/site.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/sitelink.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/sitescontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/subnetcontainer.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/subschema.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/top.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/trusteddomain.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/user.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/pek.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/sd.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/page.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/record.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/sorting_table.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/table.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/tools/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/tools/certlog.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/tools/impacket.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/tools/sru.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/tools/ual.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/util.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/exception.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/c_sqlite3.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/c_sqlite3.pyi +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/encryption/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/encryption/sqlcipher/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/encryption/sqlcipher/exception.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/encryption/sqlcipher/sqlcipher.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/exception.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/sqlite3.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/util.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/sqlite3/wal.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect.database.egg-info/SOURCES.txt +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect.database.egg-info/dependency_links.txt +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect.database.egg-info/requires.txt +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect.database.egg-info/top_level.txt +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/pyproject.toml +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/setup.cfg +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/_docs/Makefile +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/_docs/conf.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/_docs/index.rst +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/_tools/sqlite3/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/_tools/sqlite3/generate_sqlite.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/_util.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/bsd/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/bsd/conftest.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/bsd/test_db.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/bsd/test_rpm.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/conftest.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/conftest.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/conftest.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/test_benchmark.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/test_ntds.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/test_pek.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/test_query.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/test_schema.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/ntds/test_sd.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/test_cursor.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/test_ese.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/test_index.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/test_page.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/test_record.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/test_table.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/tools/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/tools/test_certlog.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/tools/test_sru.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/ese/tools/test_ual.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/__init__.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/conftest.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/test_default_values.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/test_row.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/test_sqlcipher.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/test_sqlite3.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/test_util.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tests/sqlite3/test_wal.py +0 -0
- {dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.database
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.dev11
|
|
4
4
|
Summary: A Dissect module implementing parsers for various database formats, including Berkeley DB, Microsofts Extensible Storage Engine (ESE) and SQLite3
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -282,7 +282,7 @@ def _encode_text(index: Index, column: Column, value: str, max_size: int) -> byt
|
|
|
282
282
|
else:
|
|
283
283
|
# Unicode strings == LCMapStringW
|
|
284
284
|
flags = index.record.get("LCMapFlags")
|
|
285
|
-
locale = index.record.get("LocaleName")
|
|
285
|
+
locale = local_name.decode("utf-16-le") if (local_name := index.record.get("LocaleName")) is not None else ""
|
|
286
286
|
segment = map_string(value, flags, locale)
|
|
287
287
|
key += segment[:max_size]
|
|
288
288
|
|
{dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/database.py
RENAMED
|
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
|
|
17
17
|
from collections.abc import Iterator
|
|
18
18
|
|
|
19
19
|
from dissect.database.ese.index import Index
|
|
20
|
-
from dissect.database.ese.ntds.objects import Top
|
|
20
|
+
from dissect.database.ese.ntds.objects import DMD, NTDSDSA, Top
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class Database:
|
|
@@ -43,6 +43,8 @@ class DataTable:
|
|
|
43
43
|
def __init__(self, db: Database):
|
|
44
44
|
self.db = db
|
|
45
45
|
self.table = self.db.ese.table("datatable")
|
|
46
|
+
self.hiddentable = self.db.ese.table("hiddentable")
|
|
47
|
+
self.hiddeninfo = next(self.hiddentable.records(), None)
|
|
46
48
|
|
|
47
49
|
self.schema = Schema()
|
|
48
50
|
|
|
@@ -50,6 +52,18 @@ class DataTable:
|
|
|
50
52
|
self.get = lru_cache(4096)(self.get)
|
|
51
53
|
self._make_dn = lru_cache(4096)(self._make_dn)
|
|
52
54
|
|
|
55
|
+
def dsa(self) -> NTDSDSA:
|
|
56
|
+
"""Return the Directory System Agent (DSA) object."""
|
|
57
|
+
if not self.hiddeninfo:
|
|
58
|
+
raise ValueError("No hiddentable information available")
|
|
59
|
+
return self.get(self.hiddeninfo.get("dsa_col"))
|
|
60
|
+
|
|
61
|
+
def dmd(self) -> DMD:
|
|
62
|
+
"""Return the Directory Management Domain (DMD) object, a.k.a. the schema container."""
|
|
63
|
+
if not self.hiddeninfo:
|
|
64
|
+
raise ValueError("No hiddentable information available")
|
|
65
|
+
return self.get(self.dsa().get("dMDLocation", raw=True))
|
|
66
|
+
|
|
53
67
|
def root(self) -> Top:
|
|
54
68
|
"""Return the top-level object in the NTDS database."""
|
|
55
69
|
if (root := next(self.children_of(0), None)) is None:
|
|
@@ -129,7 +143,7 @@ class DataTable:
|
|
|
129
143
|
raise ValueError(f"Attribute {key!r} is not found in the schema")
|
|
130
144
|
|
|
131
145
|
index = self.table.find_index(schema.column)
|
|
132
|
-
record = index.search([encode_value(self.db,
|
|
146
|
+
record = index.search([encode_value(self.db, schema, value)])
|
|
133
147
|
return Object.from_record(self.db, record)
|
|
134
148
|
|
|
135
149
|
def query(self, query: str, *, optimize: bool = True) -> Iterator[Object]:
|
|
@@ -80,7 +80,7 @@ class NTDS:
|
|
|
80
80
|
|
|
81
81
|
def users(self) -> Iterator[User]:
|
|
82
82
|
"""Get all user objects from the database."""
|
|
83
|
-
yield from self.search(objectCategory="person")
|
|
83
|
+
yield from self.search(objectCategory="person", objectClass="user")
|
|
84
84
|
|
|
85
85
|
def computers(self) -> Iterator[Computer]:
|
|
86
86
|
"""Get all computer objects from the database."""
|
{dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/objects/object.py
RENAMED
|
@@ -64,10 +64,15 @@ class Object:
|
|
|
64
64
|
db: The database instance associated with this object.
|
|
65
65
|
record: The :class:`Record` instance representing this object.
|
|
66
66
|
"""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
try:
|
|
68
|
+
if (object_classes := _get_attribute(db, record, "objectClass")) and (
|
|
69
|
+
known_cls := cls.__known_classes__.get(object_classes[0])
|
|
70
|
+
) is not None:
|
|
71
|
+
return known_cls(db, record)
|
|
72
|
+
except ValueError:
|
|
73
|
+
# Resolving the objectClass values can fail if the schema is not loaded yet (or is malformed)
|
|
74
|
+
# Fallback to a generic Object in that case
|
|
75
|
+
pass
|
|
71
76
|
|
|
72
77
|
return cls(db, record)
|
|
73
78
|
|
|
@@ -268,4 +273,4 @@ def _get_attribute(db: Database, record: Record, name: str, *, raw: bool = False
|
|
|
268
273
|
if raw:
|
|
269
274
|
return value
|
|
270
275
|
|
|
271
|
-
return decode_value(db,
|
|
276
|
+
return decode_value(db, schema, value)
|
|
@@ -83,7 +83,7 @@ class Query:
|
|
|
83
83
|
raise NotImplementedError("Wildcards in the middle or start of the value are not yet supported")
|
|
84
84
|
else:
|
|
85
85
|
# Exact match query
|
|
86
|
-
encoded_value = encode_value(self.db,
|
|
86
|
+
encoded_value = encode_value(self.db, schema, filter.value)
|
|
87
87
|
yield from index.cursor().find_all(**{schema.column: encoded_value})
|
|
88
88
|
|
|
89
89
|
def _process_and_operation(self, filter: SearchFilter, records: list[Record] | None) -> Iterator[Record]:
|
|
@@ -132,12 +132,11 @@ class Query:
|
|
|
132
132
|
Yields:
|
|
133
133
|
Records that match the filter criteria.
|
|
134
134
|
"""
|
|
135
|
-
|
|
136
|
-
schema = self.db.data.schema.lookup_attribute(name=filter.attribute)
|
|
137
|
-
|
|
138
|
-
if schema is None:
|
|
135
|
+
if (schema := self.db.data.schema.lookup_attribute(name=filter.attribute)) is None:
|
|
139
136
|
return
|
|
140
137
|
|
|
138
|
+
encoded_value = encode_value(self.db, schema, filter.value)
|
|
139
|
+
|
|
141
140
|
has_wildcard = "*" in filter.value
|
|
142
141
|
wildcard_prefix = filter.value.replace("*", "").lower() if has_wildcard else None
|
|
143
142
|
|
{dissect_database-1.1.dev9 → dissect_database-1.1.dev11}/dissect/database/ese/ntds/schema.py
RENAMED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from io import BytesIO
|
|
3
4
|
from typing import TYPE_CHECKING, NamedTuple
|
|
4
5
|
|
|
5
|
-
from dissect.database.ese.ntds.
|
|
6
|
-
from dissect.database.ese.ntds.util import OID_TO_TYPE, attrtyp_to_oid
|
|
6
|
+
from dissect.database.ese.ntds.c_ds import c_ds
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
|
-
from collections.abc import Iterator
|
|
10
|
-
|
|
11
9
|
from dissect.database.ese.ntds.database import Database
|
|
12
10
|
from dissect.database.ese.ntds.util import SearchFlags
|
|
13
11
|
|
|
@@ -50,6 +48,8 @@ BOOTSTRAP_ATTRIBUTES = [
|
|
|
50
48
|
("searchFlags", 131406, 0x00080009, True), # ATTj131406
|
|
51
49
|
# Class schema
|
|
52
50
|
("governsID", 131094, 0x00080002, True), # ATTc131094
|
|
51
|
+
# DSA attributes
|
|
52
|
+
("dMDLocation", 131108, 0x00080001, True), # ATTb131108
|
|
53
53
|
]
|
|
54
54
|
|
|
55
55
|
# For convenience, bootstrap some common object classes
|
|
@@ -60,21 +60,63 @@ BOOTSTRAP_OBJECT_CLASSES = {
|
|
|
60
60
|
"attributeSchema": 0x0003000E,
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
# These are fixed OID prefixes used in the schema
|
|
64
|
+
# Reference: MSPrefixTable
|
|
65
|
+
BOOTSTRAP_OID_PREFIXES = {
|
|
66
|
+
0: b"\x55\x04",
|
|
67
|
+
1: b"\x55\x06",
|
|
68
|
+
2: b"\x2a\x86\x48\x86\xf7\x14\x01\x02",
|
|
69
|
+
3: b"\x2a\x86\x48\x86\xf7\x14\x01\x03",
|
|
70
|
+
4: b"\x60\x86\x48\x01\x65\x02\x02\x01",
|
|
71
|
+
5: b"\x60\x86\x48\x01\x65\x02\x02\x03",
|
|
72
|
+
6: b"\x60\x86\x48\x01\x65\x02\x01\x05",
|
|
73
|
+
7: b"\x60\x86\x48\x01\x65\x02\x01\x04",
|
|
74
|
+
8: b"\x55\x05",
|
|
75
|
+
9: b"\x2a\x86\x48\x86\xf7\x14\x01\x04",
|
|
76
|
+
10: b"\x2a\x86\x48\x86\xf7\x14\x01\x05",
|
|
77
|
+
11: b"\x2a\x86\x48\x86\xf7\x14\x01\x04\x82\x04",
|
|
78
|
+
12: b"\x2a\x86\x48\x86\xf7\x14\x01\x05\x38",
|
|
79
|
+
13: b"\x2a\x86\x48\x86\xf7\x14\x01\x04\x82\x06",
|
|
80
|
+
14: b"\x2a\x86\x48\x86\xf7\x14\x01\x05\x39",
|
|
81
|
+
15: b"\x2a\x86\x48\x86\xf7\x14\x01\x04\x82\x07",
|
|
82
|
+
16: b"\x2a\x86\x48\x86\xf7\x14\x01\x05\x3a",
|
|
83
|
+
17: b"\x2a\x86\x48\x86\xf7\x14\x01\x05\x49",
|
|
84
|
+
18: b"\x2a\x86\x48\x86\xf7\x14\x01\x04\x82\x31",
|
|
85
|
+
19: b"\x09\x92\x26\x89\x93\xf2\x2c\x64",
|
|
86
|
+
20: b"\x60\x86\x48\x01\x86\xf8\x42\x03",
|
|
87
|
+
21: b"\x09\x92\x26\x89\x93\xf2\x2c\x64\x01",
|
|
88
|
+
22: b"\x60\x86\x48\x01\x86\xf8\x42\x03\x01",
|
|
89
|
+
23: b"\x2a\x86\x48\x86\xf7\x14\x01\x05\xb6\x58",
|
|
90
|
+
24: b"\x55\x15",
|
|
91
|
+
25: b"\x55\x12",
|
|
92
|
+
26: b"\x55\x14",
|
|
93
|
+
27: b"\x2b\x06\x01\x04\x01\x8b\x3a\x65\x77",
|
|
94
|
+
28: b"\x60\x86\x48\x01\x86\xf8\x42\x03\x02",
|
|
95
|
+
29: b"\x2b\x06\x01\x04\x01\x81\x7a\x01",
|
|
96
|
+
30: b"\x2a\x86\x48\x86\xf7\x0d\x01\x09",
|
|
97
|
+
31: b"\x09\x92\x26\x89\x93\xf2\x2c\x64\x04",
|
|
98
|
+
32: b"\x2a\x86\x48\x86\xf7\x14\x01\x06\x17",
|
|
99
|
+
33: b"\x2a\x86\x48\x86\xf7\x14\x01\x06\x12\x01",
|
|
100
|
+
34: b"\x2a\x86\x48\x86\xf7\x14\x01\x06\x12\x02",
|
|
101
|
+
35: b"\x2a\x86\x48\x86\xf7\x14\x01\x06\x0d\x03",
|
|
102
|
+
36: b"\x2a\x86\x48\x86\xf7\x14\x01\x06\x0d\x04",
|
|
103
|
+
37: b"\x2b\x06\x01\x01\x01\x01",
|
|
104
|
+
38: b"\x2b\x06\x01\x01\x01\x02",
|
|
105
|
+
}
|
|
106
|
+
|
|
63
107
|
|
|
64
108
|
class ClassEntry(NamedTuple):
|
|
65
109
|
dnt: int
|
|
66
|
-
oid: str
|
|
67
110
|
id: int
|
|
68
111
|
name: str
|
|
69
112
|
|
|
70
113
|
|
|
71
114
|
class AttributeEntry(NamedTuple):
|
|
72
115
|
dnt: int
|
|
73
|
-
oid: str
|
|
74
116
|
id: int
|
|
75
117
|
name: str
|
|
76
118
|
column: str
|
|
77
|
-
|
|
119
|
+
syntax: int
|
|
78
120
|
om_syntax: int | None
|
|
79
121
|
om_object_class: bytes | None
|
|
80
122
|
is_single_valued: bool
|
|
@@ -91,7 +133,6 @@ class Schema:
|
|
|
91
133
|
def __init__(self):
|
|
92
134
|
# Combined indices
|
|
93
135
|
self._dnt_index: dict[int, ClassEntry | AttributeEntry] = {}
|
|
94
|
-
self._oid_index: dict[str, ClassEntry | AttributeEntry] = {}
|
|
95
136
|
self._attrtyp_index: dict[int, ClassEntry | AttributeEntry] = {}
|
|
96
137
|
|
|
97
138
|
# Attribute specific indices
|
|
@@ -104,16 +145,23 @@ class Schema:
|
|
|
104
145
|
self._class_id_index: dict[int, ClassEntry] = {}
|
|
105
146
|
self._class_name_index: dict[str, ClassEntry] = {}
|
|
106
147
|
|
|
148
|
+
# OID prefixes
|
|
149
|
+
self._oid_idx_to_prefix_index: dict[int, str] = {
|
|
150
|
+
idx: decode_oid(prefix) for idx, prefix in BOOTSTRAP_OID_PREFIXES.items()
|
|
151
|
+
}
|
|
152
|
+
self._oid_prefix_to_idx_index: dict[str, int] = {
|
|
153
|
+
prefix: idx for idx, prefix in self._oid_idx_to_prefix_index.items()
|
|
154
|
+
}
|
|
155
|
+
|
|
107
156
|
# Bootstrap fixed database columns (these do not exist in the schema)
|
|
108
|
-
for ldap_name, column_name,
|
|
157
|
+
for ldap_name, column_name, attrtyp in BOOTSTRAP_COLUMNS:
|
|
109
158
|
self._add(
|
|
110
159
|
AttributeEntry(
|
|
111
160
|
dnt=-1,
|
|
112
|
-
oid="",
|
|
113
161
|
id=-1,
|
|
114
162
|
name=ldap_name,
|
|
115
163
|
column=column_name,
|
|
116
|
-
|
|
164
|
+
syntax=attrtyp & 0xFF,
|
|
117
165
|
om_syntax=None,
|
|
118
166
|
om_object_class=None,
|
|
119
167
|
is_single_valued=True,
|
|
@@ -123,12 +171,12 @@ class Schema:
|
|
|
123
171
|
)
|
|
124
172
|
|
|
125
173
|
# Bootstrap initial attributes
|
|
126
|
-
for name, id,
|
|
174
|
+
for name, id, attrtyp, is_single_valued in BOOTSTRAP_ATTRIBUTES:
|
|
127
175
|
self._add_attribute(
|
|
128
176
|
dnt=-1,
|
|
129
177
|
id=id,
|
|
130
178
|
name=name,
|
|
131
|
-
syntax=
|
|
179
|
+
syntax=attrtyp,
|
|
132
180
|
om_syntax=None,
|
|
133
181
|
om_object_class=None,
|
|
134
182
|
is_single_valued=is_single_valued,
|
|
@@ -151,48 +199,48 @@ class Schema:
|
|
|
151
199
|
db: The database instance to load the schema from.
|
|
152
200
|
"""
|
|
153
201
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
cursor.reset()
|
|
161
|
-
cursor.seek([id])
|
|
162
|
-
|
|
163
|
-
record = cursor.record()
|
|
164
|
-
while record is not None and record != end:
|
|
165
|
-
yield Object.from_record(db, record)
|
|
166
|
-
record = cursor.next()
|
|
202
|
+
# Load the schema entries from the DMD object
|
|
203
|
+
# This _should_ have all the attribute and class schema entries
|
|
204
|
+
# We used to perform an index search on objectClass (ATTc0, INDEX_00000000), but apparently
|
|
205
|
+
# not all databases have this index
|
|
206
|
+
dmd = db.data.dmd()
|
|
167
207
|
|
|
168
208
|
# We bootstrapped these earlier
|
|
169
209
|
attribute_schema = self.lookup_class(name="attributeSchema")
|
|
170
210
|
class_schema = self.lookup_class(name="classSchema")
|
|
171
211
|
|
|
172
|
-
for obj in
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
212
|
+
for obj in dmd.children():
|
|
213
|
+
# Get as raw to avoid decoding the attribute and class schema entries before we know which is which
|
|
214
|
+
classes = obj.get("objectClass", raw=True)
|
|
215
|
+
if attribute_schema.id in classes:
|
|
216
|
+
self._add_attribute(
|
|
217
|
+
dnt=obj.dnt,
|
|
218
|
+
id=obj.get("attributeID", raw=True),
|
|
219
|
+
name=obj.get("lDAPDisplayName"),
|
|
220
|
+
syntax=obj.get("attributeSyntax", raw=True),
|
|
221
|
+
om_syntax=obj.get("oMSyntax"),
|
|
222
|
+
om_object_class=obj.get("oMObjectClass"),
|
|
223
|
+
is_single_valued=obj.get("isSingleValued"),
|
|
224
|
+
link_id=obj.get("linkId"),
|
|
225
|
+
search_flags=obj.get("searchFlags"),
|
|
226
|
+
)
|
|
184
227
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
228
|
+
elif class_schema.id in classes:
|
|
229
|
+
self._add_class(
|
|
230
|
+
dnt=obj.dnt,
|
|
231
|
+
id=obj.get("governsID", raw=True),
|
|
232
|
+
name=obj.get("lDAPDisplayName"),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Load user-defined OID prefixes
|
|
236
|
+
if (prefix_map := db.data.dmd().get("prefixMap")) is not None:
|
|
237
|
+
self._oid_idx_to_prefix_index.update(parse_prefix_map(prefix_map))
|
|
238
|
+
# Rebuild the reverse index
|
|
239
|
+
self._oid_prefix_to_idx_index = {prefix: idx for idx, prefix in self._oid_idx_to_prefix_index.items()}
|
|
191
240
|
|
|
192
241
|
def _add_class(self, dnt: int, id: int, name: str) -> None:
|
|
193
242
|
entry = ClassEntry(
|
|
194
243
|
dnt=dnt,
|
|
195
|
-
oid=attrtyp_to_oid(id),
|
|
196
244
|
id=id,
|
|
197
245
|
name=name,
|
|
198
246
|
)
|
|
@@ -210,14 +258,12 @@ class Schema:
|
|
|
210
258
|
link_id: int | None,
|
|
211
259
|
search_flags: SearchFlags | None,
|
|
212
260
|
) -> None:
|
|
213
|
-
type_oid = attrtyp_to_oid(syntax)
|
|
214
261
|
entry = AttributeEntry(
|
|
215
262
|
dnt=dnt,
|
|
216
|
-
oid=attrtyp_to_oid(id),
|
|
217
263
|
id=id,
|
|
218
264
|
name=name,
|
|
219
|
-
column=f"ATT{
|
|
220
|
-
|
|
265
|
+
column=f"ATT{chr(ord('a') + (syntax & 0xFFFF))}{id}",
|
|
266
|
+
syntax=syntax & 0xFF,
|
|
221
267
|
om_syntax=om_syntax,
|
|
222
268
|
om_object_class=om_object_class,
|
|
223
269
|
is_single_valued=is_single_valued,
|
|
@@ -229,8 +275,6 @@ class Schema:
|
|
|
229
275
|
def _add(self, entry: ClassEntry | AttributeEntry) -> None:
|
|
230
276
|
if entry.dnt != -1:
|
|
231
277
|
self._dnt_index[entry.dnt] = entry
|
|
232
|
-
if entry.oid != "":
|
|
233
|
-
self._oid_index[entry.oid] = entry
|
|
234
278
|
if entry.id != -1:
|
|
235
279
|
self._attrtyp_index[entry.id] = entry
|
|
236
280
|
|
|
@@ -311,6 +355,62 @@ class Schema:
|
|
|
311
355
|
|
|
312
356
|
return None
|
|
313
357
|
|
|
358
|
+
def lookup_oid(self, oid: str) -> ClassEntry | AttributeEntry | None:
|
|
359
|
+
"""Lookup a schema entry by OID.
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
oid: The OID to look up.
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
The matching schema entry or ``None`` if not found.
|
|
366
|
+
"""
|
|
367
|
+
parts = oid.split(".")
|
|
368
|
+
if len(parts) < 2:
|
|
369
|
+
return None
|
|
370
|
+
|
|
371
|
+
long_id = 0
|
|
372
|
+
prefix_length = 0
|
|
373
|
+
if len(parts) > 2 and int(parts[-2]) & 0x80:
|
|
374
|
+
prefix_length = len(parts) - 2
|
|
375
|
+
long_id = int(parts[-3]) >> 7
|
|
376
|
+
else:
|
|
377
|
+
prefix_length = len(parts) - 1
|
|
378
|
+
|
|
379
|
+
prefix = ".".join(parts[:prefix_length])
|
|
380
|
+
if (idx := self._oid_prefix_to_idx_index.get(prefix)) is None:
|
|
381
|
+
return None
|
|
382
|
+
|
|
383
|
+
attrtyp = idx << 16
|
|
384
|
+
if len(parts) == prefix_length + 2:
|
|
385
|
+
attrtyp += (int(parts[-2]) & 0x7F) << 7
|
|
386
|
+
if long_id:
|
|
387
|
+
attrtyp |= 0x8000
|
|
388
|
+
|
|
389
|
+
attrtyp += int(parts[-1])
|
|
390
|
+
return self._attrtyp_index.get(attrtyp)
|
|
391
|
+
|
|
392
|
+
def attrtyp_to_oid(self, attrtyp: int) -> str | None:
|
|
393
|
+
"""Convert an ATTRTYP integer value to an OID string.
|
|
394
|
+
|
|
395
|
+
Args:
|
|
396
|
+
attrtyp: The ATTRTYP integer value to convert.
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
The corresponding OID string or ``None`` if the ATTRTYP does not correspond to a valid OID.
|
|
400
|
+
"""
|
|
401
|
+
if (prefix := self._oid_idx_to_prefix_index.get(attrtyp >> 16)) is None:
|
|
402
|
+
return None
|
|
403
|
+
|
|
404
|
+
parts = [prefix]
|
|
405
|
+
|
|
406
|
+
if attrtyp & 0xFFFF < 0x80:
|
|
407
|
+
parts.append(str(attrtyp & 0xFF))
|
|
408
|
+
else:
|
|
409
|
+
parts.append(str(((attrtyp & 0xFF80) >> 7) | 0x80))
|
|
410
|
+
parts.append(str(attrtyp & 0x7F))
|
|
411
|
+
|
|
412
|
+
return ".".join(parts)
|
|
413
|
+
|
|
314
414
|
def lookup(
|
|
315
415
|
self,
|
|
316
416
|
*,
|
|
@@ -338,7 +438,7 @@ class Schema:
|
|
|
338
438
|
return self._dnt_index.get(dnt)
|
|
339
439
|
|
|
340
440
|
if oid is not None:
|
|
341
|
-
return self.
|
|
441
|
+
return self.lookup_oid(oid)
|
|
342
442
|
|
|
343
443
|
if attrtyp is not None:
|
|
344
444
|
return self._attrtyp_index.get(attrtyp)
|
|
@@ -348,3 +448,51 @@ class Schema:
|
|
|
348
448
|
return self._class_name_index.get(name) or self._attribute_name_index.get(name)
|
|
349
449
|
|
|
350
450
|
return None
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def parse_prefix_map(buf: bytes) -> dict[int, str]:
|
|
454
|
+
"""Parse a prefix map.
|
|
455
|
+
|
|
456
|
+
Args:
|
|
457
|
+
buf: The buffer containing the prefix map data.
|
|
458
|
+
"""
|
|
459
|
+
result = {}
|
|
460
|
+
|
|
461
|
+
fh = BytesIO(buf)
|
|
462
|
+
c_ds.uint32(fh) # Number of prefixes
|
|
463
|
+
total_size = c_ds.uint32(fh) # Total size
|
|
464
|
+
|
|
465
|
+
while fh.tell() < total_size:
|
|
466
|
+
index = c_ds.uint16(fh)
|
|
467
|
+
prefix_length = c_ds.uint16(fh)
|
|
468
|
+
prefix = fh.read(prefix_length)
|
|
469
|
+
|
|
470
|
+
result[index] = decode_oid(prefix)
|
|
471
|
+
|
|
472
|
+
return result
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def decode_oid(buf: bytes) -> str:
|
|
476
|
+
"""Decode a BER encoded OID.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
buf: The buffer containing the BER encoded OID.
|
|
480
|
+
"""
|
|
481
|
+
values = [*divmod(buf[0], 40)]
|
|
482
|
+
|
|
483
|
+
idx = 1
|
|
484
|
+
while idx < len(buf):
|
|
485
|
+
value = buf[idx] & 0x7F
|
|
486
|
+
while buf[idx] & 0x80:
|
|
487
|
+
value <<= 7
|
|
488
|
+
idx += 1
|
|
489
|
+
|
|
490
|
+
if idx >= len(buf):
|
|
491
|
+
break
|
|
492
|
+
|
|
493
|
+
value |= buf[idx] & 0x7F
|
|
494
|
+
|
|
495
|
+
values.append(value)
|
|
496
|
+
idx += 1
|
|
497
|
+
|
|
498
|
+
return ".".join(map(str, values))
|