mirror of
https://github.com/samba-team/samba.git
synced 2025-08-04 08:22:08 +03:00
r26628: python: Add more documentation, simplify code in Samba3 module.
(This used to be commit 3c329ee73d
)
This commit is contained in:
committed by
Stefan Metzmacher
parent
ac65321a46
commit
6817c5d885
@ -30,7 +30,7 @@ realdistclean::
|
|||||||
|
|
||||||
pythonmods: $(PYTHON_DSOS)
|
pythonmods: $(PYTHON_DSOS)
|
||||||
|
|
||||||
PYDOCTOR_MODULES=bin/python/ldb.py bin/python/auth.py bin/python/credentials.py bin/python/registry.py bin/python/tdb.py bin/python/security.py
|
PYDOCTOR_MODULES=bin/python/ldb.py bin/python/auth.py bin/python/credentials.py bin/python/registry.py bin/python/tdb.py bin/python/security.py bin/python/events.py bin/python/net.py
|
||||||
|
|
||||||
pydoctor:: pythonmods
|
pydoctor:: pythonmods
|
||||||
LD_LIBRARY_PATH=bin/shared PYTHONPATH=bin/python pydoctor --make-html --docformat=restructuredtext --add-package scripting/python/samba/ $(addprefix --add-module , $(PYDOCTOR_MODULES))
|
LD_LIBRARY_PATH=bin/shared PYTHONPATH=bin/python pydoctor --make-html --docformat=restructuredtext --add-package scripting/python/samba/ $(addprefix --add-module , $(PYDOCTOR_MODULES))
|
||||||
|
@ -159,11 +159,19 @@ class Ldb(ldb.Ldb):
|
|||||||
self.add_ldif(open(ldif_path, 'r').read())
|
self.add_ldif(open(ldif_path, 'r').read())
|
||||||
|
|
||||||
def add_ldif(self, ldif):
|
def add_ldif(self, ldif):
|
||||||
|
"""Add data based on a LDIF string.
|
||||||
|
|
||||||
|
:param ldif: LDIF text.
|
||||||
|
"""
|
||||||
for changetype, msg in self.parse_ldif(ldif):
|
for changetype, msg in self.parse_ldif(ldif):
|
||||||
assert changetype == ldb.CHANGETYPE_NONE
|
assert changetype == ldb.CHANGETYPE_NONE
|
||||||
self.add(msg)
|
self.add(msg)
|
||||||
|
|
||||||
def modify_ldif(self, ldif):
|
def modify_ldif(self, ldif):
|
||||||
|
"""Modify database based on a LDIF string.
|
||||||
|
|
||||||
|
:param ldif: LDIF text.
|
||||||
|
"""
|
||||||
for (changetype, msg) in self.parse_ldif(ldif):
|
for (changetype, msg) in self.parse_ldif(ldif):
|
||||||
assert changetype == ldb.CHANGETYPE_MODIFY
|
assert changetype == ldb.CHANGETYPE_MODIFY
|
||||||
self.modify(msg)
|
self.modify(msg)
|
||||||
|
@ -58,7 +58,7 @@ class CredentialsOptions(optparse.OptionGroup):
|
|||||||
self.creds.set_password(arg)
|
self.creds.set_password(arg)
|
||||||
|
|
||||||
def set_simple_bind_dn(self, option, opt_str, arg, parser):
|
def set_simple_bind_dn(self, option, opt_str, arg, parser):
|
||||||
self.creds.set_simple_bind_dn(arg)
|
self.creds.set_bind_dn(arg)
|
||||||
|
|
||||||
def get_credentials(self):
|
def get_credentials(self):
|
||||||
return self.creds
|
return self.creds
|
||||||
|
@ -74,6 +74,14 @@ def findnss(nssfn, *names):
|
|||||||
|
|
||||||
|
|
||||||
def open_ldb(session_info, credentials, lp, dbname):
|
def open_ldb(session_info, credentials, lp, dbname):
|
||||||
|
"""Open a LDB, thrashing it if it is corrupt.
|
||||||
|
|
||||||
|
:param session_info: auth session information
|
||||||
|
:param credentials: credentials
|
||||||
|
:param lp: Loadparm context
|
||||||
|
:param dbname: Path of the database to open.
|
||||||
|
:return: a Ldb object
|
||||||
|
"""
|
||||||
assert session_info is not None
|
assert session_info is not None
|
||||||
try:
|
try:
|
||||||
return Ldb(dbname, session_info=session_info, credentials=credentials,
|
return Ldb(dbname, session_info=session_info, credentials=credentials,
|
||||||
@ -86,7 +94,12 @@ def open_ldb(session_info, credentials, lp, dbname):
|
|||||||
|
|
||||||
|
|
||||||
def setup_add_ldif(ldb, ldif_path, subst_vars=None):
|
def setup_add_ldif(ldb, ldif_path, subst_vars=None):
|
||||||
"""Setup a ldb in the private dir."""
|
"""Setup a ldb in the private dir.
|
||||||
|
|
||||||
|
:param ldb: LDB file to import data into
|
||||||
|
:param ldif_path: Path of the LDIF file to load
|
||||||
|
:param subst_vars: Optional variables to subsitute in LDIF.
|
||||||
|
"""
|
||||||
assert isinstance(ldif_path, str)
|
assert isinstance(ldif_path, str)
|
||||||
|
|
||||||
data = open(ldif_path, 'r').read()
|
data = open(ldif_path, 'r').read()
|
||||||
@ -126,7 +139,12 @@ def setup_ldb(ldb, ldif_path, subst_vars):
|
|||||||
|
|
||||||
|
|
||||||
def setup_file(template, fname, substvars):
|
def setup_file(template, fname, substvars):
|
||||||
"""Setup a file in the private dir."""
|
"""Setup a file in the private dir.
|
||||||
|
|
||||||
|
:param template: Path of the template file.
|
||||||
|
:param fname: Path of the file to create.
|
||||||
|
:param substvars: Substitution variables.
|
||||||
|
"""
|
||||||
f = fname
|
f = fname
|
||||||
|
|
||||||
if os.path.exists(f):
|
if os.path.exists(f):
|
||||||
@ -179,7 +197,17 @@ def provision_paths_from_lp(lp, dnsdomain):
|
|||||||
|
|
||||||
def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users,
|
def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users,
|
||||||
wheel, backup):
|
wheel, backup):
|
||||||
"""setup reasonable name mappings for sam names to unix names."""
|
"""setup reasonable name mappings for sam names to unix names.
|
||||||
|
|
||||||
|
:param ldb: SamDB object.
|
||||||
|
:param sid: The domain sid.
|
||||||
|
:param domaindn: The domain DN.
|
||||||
|
:param root: Name of the UNIX root user.
|
||||||
|
:param nobody: Name of the UNIX nobody user.
|
||||||
|
:param nogroup: Name of the unix nobody group.
|
||||||
|
:param users: Name of the unix users group.
|
||||||
|
:param wheel: Name of the wheel group (users that can become root).
|
||||||
|
:param backup: Name of the backup group."""
|
||||||
# add some foreign sids if they are not present already
|
# add some foreign sids if they are not present already
|
||||||
ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
|
ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous")
|
||||||
ldb.add_foreign(domaindn, "S-1-1-0", "World")
|
ldb.add_foreign(domaindn, "S-1-1-0", "World")
|
||||||
@ -591,7 +619,8 @@ def provision(lp, setup_dir, message, blank, paths, session_info,
|
|||||||
if nogroup is None:
|
if nogroup is None:
|
||||||
nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2]
|
nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2]
|
||||||
if users is None:
|
if users is None:
|
||||||
users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", "usr")[2]
|
users = findnss(grp.getgrnam, "users", "guest", "other", "unknown",
|
||||||
|
"usr")[2]
|
||||||
if wheel is None:
|
if wheel is None:
|
||||||
wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2]
|
wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2]
|
||||||
if backup is None:
|
if backup is None:
|
||||||
@ -748,13 +777,32 @@ def provision(lp, setup_dir, message, blank, paths, session_info,
|
|||||||
return domaindn
|
return domaindn
|
||||||
|
|
||||||
def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path):
|
def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path):
|
||||||
|
"""Create a PHP LDAP admin configuration file.
|
||||||
|
|
||||||
|
:param path: Path to write the configuration to.
|
||||||
|
:param setup_path: Function to generate setup paths.
|
||||||
|
:param s4_ldapi_path: Path to Samba 4 LDAPI socket.
|
||||||
|
"""
|
||||||
setup_file(setup_path("phpldapadmin-config.php"),
|
setup_file(setup_path("phpldapadmin-config.php"),
|
||||||
path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")})
|
path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")})
|
||||||
|
|
||||||
|
|
||||||
def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn,
|
def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn,
|
||||||
hostip, hostname, dnspass, realm, domainguid, hostguid):
|
hostip, hostname, dnspass, realm, domainguid, hostguid):
|
||||||
"""Write out a DNS zone file, from the info in the current database."""
|
"""Write out a DNS zone file, from the info in the current database.
|
||||||
|
|
||||||
|
:param path: Path of the new file.
|
||||||
|
:param setup_path": Setup path function.
|
||||||
|
:param samdb: SamDB object
|
||||||
|
:param dnsdomain: DNS Domain name
|
||||||
|
:param domaindn: DN of the Domain
|
||||||
|
:param hostip: Local IP
|
||||||
|
:param hostname: Local hostname
|
||||||
|
:param dnspass: Password for DNS
|
||||||
|
:param realm: Realm name
|
||||||
|
:param domainguid: GUID of the domain.
|
||||||
|
:param hostguid: GUID of the host.
|
||||||
|
"""
|
||||||
|
|
||||||
setup_file(setup_path("provision.zone"), path, {
|
setup_file(setup_path("provision.zone"), path, {
|
||||||
"DNSPASS_B64": b64encode(dnspass),
|
"DNSPASS_B64": b64encode(dnspass),
|
||||||
@ -795,7 +843,14 @@ def provision_ldapbase(setup_dir, message, paths):
|
|||||||
|
|
||||||
|
|
||||||
def load_schema(setup_path, samdb, schemadn, netbiosname, configdn):
|
def load_schema(setup_path, samdb, schemadn, netbiosname, configdn):
|
||||||
"""Load schema."""
|
"""Load schema.
|
||||||
|
|
||||||
|
:param samdb: Load a schema into a SamDB.
|
||||||
|
:param setup_path: Setup path function.
|
||||||
|
:param schemadn: DN of the schema
|
||||||
|
:param netbiosname: NetBIOS name of the host.
|
||||||
|
:param configdn: DN of the configuration
|
||||||
|
"""
|
||||||
schema_data = open(setup_path("schema.ldif"), 'r').read()
|
schema_data = open(setup_path("schema.ldif"), 'r').read()
|
||||||
schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
|
schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
|
||||||
schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
|
schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
|
||||||
@ -807,32 +862,3 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn):
|
|||||||
"DEFAULTSITE": DEFAULTSITE})
|
"DEFAULTSITE": DEFAULTSITE})
|
||||||
samdb.attach_schema_from_ldif(head_data, schema_data)
|
samdb.attach_schema_from_ldif(head_data, schema_data)
|
||||||
|
|
||||||
|
|
||||||
def join_domain(domain, netbios_name, join_type, creds):
|
|
||||||
ctx = NetContext(creds)
|
|
||||||
joindom = object()
|
|
||||||
joindom.domain = domain
|
|
||||||
joindom.join_type = join_type
|
|
||||||
joindom.netbios_name = netbios_name
|
|
||||||
if not ctx.JoinDomain(joindom):
|
|
||||||
raise Exception("Domain Join failed: " + joindom.error_string)
|
|
||||||
|
|
||||||
|
|
||||||
def vampire(domain, session_info, credentials, message):
|
|
||||||
"""Vampire a remote domain.
|
|
||||||
|
|
||||||
Session info and credentials are required for for
|
|
||||||
access to our local database (might be remote ldap)
|
|
||||||
"""
|
|
||||||
ctx = NetContext(credentials)
|
|
||||||
machine_creds = Credentials()
|
|
||||||
machine_creds.set_domain(form.domain)
|
|
||||||
if not machine_creds.set_machine_account():
|
|
||||||
raise Exception("Failed to access domain join information!")
|
|
||||||
vampire_ctx.machine_creds = machine_creds
|
|
||||||
vampire_ctx.session_info = session_info
|
|
||||||
if not ctx.SamSyncLdb(vampire_ctx):
|
|
||||||
raise Exception("Migration of remote domain to Samba failed: %s " % vampire_ctx.error_string)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,14 +25,33 @@ REGISTRY_DB_VERSION = 1
|
|||||||
import os
|
import os
|
||||||
import tdb
|
import tdb
|
||||||
|
|
||||||
class Registry:
|
|
||||||
"""Simple read-only support for reading the Samba3 registry."""
|
class TdbDatabase:
|
||||||
|
"""Simple Samba 3 TDB database reader."""
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
|
"""Open a file.
|
||||||
|
|
||||||
|
:param file: Path of the file to open.
|
||||||
|
"""
|
||||||
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
||||||
|
self._check_version()
|
||||||
|
|
||||||
|
def _check_version(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
"""Close resources associated with this object."""
|
||||||
self.tdb.close()
|
self.tdb.close()
|
||||||
|
|
||||||
|
|
||||||
|
class Registry(TdbDatabase):
|
||||||
|
"""Simple read-only support for reading the Samba3 registry.
|
||||||
|
|
||||||
|
:note: This object uses the same syntax for registry key paths as
|
||||||
|
Samba 3. This particular format uses forward slashes for key path
|
||||||
|
separators and abbreviations for the predefined key names.
|
||||||
|
e.g.: HKLM/Software/Bar.
|
||||||
|
"""
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"""Return the number of keys."""
|
"""Return the number of keys."""
|
||||||
return len(self.keys())
|
return len(self.keys())
|
||||||
@ -42,6 +61,11 @@ class Registry:
|
|||||||
return [k.rstrip("\x00") for k in self.tdb.keys() if not k.startswith(REGISTRY_VALUE_PREFIX)]
|
return [k.rstrip("\x00") for k in self.tdb.keys() if not k.startswith(REGISTRY_VALUE_PREFIX)]
|
||||||
|
|
||||||
def subkeys(self, key):
|
def subkeys(self, key):
|
||||||
|
"""Retrieve the subkeys for the specified key.
|
||||||
|
|
||||||
|
:param key: Key path.
|
||||||
|
:return: list with key names
|
||||||
|
"""
|
||||||
data = self.tdb.get("%s\x00" % key)
|
data = self.tdb.get("%s\x00" % key)
|
||||||
if data is None:
|
if data is None:
|
||||||
return []
|
return []
|
||||||
@ -54,7 +78,11 @@ class Registry:
|
|||||||
return keys
|
return keys
|
||||||
|
|
||||||
def values(self, key):
|
def values(self, key):
|
||||||
"""Return a dictionary with the values set for a specific key."""
|
"""Return a dictionary with the values set for a specific key.
|
||||||
|
|
||||||
|
:param key: Key to retrieve values for.
|
||||||
|
:return: Dictionary with value names as key, tuple with type and
|
||||||
|
data as value."""
|
||||||
data = self.tdb.get("%s/%s\x00" % (REGISTRY_VALUE_PREFIX, key))
|
data = self.tdb.get("%s/%s\x00" % (REGISTRY_VALUE_PREFIX, key))
|
||||||
if data is None:
|
if data is None:
|
||||||
return {}
|
return {}
|
||||||
@ -77,9 +105,14 @@ class Registry:
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class PolicyDatabase:
|
class PolicyDatabase(TdbDatabase):
|
||||||
|
"""Samba 3 Account Policy database reader."""
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
"""Open a policy database
|
||||||
|
|
||||||
|
:param file: Path to the file to open.
|
||||||
|
"""
|
||||||
|
super(PolicyDatabase, self).__init__(file)
|
||||||
self.min_password_length = self.tdb.fetch_uint32("min password length\x00")
|
self.min_password_length = self.tdb.fetch_uint32("min password length\x00")
|
||||||
self.password_history = self.tdb.fetch_uint32("password history\x00")
|
self.password_history = self.tdb.fetch_uint32("password history\x00")
|
||||||
self.user_must_logon_to_change_password = self.tdb.fetch_uint32("user must logon to change pasword\x00")
|
self.user_must_logon_to_change_password = self.tdb.fetch_uint32("user must logon to change pasword\x00")
|
||||||
@ -93,9 +126,6 @@ class PolicyDatabase:
|
|||||||
|
|
||||||
# FIXME: Read privileges as well
|
# FIXME: Read privileges as well
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.tdb.close()
|
|
||||||
|
|
||||||
|
|
||||||
GROUPDB_DATABASE_VERSION_V1 = 1 # native byte format.
|
GROUPDB_DATABASE_VERSION_V1 = 1 # native byte format.
|
||||||
GROUPDB_DATABASE_VERSION_V2 = 2 # le format.
|
GROUPDB_DATABASE_VERSION_V2 = 2 # le format.
|
||||||
@ -108,17 +138,27 @@ GROUP_PREFIX = "UNIXGROUP/"
|
|||||||
# hanging of the member as key.
|
# hanging of the member as key.
|
||||||
MEMBEROF_PREFIX = "MEMBEROF/"
|
MEMBEROF_PREFIX = "MEMBEROF/"
|
||||||
|
|
||||||
class GroupMappingDatabase:
|
class GroupMappingDatabase(TdbDatabase):
|
||||||
def __init__(self, file):
|
"""Samba 3 group mapping database reader."""
|
||||||
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
def _check_version(self):
|
||||||
assert self.tdb.fetch_int32("INFO/version\x00") in (GROUPDB_DATABASE_VERSION_V1, GROUPDB_DATABASE_VERSION_V2)
|
assert self.tdb.fetch_int32("INFO/version\x00") in (GROUPDB_DATABASE_VERSION_V1, GROUPDB_DATABASE_VERSION_V2)
|
||||||
|
|
||||||
def groupsids(self):
|
def groupsids(self):
|
||||||
|
"""Retrieve the SIDs for the groups in this database.
|
||||||
|
|
||||||
|
:return: List with sids as strings.
|
||||||
|
"""
|
||||||
for k in self.tdb.keys():
|
for k in self.tdb.keys():
|
||||||
if k.startswith(GROUP_PREFIX):
|
if k.startswith(GROUP_PREFIX):
|
||||||
yield k[len(GROUP_PREFIX):].rstrip("\0")
|
yield k[len(GROUP_PREFIX):].rstrip("\0")
|
||||||
|
|
||||||
def get_group(self, sid):
|
def get_group(self, sid):
|
||||||
|
"""Retrieve the group mapping information for a particular group.
|
||||||
|
|
||||||
|
:param sid: SID of the group
|
||||||
|
:return: None if the group can not be found, otherwise
|
||||||
|
a tuple with gid, sid_name_use, the NT name and comment.
|
||||||
|
"""
|
||||||
data = self.tdb.get("%s%s\0" % (GROUP_PREFIX, sid))
|
data = self.tdb.get("%s%s\0" % (GROUP_PREFIX, sid))
|
||||||
if data is None:
|
if data is None:
|
||||||
return data
|
return data
|
||||||
@ -128,13 +168,11 @@ class GroupMappingDatabase:
|
|||||||
return (gid, sid_name_use, nt_name, comment)
|
return (gid, sid_name_use, nt_name, comment)
|
||||||
|
|
||||||
def aliases(self):
|
def aliases(self):
|
||||||
|
"""Retrieve the aliases in this database."""
|
||||||
for k in self.tdb.keys():
|
for k in self.tdb.keys():
|
||||||
if k.startswith(MEMBEROF_PREFIX):
|
if k.startswith(MEMBEROF_PREFIX):
|
||||||
yield k[len(MEMBEROF_PREFIX):].rstrip("\0")
|
yield k[len(MEMBEROF_PREFIX):].rstrip("\0")
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.tdb.close()
|
|
||||||
|
|
||||||
|
|
||||||
# High water mark keys
|
# High water mark keys
|
||||||
IDMAP_HWM_GROUP = "GROUP HWM\0"
|
IDMAP_HWM_GROUP = "GROUP HWM\0"
|
||||||
@ -146,22 +184,29 @@ IDMAP_USER_PREFIX = "UID "
|
|||||||
# idmap version determines auto-conversion
|
# idmap version determines auto-conversion
|
||||||
IDMAP_VERSION_V2 = 2
|
IDMAP_VERSION_V2 = 2
|
||||||
|
|
||||||
class IdmapDatabase:
|
class IdmapDatabase(TdbDatabase):
|
||||||
def __init__(self, file):
|
"""Samba 3 ID map database reader."""
|
||||||
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
def _check_version(self):
|
||||||
assert self.tdb.fetch_int32("IDMAP_VERSION\0") == IDMAP_VERSION_V2
|
assert self.tdb.fetch_int32("IDMAP_VERSION\0") == IDMAP_VERSION_V2
|
||||||
|
|
||||||
def uids(self):
|
def uids(self):
|
||||||
|
"""Retrieve a list of all uids in this database."""
|
||||||
for k in self.tdb.keys():
|
for k in self.tdb.keys():
|
||||||
if k.startswith(IDMAP_USER_PREFIX):
|
if k.startswith(IDMAP_USER_PREFIX):
|
||||||
yield int(k[len(IDMAP_USER_PREFIX):].rstrip("\0"))
|
yield int(k[len(IDMAP_USER_PREFIX):].rstrip("\0"))
|
||||||
|
|
||||||
def gids(self):
|
def gids(self):
|
||||||
|
"""Retrieve a list of all gids in this database."""
|
||||||
for k in self.tdb.keys():
|
for k in self.tdb.keys():
|
||||||
if k.startswith(IDMAP_GROUP_PREFIX):
|
if k.startswith(IDMAP_GROUP_PREFIX):
|
||||||
yield int(k[len(IDMAP_GROUP_PREFIX):].rstrip("\0"))
|
yield int(k[len(IDMAP_GROUP_PREFIX):].rstrip("\0"))
|
||||||
|
|
||||||
def get_user_sid(self, uid):
|
def get_user_sid(self, uid):
|
||||||
|
"""Retrieve the SID associated with a particular uid.
|
||||||
|
|
||||||
|
:param uid: UID to retrieve SID for.
|
||||||
|
:return: A SID or None if no mapping was found.
|
||||||
|
"""
|
||||||
data = self.tdb.get("%s%d\0" % (IDMAP_USER_PREFIX, uid))
|
data = self.tdb.get("%s%d\0" % (IDMAP_USER_PREFIX, uid))
|
||||||
if data is None:
|
if data is None:
|
||||||
return data
|
return data
|
||||||
@ -174,19 +219,15 @@ class IdmapDatabase:
|
|||||||
return data.rstrip("\0")
|
return data.rstrip("\0")
|
||||||
|
|
||||||
def get_user_hwm(self):
|
def get_user_hwm(self):
|
||||||
|
"""Obtain the user high-water mark."""
|
||||||
return self.tdb.fetch_uint32(IDMAP_HWM_USER)
|
return self.tdb.fetch_uint32(IDMAP_HWM_USER)
|
||||||
|
|
||||||
def get_group_hwm(self):
|
def get_group_hwm(self):
|
||||||
|
"""Obtain the group high-water mark."""
|
||||||
return self.tdb.fetch_uint32(IDMAP_HWM_GROUP)
|
return self.tdb.fetch_uint32(IDMAP_HWM_GROUP)
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.tdb.close()
|
|
||||||
|
|
||||||
|
|
||||||
class SecretsDatabase:
|
|
||||||
def __init__(self, file):
|
|
||||||
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
|
||||||
|
|
||||||
|
class SecretsDatabase(TdbDatabase):
|
||||||
def get_auth_password(self):
|
def get_auth_password(self):
|
||||||
return self.tdb.get("SECRETS/AUTH_PASSWORD")
|
return self.tdb.get("SECRETS/AUTH_PASSWORD")
|
||||||
|
|
||||||
@ -241,16 +282,12 @@ class SecretsDatabase:
|
|||||||
def get_sid(self, host):
|
def get_sid(self, host):
|
||||||
return self.tdb.get("SECRETS/SID/%s" % host.upper())
|
return self.tdb.get("SECRETS/SID/%s" % host.upper())
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.tdb.close()
|
|
||||||
|
|
||||||
|
|
||||||
SHARE_DATABASE_VERSION_V1 = 1
|
SHARE_DATABASE_VERSION_V1 = 1
|
||||||
SHARE_DATABASE_VERSION_V2 = 2
|
SHARE_DATABASE_VERSION_V2 = 2
|
||||||
|
|
||||||
class ShareInfoDatabase:
|
class ShareInfoDatabase(TdbDatabase):
|
||||||
def __init__(self, file):
|
def _check_version(self):
|
||||||
self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
|
|
||||||
assert self.tdb.fetch_int32("INFO/version\0") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2)
|
assert self.tdb.fetch_int32("INFO/version\0") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2)
|
||||||
|
|
||||||
def get_secdesc(self, name):
|
def get_secdesc(self, name):
|
||||||
@ -258,9 +295,6 @@ class ShareInfoDatabase:
|
|||||||
# FIXME: Run ndr_pull_security_descriptor
|
# FIXME: Run ndr_pull_security_descriptor
|
||||||
return secdesc
|
return secdesc
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.tdb.close()
|
|
||||||
|
|
||||||
|
|
||||||
class Shares:
|
class Shares:
|
||||||
def __init__(self, lp, shareinfo):
|
def __init__(self, lp, shareinfo):
|
||||||
|
@ -20,13 +20,20 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
"""Convenience functions for using the SAM."""
|
||||||
|
|
||||||
import samba
|
import samba
|
||||||
import misc
|
import misc
|
||||||
import ldb
|
import ldb
|
||||||
|
|
||||||
class SamDB(samba.Ldb):
|
class SamDB(samba.Ldb):
|
||||||
|
"""The SAM database."""
|
||||||
def __init__(self, url=None, session_info=None, credentials=None,
|
def __init__(self, url=None, session_info=None, credentials=None,
|
||||||
modules_dir=None, lp=None):
|
modules_dir=None, lp=None):
|
||||||
|
"""Open the Sam Database.
|
||||||
|
|
||||||
|
:param url: URL of the database.
|
||||||
|
"""
|
||||||
super(SamDB, self).__init__(session_info=session_info, credentials=credentials,
|
super(SamDB, self).__init__(session_info=session_info, credentials=credentials,
|
||||||
modules_dir=modules_dir, lp=lp)
|
modules_dir=modules_dir, lp=lp)
|
||||||
assert misc.dsdb_set_global_schema(self) == 0
|
assert misc.dsdb_set_global_schema(self) == 0
|
||||||
@ -47,7 +54,12 @@ description: %s
|
|||||||
self.add(msg[1])
|
self.add(msg[1])
|
||||||
|
|
||||||
def setup_name_mapping(self, domaindn, sid, unixname):
|
def setup_name_mapping(self, domaindn, sid, unixname):
|
||||||
"""Setup a mapping between a sam name and a unix name."""
|
"""Setup a mapping between a sam name and a unix name.
|
||||||
|
|
||||||
|
:param domaindn: DN of the domain.
|
||||||
|
:param sid: SID of the NT-side of the mapping.
|
||||||
|
:param unixname: Unix name to map to.
|
||||||
|
"""
|
||||||
res = self.search(ldb.Dn(self, domaindn), ldb.SCOPE_SUBTREE,
|
res = self.search(ldb.Dn(self, domaindn), ldb.SCOPE_SUBTREE,
|
||||||
"objectSid=%s" % sid, ["dn"])
|
"objectSid=%s" % sid, ["dn"])
|
||||||
assert len(res) == 1, "Failed to find record for objectSid %s" % sid
|
assert len(res) == 1, "Failed to find record for objectSid %s" % sid
|
||||||
@ -61,7 +73,7 @@ unixName: %s
|
|||||||
self.modify(self.parse_ldif(mod).next()[1])
|
self.modify(self.parse_ldif(mod).next()[1])
|
||||||
|
|
||||||
def enable_account(self, user_dn):
|
def enable_account(self, user_dn):
|
||||||
"""enable the account.
|
"""Enable an account.
|
||||||
|
|
||||||
:param user_dn: Dn of the account to enable.
|
:param user_dn: Dn of the account to enable.
|
||||||
"""
|
"""
|
||||||
@ -75,10 +87,15 @@ changetype: modify
|
|||||||
replace: userAccountControl
|
replace: userAccountControl
|
||||||
userAccountControl: %u
|
userAccountControl: %u
|
||||||
""" % (user_dn, userAccountControl)
|
""" % (user_dn, userAccountControl)
|
||||||
self.modify(mod)
|
self.modify_ldif(mod)
|
||||||
|
|
||||||
def newuser(self, username, unixname, password, message):
|
def newuser(self, username, unixname, password):
|
||||||
"""add a new user record"""
|
"""add a new user record.
|
||||||
|
|
||||||
|
:param username: Name of the new user.
|
||||||
|
:param unixname: Name of the unix user to map to.
|
||||||
|
:param password: Password for the new user
|
||||||
|
"""
|
||||||
# connect to the sam
|
# connect to the sam
|
||||||
self.transaction_start()
|
self.transaction_start()
|
||||||
|
|
||||||
@ -97,13 +114,13 @@ userAccountControl: %u
|
|||||||
# the new user record. note the reliance on the samdb module to fill
|
# the new user record. note the reliance on the samdb module to fill
|
||||||
# in a sid, guid etc
|
# in a sid, guid etc
|
||||||
#
|
#
|
||||||
ldif = """
|
# now the real work
|
||||||
dn: %s
|
self.add({"dn": user_dn,
|
||||||
sAMAccountName: %s
|
"sAMAccountName": username,
|
||||||
unixName: %s
|
"unixName": unixname,
|
||||||
sambaPassword: %s
|
"sambaPassword": password,
|
||||||
objectClass: user
|
"objectClass": "user"})
|
||||||
""" % (user_dn, username, unixname, password)
|
|
||||||
# add the user to the users group as well
|
# add the user to the users group as well
|
||||||
modgroup = """
|
modgroup = """
|
||||||
dn: %s
|
dn: %s
|
||||||
@ -113,11 +130,6 @@ member: %s
|
|||||||
""" % (dom_users, user_dn)
|
""" % (dom_users, user_dn)
|
||||||
|
|
||||||
|
|
||||||
# now the real work
|
|
||||||
message("Adding user %s" % user_dn)
|
|
||||||
self.add(ldif)
|
|
||||||
|
|
||||||
message("Modifying group %s" % dom_users)
|
|
||||||
self.modify(modgroup)
|
self.modify(modgroup)
|
||||||
|
|
||||||
# modify the userAccountControl to remove the disabled bit
|
# modify the userAccountControl to remove the disabled bit
|
||||||
@ -125,6 +137,10 @@ member: %s
|
|||||||
self.transaction_commit()
|
self.transaction_commit()
|
||||||
|
|
||||||
def set_domain_sid(self, sid):
|
def set_domain_sid(self, sid):
|
||||||
|
"""Change the domain SID used by this SamDB.
|
||||||
|
|
||||||
|
:param sid: The new domain sid to use.
|
||||||
|
"""
|
||||||
misc.samdb_set_domain_sid(self, sid)
|
misc.samdb_set_domain_sid(self, sid)
|
||||||
|
|
||||||
def attach_schema_from_ldif(self, pf, df):
|
def attach_schema_from_ldif(self, pf, df):
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
"""Samba Python tests."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import ldb
|
import ldb
|
||||||
import samba
|
import samba
|
||||||
@ -24,11 +26,13 @@ import tempfile
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
class LdbTestCase(unittest.TestCase):
|
class LdbTestCase(unittest.TestCase):
|
||||||
|
"""Trivial test case for running tests against a LDB."""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.filename = os.tempnam()
|
self.filename = os.tempnam()
|
||||||
self.ldb = samba.Ldb(self.filename)
|
self.ldb = samba.Ldb(self.filename)
|
||||||
|
|
||||||
def set_modules(self, modules=[]):
|
def set_modules(self, modules=[]):
|
||||||
|
"""Change the modules for this Ldb."""
|
||||||
m = ldb.Message()
|
m = ldb.Message()
|
||||||
m.dn = ldb.Dn(self.ldb, "@MODULES")
|
m.dn = ldb.Dn(self.ldb, "@MODULES")
|
||||||
m["@LIST"] = ",".join(modules)
|
m["@LIST"] = ",".join(modules)
|
||||||
|
Reference in New Issue
Block a user