diff options
author | Amitay Isaacs <amitay@gmail.com> | 2011-08-12 16:19:06 +1000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2011-08-13 12:30:50 +1000 |
commit | 9a4a2b0f0d1411c98194a838390862bff8c184dd (patch) | |
tree | 233fa826029a8a4cedcc241c3379be31dbaae484 /source4/scripting/python/samba/samba3/__init__.py | |
parent | 6d139d6b0f3d38be395626a7fb4e8d02151102ab (diff) | |
download | samba-9a4a2b0f0d1411c98194a838390862bff8c184dd.tar.gz samba-9a4a2b0f0d1411c98194a838390862bff8c184dd.tar.bz2 samba-9a4a2b0f0d1411c98194a838390862bff8c184dd.zip |
py-samba3: Create samba3 python package to hold other modules
This will include passdb and param.
Diffstat (limited to 'source4/scripting/python/samba/samba3/__init__.py')
-rw-r--r-- | source4/scripting/python/samba/samba3/__init__.py | 793 |
1 files changed, 793 insertions, 0 deletions
diff --git a/source4/scripting/python/samba/samba3/__init__.py b/source4/scripting/python/samba/samba3/__init__.py new file mode 100644 index 0000000000..55e9b18f24 --- /dev/null +++ b/source4/scripting/python/samba/samba3/__init__.py @@ -0,0 +1,793 @@ +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 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 <http://www.gnu.org/licenses/>. +# + +"""Support for reading Samba 3 data files.""" + +__docformat__ = "restructuredText" + +REGISTRY_VALUE_PREFIX = "SAMBA_REGVAL" +REGISTRY_DB_VERSION = 1 + +import os +import struct +import tdb + + +def fetch_uint32(tdb, key): + try: + data = tdb[key] + except KeyError: + return None + assert len(data) == 4 + return struct.unpack("<L", data)[0] + + +def fetch_int32(tdb, key): + try: + data = tdb[key] + except KeyError: + return None + assert len(data) == 4 + return struct.unpack("<l", data)[0] + + +class TdbDatabase(object): + """Simple Samba 3 TDB database reader.""" + def __init__(self, file): + """Open a file. + + :param file: Path of the file to open (appending "2" if TDB2 enabled). + """ + if tdb.__version__.startswith("2"): + self.tdb = tdb.Tdb(file + "2", flags=os.O_RDONLY) + else: + 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()) + + def keys(self): + """Return list with all the keys.""" + return [k.rstrip("\x00") for k in self.tdb.iterkeys() 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 [] + (num, ) = struct.unpack("<L", data[0:4]) + keys = data[4:].split("\0") + assert keys[-1] == "" + keys.pop() + assert len(keys) == num + return keys + + def values(self, 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 {} + ret = {} + (num, ) = struct.unpack("<L", data[0:4]) + data = data[4:] + for i in range(num): + # Value name + (name, data) = data.split("\0", 1) + + (type, ) = struct.unpack("<L", data[0:4]) + data = data[4:] + (value_len, ) = struct.unpack("<L", data[0:4]) + data = data[4:] + + ret[name] = (type, data[:value_len]) + data = data[value_len:] + + return ret + + +class PolicyDatabase(TdbDatabase): + """Samba 3 Account Policy database reader.""" + def __init__(self, file): + """Open a policy database + + :param file: Path to the file to open. + """ + super(PolicyDatabase, self).__init__(file) + self.min_password_length = fetch_uint32(self.tdb, "min password length\x00") + self.password_history = fetch_uint32(self.tdb, "password history\x00") + self.user_must_logon_to_change_password = fetch_uint32(self.tdb, "user must logon to change pasword\x00") + self.maximum_password_age = fetch_uint32(self.tdb, "maximum password age\x00") + self.minimum_password_age = fetch_uint32(self.tdb, "minimum password age\x00") + self.lockout_duration = fetch_uint32(self.tdb, "lockout duration\x00") + self.reset_count_minutes = fetch_uint32(self.tdb, "reset count minutes\x00") + self.bad_lockout_minutes = fetch_uint32(self.tdb, "bad lockout minutes\x00") + self.disconnect_time = fetch_int32(self.tdb, "disconnect time\x00") + self.refuse_machine_password_change = fetch_uint32(self.tdb, "refuse machine password change\x00") + + # 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(TdbDatabase): + """Samba 3 group mapping database reader.""" + def _check_version(self): + assert fetch_int32(self.tdb, "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.iterkeys(): + 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 + (gid, sid_name_use) = struct.unpack("<lL", data[0:8]) + (nt_name, comment, _) = data[8:].split("\0") + return (gid, sid_name_use, nt_name, comment) + + def aliases(self): + """Retrieve the aliases in this database.""" + for k in self.tdb.iterkeys(): + if k.startswith(MEMBEROF_PREFIX): + yield k[len(MEMBEROF_PREFIX):].rstrip("\0") + + +# High water mark keys +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_V2 = 2 + +class IdmapDatabase(TdbDatabase): + """Samba 3 ID map database reader.""" + def _check_version(self): + assert fetch_int32(self.tdb, "IDMAP_VERSION\0") == IDMAP_VERSION_V2 + + def uids(self): + """Retrieve a list of all uids in this database.""" + for k in self.tdb.iterkeys(): + 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.iterkeys(): + 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 + 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): + """Obtain the user high-water mark.""" + return fetch_uint32(self.tdb, IDMAP_HWM_USER) + + def get_group_hwm(self): + """Obtain the group high-water mark.""" + return fetch_uint32(self.tdb, IDMAP_HWM_GROUP) + + +class SecretsDatabase(TdbDatabase): + """Samba 3 Secrets database reader.""" + 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_domain_guid(self, host): + return self.tdb.get("SECRETS/DOMGUID/%s" % host) + + def ldap_dns(self): + for k in self.tdb.iterkeys(): + if k.startswith("SECRETS/LDAP_BIND_PW/"): + 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.iterkeys(): + 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) + + def get_afs_keyfile(self, host): + return self.tdb.get("SECRETS/AFS_KEYFILE/%s" % host) + + def get_machine_sec_channel_type(self, host): + return fetch_uint32(self.tdb, "SECRETS/MACHINE_SEC_CHANNEL_TYPE/%s" % host) + + def get_machine_last_change_time(self, host): + return fetch_uint32(self.tdb, "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 trusted_domains(self): + for k in self.tdb.iterkeys(): + 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") + + def get_sid(self, host): + return self.tdb.get("SECRETS/SID/%s" % host.upper()) + + +SHARE_DATABASE_VERSION_V1 = 1 +SHARE_DATABASE_VERSION_V2 = 2 + +class ShareInfoDatabase(TdbDatabase): + """Samba 3 Share Info database reader.""" + def _check_version(self): + assert fetch_int32(self.tdb, "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 + + +class Shares(object): + """Container for share objects.""" + def __init__(self, lp, shareinfo): + self.lp = lp + 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__() + + +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 + } + +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: + ret |= acb_info_mapping[x] + return ret + + +class SAMUser(object): + """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, + 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, 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 + self.nt_password = nt_password + self.acct_ctrl = acct_ctrl + self.pass_last_set_time = last_change_time + self.nt_username = nt_username + self.fullname = fullname + self.logon_time = logon_time + self.logoff_time = logoff_time + self.acct_desc = acct_desc + self.group_rid = group_rid + self.bad_password_count = bad_password_count + self.logon_count = logon_count + self.domain = domain + self.dir_drive = dir_drive + self.munged_dial = munged_dial + self.homedir = homedir + self.logon_script = logon_script + self.profile_path = profile_path + self.workstations = workstations + self.kickoff_time = kickoff_time + self.bad_password_time = bad_password_time + 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.__dict__ == other.__dict__ + + +class SmbpasswdFile(object): + """Samba 3 smbpasswd file reader.""" + 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] = SAMUser(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 __iter__(self): + return iter(self.users) + + def close(self): # For consistency + pass + + +TDBSAM_FORMAT_STRING_V0 = "ddddddBBBBBBBBBBBBddBBwdwdBwwd" +TDBSAM_FORMAT_STRING_V1 = "dddddddBBBBBBBBBBBBddBBwdwdBwwd" +TDBSAM_FORMAT_STRING_V2 = "dddddddBBBBBBBBBBBBddBBBwwdBwwd" +TDBSAM_USER_PREFIX = "USER_" + + +class LdapSam(object): + """Samba 3 LDAP passdb backend reader.""" + def __init__(self, url): + self.ldap_url = url + + +class TdbSam(TdbDatabase): + """Samba 3 TDB passdb backend reader.""" + def _check_version(self): + self.version = fetch_uint32(self.tdb, "INFO/version\0") or 0 + assert self.version in (0, 1, 2) + + def usernames(self): + """Iterate over the usernames in this Tdb database.""" + for k in self.tdb.iterkeys(): + if k.startswith(TDBSAM_USER_PREFIX): + yield k[len(TDBSAM_USER_PREFIX):].rstrip("\0") + + __iter__ = usernames + + def __getitem__(self, name): + data = self.tdb["%s%s\0" % (TDBSAM_USER_PREFIX, name)] + user = SAMUser(name) + + def unpack_string(data): + (length, ) = struct.unpack("<L", data[:4]) + data = data[4:] + if length == 0: + return (None, data) + return (data[:length].rstrip("\0"), data[length:]) + + def unpack_int32(data): + (value, ) = struct.unpack("<l", data[:4]) + return (value, data[4:]) + + def unpack_uint32(data): + (value, ) = struct.unpack("<L", data[:4]) + return (value, data[4:]) + + def unpack_uint16(data): + (value, ) = struct.unpack("<H", data[:2]) + return (value, data[2:]) + + (logon_time, data) = unpack_int32(data) + (logoff_time, data) = unpack_int32(data) + (kickoff_time, data) = unpack_int32(data) + + if self.version > 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 + if pass_last_set_time != 0: + user.pass_last_set_time = pass_last_set_time + user.pass_can_change_time = pass_can_change_time + + (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 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(object): + """Samba 3 WINS database reader.""" + def __init__(self, file): + 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")) + name = entries[0] + ttl = int(entries[1]) + i = 2 + ips = [] + while "." in entries[i]: + ips.append(entries[i]) + i+=1 + 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() + + def __getitem__(self, name): + return self.entries[name] + + def __len__(self): + return len(self.entries) + + def __iter__(self): + return iter(self.entries) + + def items(self): + """Return the entries in this WINS database.""" + return self.entries.items() + + def close(self): # for consistency + pass + + +class ParamFile(object): + """Simple smb.conf-compatible file parser + + Does not use a parameter table, unlike the "normal". + """ + + def __init__(self, sections=None): + self._sections = sections or {} + + def _sanitize_name(self, name): + return name.strip().lower().replace(" ","") + + def __repr__(self): + return "ParamFile(%r)" % self._sections + + def read(self, filename): + """Read a file. + + :param filename: Path to the file + """ + section = None + for i, l in enumerate(open(filename, 'r').xreadlines()): + l = l.strip() + if not l or l[0] == '#' or l[0] == ';': + continue + if l[0] == "[" and l[-1] == "]": + section = self._sanitize_name(l[1:-1]) + self._sections.setdefault(section, {}) + elif "=" in l: + (k, v) = l.split("=", 1) + self._sections[section][self._sanitize_name(k)] = v + else: + raise Exception("Unable to parser line %d: %r" % (i+1,l)) + + def get(self, param, section=None): + """Return the value of a parameter. + + :param param: Parameter name + :param section: Section name, defaults to "global" + :return: parameter value as string if found, None otherwise. + """ + if section is None: + section = "global" + section = self._sanitize_name(section) + if not section in self._sections: + return None + param = self._sanitize_name(param) + if not param in self._sections[section]: + return None + return self._sections[section][param].strip() + + def __getitem__(self, section): + return self._sections[section] + + def get_section(self, section): + return self._sections.get(section) + + def add_section(self, section): + self._sections[self._sanitize_name(section)] = {} + + def set_string(self, name, value): + self._sections["global"][name] = value + + def get_string(self, name): + return self._sections["global"].get(name) + + +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. + + :param libdir: Library directory + :param smbconfpath: Path to the smb.conf file. + """ + self.smbconfpath = smbconfpath + self.libdir = libdir + self.lp = 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 = (lp.get("passdb backend") or "").split(" ") + 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]) + + def get_policy_db(self): + return PolicyDatabase(self.libdir_path("account_policy.tdb")) + + def get_registry(self): + return Registry(self.libdir_path("registry.tdb")) + + def get_secrets_db(self): + return SecretsDatabase(self.libdir_path("secrets.tdb")) + + def get_shareinfo_db(self): + return ShareInfoDatabase(self.libdir_path("share_info.tdb")) + + def get_idmap_db(self): + return IdmapDatabase(self.libdir_path("winbindd_idmap.tdb")) + + def get_wins_db(self): + 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(self.libdir_path("group_mapping.tdb")) |