From aa0a06f13c44e0eca0b3f2f0c34f0f7995b87159 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 23 Dec 2007 19:19:41 -0600 Subject: r26570: - Trim size of the swig-generated Python bindings by removing a bunch of {}'s. - Start working on Python equivalents for various EJS tests. - Fix regression in argument order for reg_diff_apply() in EJS bindings. (This used to be commit c550c03372cb260b78f6a6c132e70571bc4cb852) --- source4/scripting/python/samba/samba3.py | 224 +++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 source4/scripting/python/samba/samba3.py (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py new file mode 100644 index 0000000000..d8289ae756 --- /dev/null +++ b/source4/scripting/python/samba/samba3.py @@ -0,0 +1,224 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2007 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +"""Support for reading Samba 3 data files.""" + +REGISTRY_VALUE_PREFIX = "SAMBA_REGVAL" +REGISTRY_DB_VERSION = 1 + +import tdb + +class Registry: + """Simple read-only support for reading the Samba3 registry.""" + def __init__(self, file): + self.tdb = tdb.Tdb(file) + + def __len__(self): + """Return the number of keys.""" + return len(self.keys()) + + def keys(self): + """Return list with all the keys.""" + return [k.rstrip("\x00") for k in self.tdb.keys() if not k.startswith(REGISTRY_VALUE_PREFIX)] + + def subkeys(self, key): + data = self.tdb.get(key) + if data is None: + return [] + # FIXME: Parse data + return [] + + def values(self, key): + """Return a dictionary with the values set for a specific key.""" + data = self.tdb.get("%s/%s" % (REGISTRY_VALUE_PREFIX, key)) + if data is None: + return {} + # FIXME: Parse data + return {} + + +class PolicyDatabase: + def __init__(self, file): + self.tdb = tdb.Tdb(file) + self.min_password_length = tdb.fetch_uint32("min password length") + self.user_must_logon_to_change_password = tdb.fetch_uint32("password history") + self.user_must_logon_to_change_password = tdb.fetch_uint32("user must logon to change pasword") + self.maximum_password_age = tdb.fetch_uint32("maximum password age") + self.minimum_password_age = tdb.fetch_uint32("minimum password age") + self.lockout_duration = tdb.fetch_uint32("lockout duration") + self.reset_count_minutes = tdb.fetch_uint32("reset count minutes") + self.bad_lockout_minutes = tdb.fetch_uint32("bad lockout minutes") + self.disconnect_time = tdb.fetch_uint32("disconnect time") + self.refuse_machine_password_change = tdb.fetch_uint32("refuse machine password change") + + # FIXME: Read privileges as well + + +GROUPDB_DATABASE_VERSION_V1 = 1 # native byte format. +GROUPDB_DATABASE_VERSION_V2 = 2 # le format. + +GROUP_PREFIX = "UNIXGROUP/" + +# Alias memberships are stored reverse, as memberships. The performance +# critical operation is to determine the aliases a SID is member of, not +# listing alias members. So we store a list of alias SIDs a SID is member of +# hanging of the member as key. +MEMBEROF_PREFIX = "MEMBEROF/" + +class GroupMappingDatabase: + def __init__(self, file): + self.tdb = tdb.Tdb(file) + + +# High water mark keys +HWM_GROUP = "GROUP HWM" +HWM_USER = "USER HWM" + +# idmap version determines auto-conversion +IDMAP_VERSION = 2 + +class IdmapDatabase: + def __init__(self, file): + self.tdb = tdb.Tdb(file) + assert self.tdb.fetch_int32("IDMAP_VERSION") == IDMAP_VERSION + + +class SecretsDatabase: + def __init__(self, file): + self.tdb = tdb.Tdb(file) + self.domains = {} + for k, v in self.tdb.items(): + if k == "SECRETS/AUTH_PASSWORD": + self.auth_password = v + elif k == "SECRETS/AUTH_DOMAIN": + self.auth_domain = v + elif k == "SECRETS/AUTH_USER": + self.auth_user = v + elif k.startswith("SECRETS/SID/"): + pass # FIXME + elif k.startswith("SECRETS/DOMGUID/"): + pass # FIXME + elif k.startswith("SECRETS/LDAP_BIND_PW/"): + pass # FIXME + elif k.startswith("SECRETS/AFS_KEYFILE/"): + pass # FIXME + elif k.startswith("SECRETS/MACHINE_SEC_CHANNEL_TYPE/"): + pass # FIXME + elif k.startswith("SECRETS/MACHINE_LAST_CHANGE_TIME/"): + pass # FIXME + elif k.startswith("SECRETS/MACHINE_PASSWORD/"): + pass # FIXME + elif k.startswith("SECRETS/$MACHINE.ACC/"): + pass # FIXME + elif k.startswith("SECRETS/$DOMTRUST.ACC/"): + pass # FIXME + elif k == "INFO/random_seed": + self.random_seed = v + else: + raise "Unknown key %s in secrets database" % k + +SHARE_DATABASE_VERSION_V1 = 1 +SHARE_DATABASE_VERSION_V2 = 2 + +class ShareInfoDatabase: + def __init__(self, file): + self.tdb = tdb.Tdb(file) + assert self.tdb.fetch_int32("INFO/version") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2) + + def get_secdesc(self, name): + secdesc = self.tdb.get("SECDESC/%s" % name) + # FIXME: Run ndr_pull_security_descriptor + + +ACB_DISABLED = 0x00000001 +ACB_HOMDIRREQ = 0x00000002 +ACB_PWNOTREQ = 0x00000004 +ACB_TEMPDUP = 0x00000008 +ACB_NORMAL = 0x00000010 +ACB_MNS = 0x00000020 +ACB_DOMTRUST = 0x00000040 +ACB_WSTRUST = 0x00000080 +ACB_SVRTRUST = 0x00000100 +ACB_PWNOEXP = 0x00000200 +ACB_AUTOLOCK = 0x00000400 +ACB_ENC_TXT_PWD_ALLOWED = 0x00000800 +ACB_SMARTCARD_REQUIRED = 0x00001000 +ACB_TRUSTED_FOR_DELEGATION = 0x00002000 +ACB_NOT_DELEGATED = 0x00004000 +ACB_USE_DES_KEY_ONLY = 0x00008000 +ACB_DONT_REQUIRE_PREAUTH = 0x00010000 +ACB_PW_EXPIRED = 0x00020000 +ACB_NO_AUTH_DATA_REQD = 0x00080000 + +acb_info_mapping = { + 'N': ACB_PWNOTREQ, # 'N'o password. + 'D': ACB_DISABLED, # 'D'isabled. + 'H': ACB_HOMDIRREQ, # 'H'omedir required. + 'T': ACB_TEMPDUP, # 'T'emp account. + 'U': ACB_NORMAL, # 'U'ser account (normal). + 'M': ACB_MNS, # 'M'NS logon user account. What is this ? + 'W': ACB_WSTRUST, # 'W'orkstation account. + 'S': ACB_SVRTRUST, # 'S'erver account. + 'L': ACB_AUTOLOCK, # 'L'ocked account. + 'X': ACB_PWNOEXP, # No 'X'piry on password + 'I': ACB_DOMTRUST, # 'I'nterdomain trust account. + ' ': 0 + } + + +class Smbpasswd: + def __init__(self, file): + pass + + +class TdbSam: + def __init__(self, file): + self.tdb = tdb.Tdb(file) + + +class WinsDatabase: + def __init__(self, file): + pass + + +class Samba3: + def __init__(self, smbconfpath, libdir): + self.smbconfpath = smbconfpath + self.libdir = libdir + + def get_policy_db(self): + return PolicyDatabase(os.path.join(libdir, "account_policy.tdb")) + + def get_registry(self): + return Registry(os.path.join(libdir, "registry.tdb")) + + def get_secrets_db(self): + return SecretsDatabase(os.path.join(libdir, "secrets.tdb")) + + def get_shares_db(self): + return ShareInfoDatabase(os.path.join(libdir, "share_info.tdb")) + + def get_idmap_db(self): + return IdmapDatabase(os.path.join(libdir, "winbindd_idmap.tdb")) + + def get_wins_db(self): + return WinsDatabase(os.path.join(libdir, "wins.dat")) + + def get_groupmapping_db(self): + return GroupMappingDatabase(os.path.join(libdir, "group_mapping.tdb")) -- cgit From 59efa6e5d074f9f0fbc0b5fd2b5bcdc9d78b95e3 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 24 Dec 2007 11:02:52 -0600 Subject: r26585: Fix samba3.python tests. (This used to be commit 231ec0777b7d1fb1297e3a974871b8735a386cfa) --- source4/scripting/python/samba/samba3.py | 42 +++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index d8289ae756..8225eacd58 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -22,12 +22,16 @@ REGISTRY_VALUE_PREFIX = "SAMBA_REGVAL" REGISTRY_DB_VERSION = 1 +import os import tdb class Registry: """Simple read-only support for reading the Samba3 registry.""" def __init__(self, file): - self.tdb = tdb.Tdb(file) + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) + + def close(self): + self.tdb.close() def __len__(self): """Return the number of keys.""" @@ -38,7 +42,7 @@ class Registry: return [k.rstrip("\x00") for k in self.tdb.keys() if not k.startswith(REGISTRY_VALUE_PREFIX)] def subkeys(self, key): - data = self.tdb.get(key) + data = self.tdb.get("%s\x00" % key) if data is None: return [] # FIXME: Parse data @@ -46,7 +50,7 @@ class Registry: def values(self, key): """Return a dictionary with the values set for a specific key.""" - data = self.tdb.get("%s/%s" % (REGISTRY_VALUE_PREFIX, key)) + data = self.tdb.get("%s/%s\x00" % (REGISTRY_VALUE_PREFIX, key)) if data is None: return {} # FIXME: Parse data @@ -55,17 +59,17 @@ class Registry: class PolicyDatabase: def __init__(self, file): - self.tdb = tdb.Tdb(file) - self.min_password_length = tdb.fetch_uint32("min password length") - self.user_must_logon_to_change_password = tdb.fetch_uint32("password history") - self.user_must_logon_to_change_password = tdb.fetch_uint32("user must logon to change pasword") - self.maximum_password_age = tdb.fetch_uint32("maximum password age") - self.minimum_password_age = tdb.fetch_uint32("minimum password age") - self.lockout_duration = tdb.fetch_uint32("lockout duration") - self.reset_count_minutes = tdb.fetch_uint32("reset count minutes") - self.bad_lockout_minutes = tdb.fetch_uint32("bad lockout minutes") - self.disconnect_time = tdb.fetch_uint32("disconnect time") - self.refuse_machine_password_change = tdb.fetch_uint32("refuse machine password change") + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) + self.min_password_length = self.tdb.fetch_uint32("min password length\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.maximum_password_age = self.tdb.fetch_uint32("maximum password age\x00") + self.minimum_password_age = self.tdb.fetch_uint32("minimum password age\x00") + self.lockout_duration = self.tdb.fetch_uint32("lockout duration\x00") + self.reset_count_minutes = self.tdb.fetch_uint32("reset count minutes\x00") + self.bad_lockout_minutes = self.tdb.fetch_uint32("bad lockout minutes\x00") + self.disconnect_time = self.tdb.fetch_int32("disconnect time\x00") + self.refuse_machine_password_change = self.tdb.fetch_uint32("refuse machine password change\x00") # FIXME: Read privileges as well @@ -83,7 +87,7 @@ MEMBEROF_PREFIX = "MEMBEROF/" class GroupMappingDatabase: def __init__(self, file): - self.tdb = tdb.Tdb(file) + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) # High water mark keys @@ -95,13 +99,13 @@ IDMAP_VERSION = 2 class IdmapDatabase: def __init__(self, file): - self.tdb = tdb.Tdb(file) + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) assert self.tdb.fetch_int32("IDMAP_VERSION") == IDMAP_VERSION class SecretsDatabase: def __init__(self, file): - self.tdb = tdb.Tdb(file) + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) self.domains = {} for k, v in self.tdb.items(): if k == "SECRETS/AUTH_PASSWORD": @@ -138,7 +142,7 @@ SHARE_DATABASE_VERSION_V2 = 2 class ShareInfoDatabase: def __init__(self, file): - self.tdb = tdb.Tdb(file) + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) assert self.tdb.fetch_int32("INFO/version") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2) def get_secdesc(self, name): @@ -189,7 +193,7 @@ class Smbpasswd: class TdbSam: def __init__(self, file): - self.tdb = tdb.Tdb(file) + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) class WinsDatabase: -- cgit From 95b1f554b2c57a9f975a0cc27ca51bec6c7594d6 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 24 Dec 2007 13:04:33 -0600 Subject: r26587: Fix reading Samba 3 WINS database and initial work on group db, aliases and secrets. (This used to be commit c7c4cf258ac7975b409d26c9386838d4780c756f) --- source4/scripting/python/samba/samba3.py | 160 +++++++++++++++++++++++++------ 1 file changed, 129 insertions(+), 31 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index 8225eacd58..509ee29c1d 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -73,6 +73,9 @@ class PolicyDatabase: # FIXME: Read privileges as well + def close(self): + self.tdb.close() + GROUPDB_DATABASE_VERSION_V1 = 1 # native byte format. GROUPDB_DATABASE_VERSION_V2 = 2 # le format. @@ -88,6 +91,20 @@ MEMBEROF_PREFIX = "MEMBEROF/" class GroupMappingDatabase: def __init__(self, file): self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) + assert self.tdb.fetch_int32("INFO/version\x00") in (GROUPDB_DATABASE_VERSION_V1, GROUPDB_DATABASE_VERSION_V2) + + def groupsids(self): + for k in self.tdb.keys(): + if k.startswith(GROUP_PREFIX): + yield k[len(GROUP_PREFIX):].rstrip("\0") + + def aliases(self): + for k in self.tdb.keys(): + if k.startswith(MEMBEROF_PREFIX): + yield k[len(MEMBEROF_PREFIX):].rstrip("\0") + + def close(self): + self.tdb.close() # High water mark keys @@ -102,40 +119,56 @@ class IdmapDatabase: self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) assert self.tdb.fetch_int32("IDMAP_VERSION") == IDMAP_VERSION + def close(self): + self.tdb.close() + class SecretsDatabase: def __init__(self, file): self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) - self.domains = {} - for k, v in self.tdb.items(): - if k == "SECRETS/AUTH_PASSWORD": - self.auth_password = v - elif k == "SECRETS/AUTH_DOMAIN": - self.auth_domain = v - elif k == "SECRETS/AUTH_USER": - self.auth_user = v - elif k.startswith("SECRETS/SID/"): - pass # FIXME - elif k.startswith("SECRETS/DOMGUID/"): - pass # FIXME - elif k.startswith("SECRETS/LDAP_BIND_PW/"): - pass # FIXME - elif k.startswith("SECRETS/AFS_KEYFILE/"): - pass # FIXME - elif k.startswith("SECRETS/MACHINE_SEC_CHANNEL_TYPE/"): - pass # FIXME - elif k.startswith("SECRETS/MACHINE_LAST_CHANGE_TIME/"): - pass # FIXME - elif k.startswith("SECRETS/MACHINE_PASSWORD/"): - pass # FIXME - elif k.startswith("SECRETS/$MACHINE.ACC/"): - pass # FIXME - elif k.startswith("SECRETS/$DOMTRUST.ACC/"): - pass # FIXME - elif k == "INFO/random_seed": - self.random_seed = v - else: - raise "Unknown key %s in secrets database" % k + + def get_auth_password(self): + return self.tdb.get("SECRETS/AUTH_PASSWORD") + + def get_auth_domain(self): + return self.tdb.get("SECRETS/AUTH_DOMAIN") + + def get_auth_user(self): + return self.tdb.get("SECRETS/AUTH_USER") + + def get_dom_guid(self, host): + return self.tdb.get("SECRETS/DOMGUID/%s" % host) + + def get_ldap_bind_pw(self, host): + return self.tdb.get("SECRETS/LDAP_BIND_PW/%s" % host) + + def get_afs_keyfile(self, host): + return self.tdb.get("SECRETS/AFS_KEYFILE/%s" % host) + + def get_machine_sec_channel_type(self, host): + return self.tdb.get("SECRETS/MACHINE_SEC_CHANNEL_TYPE/%s" % host) + + def get_machine_last_change_time(self, host): + return self.tdb.get("SECRETS/MACHINE_LAST_CHANGE_TIME/%s" % host) + + def get_machine_password(self, host): + return self.tdb.get("SECRETS/MACHINE_PASSWORD/%s" % host) + + def get_machine_acc(self, host): + return self.tdb.get("SECRETS/$MACHINE.ACC/%s" % host) + + def get_domtrust_acc(self, host): + return self.tdb.get("SECRETS/$DOMTRUST.ACC/%s" % host) + + def get_random_seed(self): + return self.tdb.get("INFO/random_seed") + + def get_sid(self, host): + return self.tdb.get("SECRETS/SID/%s" % host.upper()) + + def close(self): + self.tdb.close() + SHARE_DATABASE_VERSION_V1 = 1 SHARE_DATABASE_VERSION_V2 = 2 @@ -149,6 +182,8 @@ class ShareInfoDatabase: secdesc = self.tdb.get("SECDESC/%s" % name) # FIXME: Run ndr_pull_security_descriptor + def close(self): + self.tdb.close() ACB_DISABLED = 0x00000001 ACB_HOMDIRREQ = 0x00000002 @@ -190,16 +225,79 @@ class Smbpasswd: def __init__(self, file): pass +TDBSAM_FORMAT_STRING_V0 = "ddddddBBBBBBBBBBBBddBBwdwdBwwd" +TDBSAM_FORMAT_STRING_V1 = "dddddddBBBBBBBBBBBBddBBwdwdBwwd" +TDBSAM_FORMAT_STRING_V2 = "dddddddBBBBBBBBBBBBddBBBwwdBwwd" +TDBSAM_USER_PREFIX = "USER_" + class TdbSam: def __init__(self, file): self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) + self.version = self.tdb.fetch_uint32("INFO/version") or 0 + assert self.version in (0, 1, 2) + + def usernames(self): + for k in self.tdb.keys(): + if k.startswith(TDBSAM_USER_PREFIX): + yield k[len(TDBSAM_USER_PREFIX):].rstrip("\0") + + def close(self): + self.tdb.close() + + +def shellsplit(text): + """Very simple shell-like line splitting. + + :param text: Text to split. + :return: List with parts of the line as strings. + """ + ret = list() + inquotes = False + current = "" + for c in text: + if c == "\"": + inquotes = not inquotes + elif c in ("\t", "\n", " ") and not inquotes: + ret.append(current) + current = "" + else: + current += c + if current != "": + ret.append(current) + return ret class WinsDatabase: def __init__(self, file): - pass + self.entries = {} + f = open(file, 'r') + assert f.readline().rstrip("\n") == "VERSION 1 0" + for l in f.readlines(): + if l[0] == "#": # skip comments + continue + entries = shellsplit(l.rstrip("\n")) + print entries + name = entries[0] + ttl = int(entries[1]) + i = 2 + ips = [] + while "." in entries[i]: + ips.append(entries[i]) + i+=1 + nb_flags = entries[i] + assert not name in self.entries, "Name %s exists twice" % name + self.entries[name] = (ttl, ips, nb_flags) + f.close() + + def __getitem__(self, name): + return self.entries[name] + def __len__(self): + return len(self.entries) + + def close(self): # for consistency + pass class Samba3: def __init__(self, smbconfpath, libdir): -- cgit From 8ada900ee67fc8e1a1ff94c9e5f7a50752d11017 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 24 Dec 2007 14:16:40 -0600 Subject: r26590: Parsing routines for the smbpasswd file and idmap database. (This used to be commit 0c14e16a2bc965d3319ca990089566bff98a47fe) --- source4/scripting/python/samba/samba3.py | 96 ++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index 509ee29c1d..b75b24ba34 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -108,16 +108,47 @@ class GroupMappingDatabase: # High water mark keys -HWM_GROUP = "GROUP HWM" -HWM_USER = "USER HWM" +IDMAP_HWM_GROUP = "GROUP HWM\0" +IDMAP_HWM_USER = "USER HWM\0" + +IDMAP_GROUP_PREFIX = "GID " +IDMAP_USER_PREFIX = "UID " # idmap version determines auto-conversion -IDMAP_VERSION = 2 +IDMAP_VERSION_V2 = 2 class IdmapDatabase: def __init__(self, file): self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) - assert self.tdb.fetch_int32("IDMAP_VERSION") == IDMAP_VERSION + assert self.tdb.fetch_int32("IDMAP_VERSION\0") == IDMAP_VERSION_V2 + + def uids(self): + for k in self.tdb.keys(): + if k.startswith(IDMAP_USER_PREFIX): + yield int(k[len(IDMAP_USER_PREFIX):].rstrip("\0")) + + def gids(self): + for k in self.tdb.keys(): + if k.startswith(IDMAP_GROUP_PREFIX): + yield int(k[len(IDMAP_GROUP_PREFIX):].rstrip("\0")) + + def get_user_sid(self, uid): + data = self.tdb.get("%s%d\0" % (IDMAP_USER_PREFIX, uid)) + if data is None: + return data + return data.rstrip("\0") + + def get_group_sid(self, gid): + data = self.tdb.get("%s%d\0" % (IDMAP_GROUP_PREFIX, gid)) + if data is None: + return data + return data.rstrip("\0") + + def get_user_hwm(self): + return self.tdb.fetch_uint32(IDMAP_HWM_USER) + + def get_group_hwm(self): + return self.tdb.fetch_uint32(IDMAP_HWM_GROUP) def close(self): self.tdb.close() @@ -181,6 +212,7 @@ class ShareInfoDatabase: def get_secdesc(self, name): secdesc = self.tdb.get("SECDESC/%s" % name) # FIXME: Run ndr_pull_security_descriptor + return secdesc def close(self): self.tdb.close() @@ -220,11 +252,65 @@ acb_info_mapping = { ' ': 0 } +def decode_acb(text): + assert not "[" in text and not "]" in text + ret = 0 + for x in text: + ret |= acb_info_mapping[x] + return ret -class Smbpasswd: + +class SmbpasswdFile: def __init__(self, file): + self.users = {} + f = open(file, 'r') + for l in f.readlines(): + if len(l) == 0 or l[0] == "#": + continue # Skip comments and blank lines + parts = l.split(":") + username = parts[0] + uid = int(parts[1]) + acct_ctrl = 0 + last_change_time = None + if parts[2] == "NO PASSWORD": + acct_ctrl |= ACB_PWNOTREQ + lm_password = None + elif parts[2][0] in ("*", "X"): + # No password set + lm_password = None + else: + lm_password = parts[2] + + if parts[3][0] in ("*", "X"): + # No password set + nt_password = None + else: + nt_password = parts[3] + + if parts[4][0] == '[': + assert "]" in parts[4] + acct_ctrl |= decode_acb(parts[4][1:-1]) + if parts[5].startswith("LCT-"): + last_change_time = int(parts[5][len("LCT-"):], 16) + else: # old style file + if username[-1] == "$": + acct_ctrl &= ~ACB_NORMAL + acct_ctrl |= ACB_WSTRUST + + self.users[username] = (uid, lm_password, nt_password, acct_ctrl, last_change_time) + + f.close() + + def __len__(self): + return len(self.users) + + def __getitem__(self, name): + return self.users[name] + + def close(self): # For consistency pass + TDBSAM_FORMAT_STRING_V0 = "ddddddBBBBBBBBBBBBddBBwdwdBwwd" TDBSAM_FORMAT_STRING_V1 = "dddddddBBBBBBBBBBBBddBBwdwdBwwd" TDBSAM_FORMAT_STRING_V2 = "dddddddBBBBBBBBBBBBddBBBwwdBwwd" -- cgit From 3c22677a8ce1635d7e055f954153dec4c1796b17 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 24 Dec 2007 14:16:59 -0600 Subject: r26591: Get the first bits of samba3dump to work again. (This used to be commit 3511027515f8ea860fbe46639d9169999646a297) --- source4/scripting/python/samba/samba3.py | 42 +++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index b75b24ba34..40443bd8ba 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -170,6 +170,16 @@ class SecretsDatabase: def get_dom_guid(self, host): return self.tdb.get("SECRETS/DOMGUID/%s" % host) + def ldap_dns(self): + for k in self.tdb.keys(): + if k.startswith("SECRETS/LDAP_BIND_PW/"): + yield k[len("SECRETS/LDAP_BIND_PW/"):].rstrip("\0") + + def domains(self): + for k in self.tdb.keys(): + if k.startswith("SECRETS/SID/"): + yield k[len("SECRETS/SID/"):].rstrip("\0") + def get_ldap_bind_pw(self, host): return self.tdb.get("SECRETS/LDAP_BIND_PW/%s" % host) @@ -177,10 +187,10 @@ class SecretsDatabase: return self.tdb.get("SECRETS/AFS_KEYFILE/%s" % host) def get_machine_sec_channel_type(self, host): - return self.tdb.get("SECRETS/MACHINE_SEC_CHANNEL_TYPE/%s" % host) + return self.tdb.fetch_uint32("SECRETS/MACHINE_SEC_CHANNEL_TYPE/%s" % host) def get_machine_last_change_time(self, host): - return self.tdb.get("SECRETS/MACHINE_LAST_CHANGE_TIME/%s" % host) + return self.tdb.fetch_uint32("SECRETS/MACHINE_LAST_CHANGE_TIME/%s" % host) def get_machine_password(self, host): return self.tdb.get("SECRETS/MACHINE_PASSWORD/%s" % host) @@ -191,6 +201,11 @@ class SecretsDatabase: def get_domtrust_acc(self, host): return self.tdb.get("SECRETS/$DOMTRUST.ACC/%s" % host) + def trusted_domains(self): + for k in self.tdb.keys(): + if k.startswith("SECRETS/$DOMTRUST.ACC/"): + yield k[len("SECRETS/$DOMTRUST.ACC/"):].rstrip("\0") + def get_random_seed(self): return self.tdb.get("INFO/random_seed") @@ -307,6 +322,9 @@ class SmbpasswdFile: def __getitem__(self, name): return self.users[name] + def __iter__(self): + return iter(self.entries) + def close(self): # For consistency pass @@ -363,7 +381,6 @@ class WinsDatabase: if l[0] == "#": # skip comments continue entries = shellsplit(l.rstrip("\n")) - print entries name = entries[0] ttl = int(entries[1]) i = 2 @@ -382,31 +399,34 @@ class WinsDatabase: def __len__(self): return len(self.entries) + def __iter__(self): + return iter(self.entries) + def close(self): # for consistency pass class Samba3: - def __init__(self, smbconfpath, libdir): + def __init__(self, libdir, smbconfpath): self.smbconfpath = smbconfpath self.libdir = libdir def get_policy_db(self): - return PolicyDatabase(os.path.join(libdir, "account_policy.tdb")) + return PolicyDatabase(os.path.join(self.libdir, "account_policy.tdb")) def get_registry(self): - return Registry(os.path.join(libdir, "registry.tdb")) + return Registry(os.path.join(self.libdir, "registry.tdb")) def get_secrets_db(self): - return SecretsDatabase(os.path.join(libdir, "secrets.tdb")) + return SecretsDatabase(os.path.join(self.libdir, "secrets.tdb")) def get_shares_db(self): - return ShareInfoDatabase(os.path.join(libdir, "share_info.tdb")) + return ShareInfoDatabase(os.path.join(self.libdir, "share_info.tdb")) def get_idmap_db(self): - return IdmapDatabase(os.path.join(libdir, "winbindd_idmap.tdb")) + return IdmapDatabase(os.path.join(self.libdir, "winbindd_idmap.tdb")) def get_wins_db(self): - return WinsDatabase(os.path.join(libdir, "wins.dat")) + return WinsDatabase(os.path.join(self.libdir, "wins.dat")) def get_groupmapping_db(self): - return GroupMappingDatabase(os.path.join(libdir, "group_mapping.tdb")) + return GroupMappingDatabase(os.path.join(self.libdir, "group_mapping.tdb")) -- cgit From cc30cb5e24160d107b67936d71f54645d9b3d23f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 25 Dec 2007 16:36:23 -0600 Subject: r26592: Finish fixing the samba3dump script. (This used to be commit 85679f3fc98238f90280f9f10d42550d71eeb918) --- source4/scripting/python/samba/samba3.py | 63 +++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index 40443bd8ba..d125e3164b 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -222,7 +222,7 @@ SHARE_DATABASE_VERSION_V2 = 2 class ShareInfoDatabase: def __init__(self, file): self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) - assert self.tdb.fetch_int32("INFO/version") 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): secdesc = self.tdb.get("SECDESC/%s" % name) @@ -232,6 +232,19 @@ class ShareInfoDatabase: def close(self): self.tdb.close() + +class Shares: + def __init__(self, lp, shareinfo): + self.lp = lp + self.shareinfo = shareinfo + + def __len__(self): + return len(self.lp) - 1 + + def __iter__(self): + return self.lp.__iter__() + + ACB_DISABLED = 0x00000001 ACB_HOMDIRREQ = 0x00000002 ACB_PWNOTREQ = 0x00000004 @@ -323,7 +336,7 @@ class SmbpasswdFile: return self.users[name] def __iter__(self): - return iter(self.entries) + return iter(self.users) def close(self): # For consistency pass @@ -346,6 +359,8 @@ class TdbSam: if k.startswith(TDBSAM_USER_PREFIX): yield k[len(TDBSAM_USER_PREFIX):].rstrip("\0") + __iter__ = usernames + def close(self): self.tdb.close() @@ -409,24 +424,52 @@ class Samba3: def __init__(self, libdir, smbconfpath): self.smbconfpath = smbconfpath self.libdir = libdir + import param + self.lp = param.ParamFile() + self.lp.read(self.smbconfpath) + + def libdir_path(self, path): + if path[0] == "/" or path[0] == ".": + return path + return os.path.join(self.libdir, path) + + def get_conf(self): + return self.lp + + def get_sam_db(self): + lp = self.get_conf() + backends = str(lp.get("passdb backend")).split(" ") + if backends[0].startswith("smbpasswd"): + if ":" in backends[0]: + return SmbpasswdFile(self.libdir_path(backends[0][len("smbpasswd:"):])) + return SmbpasswdFile(self.libdir_path("smbpasswd")) + elif backends[0].startswith("tdbsam"): + if ":" in backends[0]: + return TdbSam(self.libdir_path(backends[0][len("tdbsam:"):])) + return TdbSam(self.libdir_path("passdb.tdb")) + else: + raise NotImplementedError("unsupported passdb backend %s" % backends[0]) def get_policy_db(self): - return PolicyDatabase(os.path.join(self.libdir, "account_policy.tdb")) + return PolicyDatabase(self.libdir_path("account_policy.tdb")) def get_registry(self): - return Registry(os.path.join(self.libdir, "registry.tdb")) + return Registry(self.libdir_path("registry.tdb")) def get_secrets_db(self): - return SecretsDatabase(os.path.join(self.libdir, "secrets.tdb")) + return SecretsDatabase(self.libdir_path("secrets.tdb")) - def get_shares_db(self): - return ShareInfoDatabase(os.path.join(self.libdir, "share_info.tdb")) + def get_shareinfo_db(self): + return ShareInfoDatabase(self.libdir_path("share_info.tdb")) def get_idmap_db(self): - return IdmapDatabase(os.path.join(self.libdir, "winbindd_idmap.tdb")) + return IdmapDatabase(self.libdir_path("winbindd_idmap.tdb")) def get_wins_db(self): - return WinsDatabase(os.path.join(self.libdir, "wins.dat")) + return WinsDatabase(self.libdir_path("wins.dat")) + + def get_shares(self): + return Shares(self.get_conf(), self.get_shareinfo_db()) def get_groupmapping_db(self): - return GroupMappingDatabase(os.path.join(self.libdir, "group_mapping.tdb")) + return GroupMappingDatabase(self.libdir_path("group_mapping.tdb")) -- cgit From 7c146c42d2cf51e891b9f29d3b61a40f173a3b23 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 25 Dec 2007 16:36:31 -0600 Subject: r26593: - More work on the python versions of samba3dump and the samba3sam tests. - Initial work converting the upgrade code to Python. - Removed the old EJS upgrade code because it has been broken for a long time. (This used to be commit 150cf39fbd4fe088546870fb0d8f20c0d9eb4aca) --- source4/scripting/python/samba/samba3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index d125e3164b..b4261f7c74 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -167,7 +167,7 @@ class SecretsDatabase: def get_auth_user(self): return self.tdb.get("SECRETS/AUTH_USER") - def get_dom_guid(self, host): + def get_domain_guid(self, host): return self.tdb.get("SECRETS/DOMGUID/%s" % host) def ldap_dns(self): -- cgit From c4d3666ac2821518be57ca89d963f77bbddaedf4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 26 Dec 2007 20:55:05 -0600 Subject: r26607: Fix reading of values and subkeys in Samba 3 registry files. (This used to be commit e3d7454ef70d6fe9a1ce34eaf57268bd5b713ccf) --- source4/scripting/python/samba/samba3.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index b4261f7c74..df94f3503c 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -45,16 +45,36 @@ class Registry: data = self.tdb.get("%s\x00" % key) if data is None: return [] - # FIXME: Parse data - return [] + import struct + (num, ) = struct.unpack(" Date: Thu, 27 Dec 2007 03:09:49 -0600 Subject: r26608: More improvements to the upgrade code. (This used to be commit 7ea06d91f602f770f55a1171174f11b922fed8e7) --- source4/scripting/python/samba/samba3.py | 165 +++++++++++++++++++++++++++---- 1 file changed, 146 insertions(+), 19 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index df94f3503c..c9153d85cf 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -118,6 +118,15 @@ class GroupMappingDatabase: if k.startswith(GROUP_PREFIX): yield k[len(GROUP_PREFIX):].rstrip("\0") + def get_group(self, sid): + data = self.tdb.get("%s%s\0" % (GROUP_PREFIX, sid)) + if data is None: + return data + import struct + (gid, sid_name_use) = struct.unpack("username, /* B */ +# &domain_len, &sampass->domain, /* B */ +# &nt_username_len, &sampass->nt_username, /* B */ +# &fullname_len, &sampass->fullname, /* B */ +# &homedir_len, &sampass->homedir, /* B */ +# &dir_drive_len, &sampass->dir_drive, /* B */ +# &logon_script_len, &sampass->logon_script, /* B */ +# &profile_path_len, &sampass->profile_path, /* B */ +# &acct_desc_len, &sampass->acct_desc, /* B */ +# &workstations_len, &sampass->workstations, /* B */ +# &unknown_str_len, &sampass->unknown_str, /* B */ +# &munged_dial_len, &sampass->munged_dial, /* B */ +# &sampass->user_rid, /* d */ +# &sampass->group_rid, /* d */ +# &lm_pw_len, sampass->lm_pw.hash, /* B */ +# &nt_pw_len, sampass->nt_pw.hash, /* B */ +# &sampass->acct_ctrl, /* w */ +# &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */ +# &sampass->logon_divs, /* w */ +# &sampass->hours_len, /* d */ +# &hourslen, &sampass->hours, /* B */ +# &sampass->bad_password_count, /* w */ +# &sampass->logon_count, /* w */ +# &sampass->unknown_6); /* d */ +# + return user def close(self): self.tdb.close() @@ -423,7 +542,7 @@ class WinsDatabase: while "." in entries[i]: ips.append(entries[i]) i+=1 - nb_flags = entries[i] + nb_flags = int(entries[i][:-1], 16) assert not name in self.entries, "Name %s exists twice" % name self.entries[name] = (ttl, ips, nb_flags) f.close() @@ -437,6 +556,9 @@ class WinsDatabase: def __iter__(self): return iter(self.entries) + def items(self): + return self.entries.items() + def close(self): # for consistency pass @@ -459,14 +581,19 @@ class Samba3: def get_sam_db(self): lp = self.get_conf() backends = str(lp.get("passdb backend")).split(" ") - if backends[0].startswith("smbpasswd"): - if ":" in backends[0]: - return SmbpasswdFile(self.libdir_path(backends[0][len("smbpasswd:"):])) - return SmbpasswdFile(self.libdir_path("smbpasswd")) - elif backends[0].startswith("tdbsam"): - if ":" in backends[0]: - return TdbSam(self.libdir_path(backends[0][len("tdbsam:"):])) - return TdbSam(self.libdir_path("passdb.tdb")) + if ":" in backends[0]: + (name, location) = backends[0].split(":", 2) + else: + name = backends[0] + location = None + if name == "smbpasswd": + return SmbpasswdFile(self.libdir_path(location or "smbpasswd")) + elif name == "tdbsam": + return TdbSam(self.libdir_path(location or "passdb.tdb")) + elif name == "ldapsam": + if location is not None: + return LdapSam("ldap:%s" % location) + return LdapSam(lp.get("ldap server")) else: raise NotImplementedError("unsupported passdb backend %s" % backends[0]) -- cgit From 8ad2a035e35284f50ed2650bb202f050416de248 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 27 Dec 2007 23:31:59 -0600 Subject: r26616: Support parsing of user data in SAmba 3 tdbsam. (This used to be commit 2f33e0451d6699fed8bc9abfa2f331317502b358) --- source4/scripting/python/samba/samba3.py | 139 ++++++++++++++++++------------- 1 file changed, 80 insertions(+), 59 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index c9153d85cf..27656900ad 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -324,7 +324,8 @@ class SAMUser: domain=None, dir_drive=None, munged_dial=None, homedir=None, logon_script=None, profile_path=None, workstations=None, kickoff_time=None, bad_password_time=None, pass_last_set_time=None, pass_can_change_time=None, pass_must_change_time=None, - user_rid=None): + user_rid=None, unknown_6=None, nt_password_history=None, + unknown_str=None, hours=None, logon_divs=None): self.username = name self.uid = uid self.lm_password = lm_password @@ -351,37 +352,16 @@ class SAMUser: self.pass_can_change_time = pass_can_change_time self.pass_must_change_time = pass_must_change_time self.user_rid = user_rid + self.unknown_6 = unknown_6 + self.nt_password_history = nt_password_history + self.unknown_str = unknown_str + self.hours = hours + self.logon_divs = logon_divs def __eq__(self, other): if not isinstance(other, SAMUser): return False - return (self.username == other.username and - self.uid == other.uid and - self.lm_password == other.lm_password and - self.nt_password == other.nt_password and - self.acct_ctrl == other.acct_ctrl and - self.pass_last_set_time == other.pass_last_set_time and - self.nt_username == other.nt_username and - self.fullname == other.fullname and - self.logon_time == other.logon_time and - self.logoff_time == other.logoff_time and - self.acct_desc == other.acct_desc and - self.group_rid == other.group_rid and - self.bad_password_count == other.bad_password_count and - self.logon_count == other.logon_count and - self.domain == other.domain and - self.dir_drive == other.dir_drive and - self.munged_dial == other.munged_dial and - self.homedir == other.homedir and - self.logon_script == other.logon_script and - self.profile_path == other.profile_path and - self.workstations == other.workstations and - self.kickoff_time == other.kickoff_time and - self.bad_password_time == other.bad_password_time and - self.pass_can_change_time == other.pass_can_change_time and - self.pass_must_change_time == other.pass_must_change_time and - self.user_rid == other.user_rid) - + return self.__dict__ == other.__dict__ class SmbpasswdFile: def __init__(self, file): @@ -451,7 +431,7 @@ class LdapSam: class TdbSam: def __init__(self, file): self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) - self.version = self.tdb.fetch_uint32("INFO/version") or 0 + self.version = self.tdb.fetch_uint32("INFO/version\0") or 0 assert self.version in (0, 1, 2) def usernames(self): @@ -463,41 +443,82 @@ class TdbSam: def __getitem__(self, name): data = self.tdb["%s%s\0" % (TDBSAM_USER_PREFIX, name)] - import struct - (logon_time, logoff_time, kickoff_time, pass_last_set_time, pass_can_change_time, \ - pass_must_change_time) = struct.unpack(" 0: + (bad_password_time, data) = unpack_int32(data) + if bad_password_time != 0: + user.bad_password_time = bad_password_time + (pass_last_set_time, data) = unpack_int32(data) + (pass_can_change_time, data) = unpack_int32(data) + (pass_must_change_time, data) = unpack_int32(data) + + if logon_time != 0: + user.logon_time = logon_time user.logoff_time = logoff_time user.kickoff_time = kickoff_time - user.pass_last_set_time = pass_last_set_time + if pass_last_set_time != 0: + user.pass_last_set_time = pass_last_set_time user.pass_can_change_time = pass_can_change_time -# &username_len, &sampass->username, /* B */ -# &domain_len, &sampass->domain, /* B */ -# &nt_username_len, &sampass->nt_username, /* B */ -# &fullname_len, &sampass->fullname, /* B */ -# &homedir_len, &sampass->homedir, /* B */ -# &dir_drive_len, &sampass->dir_drive, /* B */ -# &logon_script_len, &sampass->logon_script, /* B */ -# &profile_path_len, &sampass->profile_path, /* B */ -# &acct_desc_len, &sampass->acct_desc, /* B */ -# &workstations_len, &sampass->workstations, /* B */ -# &unknown_str_len, &sampass->unknown_str, /* B */ -# &munged_dial_len, &sampass->munged_dial, /* B */ -# &sampass->user_rid, /* d */ -# &sampass->group_rid, /* d */ -# &lm_pw_len, sampass->lm_pw.hash, /* B */ -# &nt_pw_len, sampass->nt_pw.hash, /* B */ -# &sampass->acct_ctrl, /* w */ -# &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */ -# &sampass->logon_divs, /* w */ -# &sampass->hours_len, /* d */ -# &hourslen, &sampass->hours, /* B */ -# &sampass->bad_password_count, /* w */ -# &sampass->logon_count, /* w */ -# &sampass->unknown_6); /* d */ -# + (user.username, data) = unpack_string(data) + (user.domain, data) = unpack_string(data) + (user.nt_username, data) = unpack_string(data) + (user.fullname, data) = unpack_string(data) + (user.homedir, data) = unpack_string(data) + (user.dir_drive, data) = unpack_string(data) + (user.logon_script, data) = unpack_string(data) + (user.profile_path, data) = unpack_string(data) + (user.acct_desc, data) = unpack_string(data) + (user.workstations, data) = unpack_string(data) + (user.unknown_str, data) = unpack_string(data) + (user.munged_dial, data) = unpack_string(data) + + (user.user_rid, data) = unpack_int32(data) + (user.group_rid, data) = unpack_int32(data) + + (user.lm_password, data) = unpack_string(data) + (user.nt_password, data) = unpack_string(data) + + if self.version > 1: + (user.nt_password_history, data) = unpack_string(data) + + (user.acct_ctrl, data) = unpack_uint16(data) + (_, data) = unpack_uint32(data) # remove_me field + (user.logon_divs, data) = unpack_uint16(data) + (hours, data) = unpack_string(data) + user.hours = [] + for entry in hours: + for i in range(8): + user.hours.append(ord(entry) & (2 ** i) == (2 ** i)) + (user.bad_password_count, data) = unpack_uint16(data) + (user.logon_count, data) = unpack_uint16(data) + (user.unknown_6, data) = unpack_uint32(data) + assert len(data) == 0 return user def close(self): -- cgit From 6817c5d885a75a1af0e646827c3fa8220df8c7a5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 29 Dec 2007 18:14:15 -0600 Subject: r26628: python: Add more documentation, simplify code in Samba3 module. (This used to be commit 3c329ee73d9979236313c37e51750ec06b8dd69e) --- source4/scripting/python/samba/samba3.py | 100 +++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 33 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index 27656900ad..113348e6f1 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -25,14 +25,33 @@ REGISTRY_DB_VERSION = 1 import os 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): + """Open a file. + + :param file: Path of the file to open. + """ self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) + self._check_version() + + def _check_version(self): + pass def close(self): + """Close resources associated with this object.""" 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): """Return the number of 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)] 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) if data is None: return [] @@ -54,7 +78,11 @@ class Registry: return keys 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)) if data is None: return {} @@ -77,9 +105,14 @@ class Registry: return ret -class PolicyDatabase: +class PolicyDatabase(TdbDatabase): + """Samba 3 Account Policy database reader.""" 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.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") @@ -93,9 +126,6 @@ class PolicyDatabase: # FIXME: Read privileges as well - def close(self): - self.tdb.close() - GROUPDB_DATABASE_VERSION_V1 = 1 # native byte format. GROUPDB_DATABASE_VERSION_V2 = 2 # le format. @@ -108,17 +138,27 @@ GROUP_PREFIX = "UNIXGROUP/" # hanging of the member as key. MEMBEROF_PREFIX = "MEMBEROF/" -class GroupMappingDatabase: - def __init__(self, file): - self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) +class GroupMappingDatabase(TdbDatabase): + """Samba 3 group mapping database reader.""" + def _check_version(self): assert self.tdb.fetch_int32("INFO/version\x00") in (GROUPDB_DATABASE_VERSION_V1, GROUPDB_DATABASE_VERSION_V2) def groupsids(self): + """Retrieve the SIDs for the groups in this database. + + :return: List with sids as strings. + """ for k in self.tdb.keys(): if k.startswith(GROUP_PREFIX): yield k[len(GROUP_PREFIX):].rstrip("\0") 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)) if data is None: return data @@ -128,13 +168,11 @@ class GroupMappingDatabase: return (gid, sid_name_use, nt_name, comment) def aliases(self): + """Retrieve the aliases in this database.""" for k in self.tdb.keys(): if k.startswith(MEMBEROF_PREFIX): yield k[len(MEMBEROF_PREFIX):].rstrip("\0") - def close(self): - self.tdb.close() - # High water mark keys IDMAP_HWM_GROUP = "GROUP HWM\0" @@ -146,22 +184,29 @@ IDMAP_USER_PREFIX = "UID " # idmap version determines auto-conversion IDMAP_VERSION_V2 = 2 -class IdmapDatabase: - def __init__(self, file): - self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) +class IdmapDatabase(TdbDatabase): + """Samba 3 ID map database reader.""" + def _check_version(self): assert self.tdb.fetch_int32("IDMAP_VERSION\0") == IDMAP_VERSION_V2 def uids(self): + """Retrieve a list of all uids in this database.""" for k in self.tdb.keys(): if k.startswith(IDMAP_USER_PREFIX): yield int(k[len(IDMAP_USER_PREFIX):].rstrip("\0")) def gids(self): + """Retrieve a list of all gids in this database.""" for k in self.tdb.keys(): if k.startswith(IDMAP_GROUP_PREFIX): yield int(k[len(IDMAP_GROUP_PREFIX):].rstrip("\0")) 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)) if data is None: return data @@ -174,19 +219,15 @@ class IdmapDatabase: return data.rstrip("\0") def get_user_hwm(self): + """Obtain the user high-water mark.""" return self.tdb.fetch_uint32(IDMAP_HWM_USER) def get_group_hwm(self): + """Obtain the group high-water mark.""" 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): return self.tdb.get("SECRETS/AUTH_PASSWORD") @@ -241,16 +282,12 @@ class SecretsDatabase: def get_sid(self, host): return self.tdb.get("SECRETS/SID/%s" % host.upper()) - def close(self): - self.tdb.close() - SHARE_DATABASE_VERSION_V1 = 1 SHARE_DATABASE_VERSION_V2 = 2 -class ShareInfoDatabase: - def __init__(self, file): - self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) +class ShareInfoDatabase(TdbDatabase): + def _check_version(self): assert self.tdb.fetch_int32("INFO/version\0") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2) def get_secdesc(self, name): @@ -258,9 +295,6 @@ class ShareInfoDatabase: # FIXME: Run ndr_pull_security_descriptor return secdesc - def close(self): - self.tdb.close() - class Shares: def __init__(self, lp, shareinfo): -- cgit From 2bd4bf6a1beb2b00ab86cca59ac875bf75c921ef Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 29 Dec 2007 18:14:18 -0600 Subject: r26629: python: Improve documentation in various places. (This used to be commit ee71a27bca66426d34cb1d686a83ac6a342329d3) --- source4/scripting/python/samba/samba3.py | 43 ++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index 113348e6f1..cffedb54af 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -26,7 +26,7 @@ import os import tdb -class TdbDatabase: +class TdbDatabase(object): """Simple Samba 3 TDB database reader.""" def __init__(self, file): """Open a file. @@ -228,6 +228,7 @@ class IdmapDatabase(TdbDatabase): class SecretsDatabase(TdbDatabase): + """Samba 3 Secrets database reader.""" def get_auth_password(self): return self.tdb.get("SECRETS/AUTH_PASSWORD") @@ -246,6 +247,10 @@ class SecretsDatabase(TdbDatabase): yield k[len("SECRETS/LDAP_BIND_PW/"):].rstrip("\0") def domains(self): + """Iterate over domains in this database. + + :return: Iterator over the names of domains in this database. + """ for k in self.tdb.keys(): if k.startswith("SECRETS/SID/"): yield k[len("SECRETS/SID/"):].rstrip("\0") @@ -287,10 +292,15 @@ SHARE_DATABASE_VERSION_V1 = 1 SHARE_DATABASE_VERSION_V2 = 2 class ShareInfoDatabase(TdbDatabase): + """Samba 3 Share Info database reader.""" def _check_version(self): assert self.tdb.fetch_int32("INFO/version\0") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2) def get_secdesc(self, name): + """Obtain the security descriptor on a particular share. + + :param name: Name of the share + """ secdesc = self.tdb.get("SECDESC/%s" % name) # FIXME: Run ndr_pull_security_descriptor return secdesc @@ -302,9 +312,11 @@ class Shares: self.shareinfo = shareinfo def __len__(self): + """Number of shares.""" return len(self.lp) - 1 def __iter__(self): + """Iterate over the share names.""" return self.lp.__iter__() @@ -329,7 +341,7 @@ ACB_PW_EXPIRED = 0x00020000 ACB_NO_AUTH_DATA_REQD = 0x00080000 acb_info_mapping = { - 'N': ACB_PWNOTREQ, # 'N'o password. + 'N': ACB_PWNOTREQ, # 'N'o password. 'D': ACB_DISABLED, # 'D'isabled. 'H': ACB_HOMDIRREQ, # 'H'omedir required. 'T': ACB_TEMPDUP, # 'T'emp account. @@ -344,6 +356,11 @@ acb_info_mapping = { } def decode_acb(text): + """Decode a ACB field. + + :param text: ACB text + :return: integer with flags set. + """ assert not "[" in text and not "]" in text ret = 0 for x in text: @@ -352,6 +369,10 @@ def decode_acb(text): class SAMUser: + """Samba 3 SAM User. + + :note: Unknown or unset fields are set to None. + """ def __init__(self, name, uid=None, lm_password=None, nt_password=None, acct_ctrl=None, last_change_time=None, nt_username=None, fullname=None, logon_time=None, logoff_time=None, acct_desc=None, group_rid=None, bad_password_count=None, logon_count=None, @@ -398,6 +419,7 @@ class SAMUser: return self.__dict__ == other.__dict__ class SmbpasswdFile: + """Samba 3 smbpasswd file reader.""" def __init__(self, file): self.users = {} f = open(file, 'r') @@ -458,13 +480,14 @@ TDBSAM_USER_PREFIX = "USER_" class LdapSam: + """Samba 3 LDAP passdb backend reader.""" def __init__(self, url): self.ldap_url = ldap_url -class TdbSam: - def __init__(self, file): - self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) +class TdbSam(TdbDatabase): + """Samba 3 TDB passdb backend reader.""" + def _check_version(self): self.version = self.tdb.fetch_uint32("INFO/version\0") or 0 assert self.version in (0, 1, 2) @@ -555,9 +578,6 @@ class TdbSam: assert len(data) == 0 return user - def close(self): - self.tdb.close() - def shellsplit(text): """Very simple shell-like line splitting. @@ -582,6 +602,7 @@ def shellsplit(text): class WinsDatabase: + """Samba 3 WINS database reader.""" def __init__(self, file): self.entries = {} f = open(file, 'r') @@ -618,7 +639,13 @@ class WinsDatabase: pass class Samba3: + """Samba 3 configuration and state data reader.""" def __init__(self, libdir, smbconfpath): + """Open the configuration and data for a Samba 3 installation. + + :param libdir: Library directory + :param smbconfpath: Path to the smb.conf file. + """ self.smbconfpath = smbconfpath self.libdir = libdir import param -- cgit From c401aa93573460f10256218a6a1902839b17b884 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 17:42:18 +0200 Subject: Use restructuredText formatting for docstrings. (This used to be commit 0cc58decd74d20f3d7dff93ddef1c8bce4d49ad0) --- source4/scripting/python/samba/samba3.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index cffedb54af..9e802fa093 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -19,6 +19,8 @@ """Support for reading Samba 3 data files.""" +__docformat__ = "restructuredText" + REGISTRY_VALUE_PREFIX = "SAMBA_REGVAL" REGISTRY_DB_VERSION = 1 -- cgit From c159d1221bddec5c855fda9236913c18fc7a49fa Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 18:47:32 +0200 Subject: Add docstrings to samba3 and getopt modules. (This used to be commit bdf1c039db6c184a9f275a6e4bf3786570cc924a) --- source4/scripting/python/samba/samba3.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index 9e802fa093..c1340b7760 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -309,6 +309,7 @@ class ShareInfoDatabase(TdbDatabase): class Shares: + """Container for share objects.""" def __init__(self, lp, shareinfo): self.lp = lp self.shareinfo = shareinfo @@ -494,6 +495,7 @@ class TdbSam(TdbDatabase): assert self.version in (0, 1, 2) def usernames(self): + """Iterate over the usernames in this Tdb database.""" for k in self.tdb.keys(): if k.startswith(TDBSAM_USER_PREFIX): yield k[len(TDBSAM_USER_PREFIX):].rstrip("\0") @@ -635,6 +637,7 @@ class WinsDatabase: return iter(self.entries) def items(self): + """Return the entries in this WINS database.""" return self.entries.items() def close(self): # for consistency -- cgit From 1c94f3e95da5b520ee631670a30f96e487f12ac8 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 1 Aug 2008 21:00:09 +0200 Subject: Use new style python classes. (This used to be commit 2a39aae0cef310a79427feb1b85f6794ea36849a) --- source4/scripting/python/samba/samba3.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba/samba3.py') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index c1340b7760..0e0c29dac8 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -308,7 +308,7 @@ class ShareInfoDatabase(TdbDatabase): return secdesc -class Shares: +class Shares(object): """Container for share objects.""" def __init__(self, lp, shareinfo): self.lp = lp @@ -371,7 +371,7 @@ def decode_acb(text): return ret -class SAMUser: +class SAMUser(object): """Samba 3 SAM User. :note: Unknown or unset fields are set to None. @@ -421,7 +421,8 @@ class SAMUser: return False return self.__dict__ == other.__dict__ -class SmbpasswdFile: + +class SmbpasswdFile(object): """Samba 3 smbpasswd file reader.""" def __init__(self, file): self.users = {} @@ -482,7 +483,7 @@ TDBSAM_FORMAT_STRING_V2 = "dddddddBBBBBBBBBBBBddBBBwwdBwwd" TDBSAM_USER_PREFIX = "USER_" -class LdapSam: +class LdapSam(object): """Samba 3 LDAP passdb backend reader.""" def __init__(self, url): self.ldap_url = ldap_url @@ -605,7 +606,7 @@ def shellsplit(text): return ret -class WinsDatabase: +class WinsDatabase(object): """Samba 3 WINS database reader.""" def __init__(self, file): self.entries = {} @@ -643,7 +644,8 @@ class WinsDatabase: def close(self): # for consistency pass -class Samba3: + +class Samba3(object): """Samba 3 configuration and state data reader.""" def __init__(self, libdir, smbconfpath): """Open the configuration and data for a Samba 3 installation. -- cgit