From 39adc2418a0586261c6c4aea36f72596c6cf8897 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 21 Nov 2007 13:07:16 +0100 Subject: r26088: Import some native-python python modules and move original python swig torture code to common python directory as well. (This used to be commit cbf656ff054ab2b0b5ca81e1d4f16ac54c8098f1) --- source4/scripting/python/samba/__init__.py | 57 ++ source4/scripting/python/samba/getopt.py | 46 ++ source4/scripting/python/samba/samr.py | 753 +++++++++++++++++++++ source4/scripting/python/samba/torture/pytorture | 51 ++ source4/scripting/python/samba/torture/spoolss.py | 437 ++++++++++++ .../scripting/python/samba/torture/torture_samr.py | 221 ++++++ .../scripting/python/samba/torture/torture_tdb.py | 90 +++ source4/scripting/python/samba/torture/winreg.py | 165 +++++ 8 files changed, 1820 insertions(+) create mode 100644 source4/scripting/python/samba/__init__.py create mode 100644 source4/scripting/python/samba/getopt.py create mode 100644 source4/scripting/python/samba/samr.py create mode 100755 source4/scripting/python/samba/torture/pytorture create mode 100644 source4/scripting/python/samba/torture/spoolss.py create mode 100755 source4/scripting/python/samba/torture/torture_samr.py create mode 100755 source4/scripting/python/samba/torture/torture_tdb.py create mode 100755 source4/scripting/python/samba/torture/winreg.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py new file mode 100644 index 0000000000..46d8ff7d37 --- /dev/null +++ b/source4/scripting/python/samba/__init__.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Andrew Tridgell 2005 +# 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 . +# + +import os +from misc import ldb_set_credentials + +def Ldb(url, session_info=None, credentials=None, modules_dir=None): + """Open a Samba Ldb file. + + This is different from a regular Ldb file in that the Samba-specific + modules-dir is used by default and that credentials and session_info + can be passed through (required by some modules). + """ + import ldb + ret = ldb.Ldb() + if modules_dir is None: + modules_dir = os.path.join(os.getcwd(), "bin", "modules", "ldb") + ret.set_modules_dir(modules_dir) + def samba_debug(level,text): + print "%d %s" % (level, text) + ldb_set_opaque("credentials", credentials) + ret.set_opaque("sessionInfo", session_info) + #ret.set_debug(samba_debug) + ret.connect(url) + return ret + + +def substitute_var(text, values): + """substitute strings of the form ${NAME} in str, replacing + with substitutions from subobj. + + :param text: Text in which to subsitute. + :param values: Dictionary with keys and values. + """ + + for (name, value) in values.items(): + text = text.replace("${%s}" % name, value) + + return text + diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py new file mode 100644 index 0000000000..8143dcafdb --- /dev/null +++ b/source4/scripting/python/samba/getopt.py @@ -0,0 +1,46 @@ +#!/usr/bin/python + +# Samba-specific bits for optparse +# 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 . +# + +import optparse +from credentials import Credentials + +class SambaOptions(optparse.OptionGroup): + def __init__(self, parser): + optparse.OptionGroup.__init__(self, parser, "Samba Common Options") + self.add_option("--configfile", type="string", metavar="FILE", + help="Configuration file") + + +class VersionOptions(optparse.OptionGroup): + def __init__(self, parser): + optparse.OptionGroup.__init__(self, parser, "Version Options") + + +class CredentialsOptions(optparse.OptionGroup): + def __init__(self, parser): + optparse.OptionGroup.__init__(self, parser, "Credentials Options") + self.add_option("--simple-bind-dn", type="string", metavar="DN", + help="DN to use for a simple bind") + self.add_option("--password", type="string", metavar="PASSWORD", + help="Password") + + def get_credentials(self): + creds = Credentials() + # FIXME: Update + return creds diff --git a/source4/scripting/python/samba/samr.py b/source4/scripting/python/samba/samr.py new file mode 100644 index 0000000000..314f78b8ad --- /dev/null +++ b/source4/scripting/python/samba/samr.py @@ -0,0 +1,753 @@ +import dcerpc + +def sid_to_string(sid): + """Convert a Python dictionary SID to a string SID.""" + + result = 'S-%d' % sid.sid_rev_num + + result = result + '-%u' % \ + (dcerpc.uint8_array_getitem(sid.id_auth, 5) + + (dcerpc.uint8_array_getitem(sid.id_auth, 4) << 8) + + (dcerpc.uint8_array_getitem(sid.id_auth, 3) << 16) + + (dcerpc.uint8_array_getitem(sid.id_auth, 2) << 24)) + + for i in range(0, sid.num_auths): + result = result + '-%u' % \ + dcerpc.uint32_array_getitem(sid.sub_auths, i) + + return result + +def string_to_sid(string): + """Convert a string SID to a Python dictionary SID. Throws a + ValueError if the SID string was badly formed.""" + + if string[0] != 'S': + raise ValueError('Bad SID format') + + string = string[1:] + + import re + + match = re.match('-\d+', string) + + if not match: + raise ValueError('Bad SID format') + + try: + sid_rev_num = int(string[match.start()+1:match.end()]) + except ValueError: + raise ValueError('Bad SID format') + + string = string[match.end():] + + match = re.match('-\d+', string) + + if not match: + raise ValueError('Bad SID format') + + try: + ia = int(string[match.start()+1:match.end()]) + except ValueError: + raise ValueError('Bad SID format') + + string = string[match.end():] + + id_auth = [0, 0, (ia >> 24) & 0xff, (ia >> 16) & 0xff, + (ia >> 8) & 0xff, ia & 0xff] + + num_auths = 0 + sub_auths = [] + + while len(string): + + match = re.match('-\d+', string) + + if not match: + raise ValueError('Bad SID format') + + try: + sa = int(string[match.start() + 1 : match.end()]) + except ValueError: + raise ValueError('Bad SID format') + + num_auths = num_auths + 1 + sub_auths.append(int(sa)) + + string = string[match.end():] + + sid = dcerpc.dom_sid() + sid.sid_rev_num = sid_rev_num + sid.id_auth = dcerpc.new_uint8_array(6) + for i in range(6): + dcerpc.uint8_array_setitem(sid.id_auth, i, id_auth[i]) + sid.num_auths = num_auths + sid.sub_auths = dcerpc.new_uint32_array(num_auths) + for i in range(num_auths): + dcerpc.uint32_array_setitem(sid.sub_auths, i, sub_auths[i]) + + return sid + +def call_fn(fn, pipe, args): + """Wrap up a RPC call and throw an exception is an error was returned.""" + + result = fn(pipe, args); + + if result & 0xc0000000L: + raise dcerpc.NTSTATUS(result, dcerpc.nt_errstr(result)); + + return result; + +class SamrHandle: + + def __init__(self, pipe, handle): + + self.pipe = pipe + self.handle = handle + + def __del__(self): + + if self.handle is not None: + self.Close() + + def Close(self): + + r = dcerpc.samr_Close() + r.data_in.handle = self.handle + + call_fn(dcerpc.dcerpc_samr_Close, self.pipe, r) + + self.handle = None + + def QuerySecurity(self, sec_info = 7): + + r = dcerpc.samr_QuerySecurity() + r.data_in.handle = self.handle + r.data_in.sec_info = sec_info + + call_fn(dcerpc.dcerpc_samr_QuerySecurity, self.pipe, r) + + return r.data_out.sdbuf + + def SetSecurity(self, sdbuf, sec_info = 7): + + r = dcerpc.samr_SetSecurity() + r.data_in.handle = self.handle + r.data_in.sec_info = sec_info + r.data_in.sdbuf = sdbuf + + call_fn(dcerpc.dcerpc_samr_SetSecurity, self.pipe, r) + +class ConnectHandle(SamrHandle): + + def EnumDomains(self): + + r = dcerpc.samr_EnumDomains() + r.data_in.connect_handle = self.handle + r.data_in.resume_handle = 0 + r.data_in.buf_size = -1 + + domains = [] + + while 1: + + call_fn(dcerpc.dcerpc_samr_EnumDomains, self.pipe, r) + + for i in range(r.data_out.sam.count): + domains.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + # TODO: Handle more entries here + + break + + return domains + + def LookupDomain(self, domain_name): + + r = dcerpc.samr_LookupDomain() + r.data_in.connect_handle = self.handle + r.data_in.domain_name = dcerpc.samr_String() + r.data_in.domain_name.string = domain_name + + call_fn(dcerpc.dcerpc_samr_LookupDomain, self.pipe, r) + + return sid_to_string(r.data_out.sid); + + def OpenDomain(self, domain_sid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenDomain() + r.data_in.connect_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.sid = string_to_sid(domain_sid) + + call_fn(dcerpc.dcerpc_samr_OpenDomain, self.pipe, r) + + return DomainHandle(self.pipe, r.data_out.domain_handle) + + def Shutdown(self): + + r = dcerpc.samr_Shutdown() + r.data_in.connect_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_Shutdown, self.pipe, r) + + def GetDomPwInfo(self, domain_name): + + r = dcerpc.samr_GetDomPwInfo() + r.data_in.domain_name = dcerpc.samr_String() + r.data_in.domain_name.string = domain_name + + call_fn(dcerpc.dcerpc_samr_GetDomPwInfo, self.pipe, r) + + return r.data_out.info + + + def SetBootKeyInformation(self, unknown1, unknown2, unknown3): + + r = dcerpc.samr_GetBootKeyInformation() + r.data_in.connect_handle = self.handle + r.data_in.unknown1 = unknown1 + r.data_in.unknown2 = unknown2 + r.data_in.unknown3 = unknown3 + + call_fn(dcerpc.dcerpc_samr_SetBootKeyInformation, self.pipe, r) + +class DomainHandle(SamrHandle): + + def QueryDomainInfo(self, level = 2): + + r = dcerpc.samr_QueryDomainInfo() + r.data_in.domain_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryDomainInfo, self.pipe, r) + + return getattr(r.data_out.info, 'info%d' % level) + + def QueryDomainInfo2(self, level = 2): + + r = dcerpc.samr_QueryDomainInfo2() + r.data_in.domain_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryDomainInfo2, self.pipe, r) + + return getattr(r.data_out.info, 'info%d' % level) + + def SetDomainInfo(self, level, info): + + r = dcerpc.samr_SetDomainInfo() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.info = dcerpc.samr_DomainInfo() + setattr(r.data_in.info, 'info%d' % level, info) + + call_fn(dcerpc.dcerpc_samr_SetDomainInfo, self.pipe, r) + + def EnumDomainGroups(self): + + r = dcerpc.samr_EnumDomainGroups() + r.data_in.domain_handle = self.handle + r.data_in.resume_handle = 0 + r.data_in.max_size = 1000 + + call_fn(dcerpc.dcerpc_samr_EnumDomainGroups, self.pipe, r) + + groups = [] + + if r.data_out.sam.entries: + for i in range(r.data_out.sam.count): + groups.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + return groups + + def EnumDomainAliases(self): + + r = dcerpc.samr_EnumDomainAliases() + r.data_in.domain_handle = self.handle + r.data_in.resume_handle = 0 + # acct_flags in SamrEnumerateAliasesInDomain has probably + # no meaning so use 0xffffffff like W2K + r.data_in.acct_flags = 0xffffffffL + + call_fn(dcerpc.dcerpc_samr_EnumDomainAliases, self.pipe, r) + + aliases = [] + + if r.data_out.sam.entries: + for i in range(r.data_out.sam.count): + aliases.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + return aliases + + def EnumDomainUsers(self, user_account_flags = 16): + + r = dcerpc.samr_EnumDomainUsers() + r.data_in.domain_handle = self.handle + r.data_in.resume_handle = 0 + r.data_in.acct_flags = user_account_flags + r.data_in.max_size = 1000 + + call_fn(dcerpc.dcerpc_samr_EnumDomainUsers, self.pipe, r) + + users = [] + + if r.data_out.sam.entries: + for i in range(r.data_out.sam.count): + users.append(dcerpc.samr_SamEntry_array_getitem( + r.data_out.sam.entries, i).name.string) + + return users + + def CreateUser(self, account_name, access_mask = 0x02000000): + + r = dcerpc.samr_CreateUser() + r.data_in.domain_handle = self.handle + r.data_in.account_name = dcerpc.samr_String() + r.data_in.account_name.string = account_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateUser, self.pipe, r) + + return (r.data_out.user_handle, + dcerpc.uint32_array_getitem(r.data_out.rid, 0)) + + def CreateUser2(self, account_name, acct_flags = 0x00000010, + access_mask = 0x02000000): + + r = dcerpc.samr_CreateUser2() + r.data_in.domain_handle = self.handle + r.data_in.account_name = dcerpc.samr_String() + r.data_in.account_name.string = account_name + r.data_in.acct_flags = acct_flags + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateUser2, self.pipe, r) + + return (r.data_out.user_handle, + dcerpc.uint32_array_getitem(r.data_out.access_granted, 0), + dcerpc.uint32_array_getitem(r.data_out.rid, 0)) + + def OpenUser(self, rid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenUser() + r.data_in.domain_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_OpenUser, self.pipe, r) + + return UserHandle(self.pipe, r.data_out.user_handle) + + def OpenGroup(self, rid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenGroup() + r.data_in.domain_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_OpenGroup, self.pipe, r) + + return GroupHandle(self.pipe, r.data_out.group_handle) + + def OpenAlias(self, rid, access_mask = 0x02000000): + + r = dcerpc.samr_OpenAlias() + r.data_in.domain_handle = self.handle + r.data_in.access_mask = access_mask + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_OpenAlias, self.pipe, r) + + return AliasHandle(self.pipe, r.data_out.alias_handle) + + def CreateDomAlias(self, alias_name, access_mask = 0x02000000): + + r = dcerpc.samr_CreateDomAlias() + r.data_in.domain_handle = self.handle + r.data_in.alias_name = dcerpc.samr_String() + r.data_in.alias_name.string = alias_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateDomAlias, self.pipe, r) + + return (AliasHandle(self.pipe, r.data_out.alias_handle), + r.data_out.rid) + + def RidToSid(self, rid): + + r = dcerpc.samr_RidToSid() + r.data_in.domain_handle = self.handle + r.data_in.rid = rid + + call_fn(dcerpc.dcerpc_samr_RidToSid, self.pipe, r) + + return sid_to_string(r.data_out.sid) + + def RemoveMemberFromForeignDomain(self, sid): + + r = dcerpc.samr_RemoveMemberFromForeignDomain() + r.data_in.domain_handle = self.handle + r.data_in.sid = sid + + call_fn(dcerpc.dcerpc_samr_RemoveMemberFromForeignDomain, self.pipe, r) + + def LookupNames(self, names): + + r = dcerpc.samr_LookupNames() + r.data_in.domain_handle = self.handle + r.data_in.num_names = len(names) + r.data_in.names = dcerpc.new_samr_String_array(len(names)) + + for i in range(len(names)): + s = dcerpc.samr_String() + s.string = names[i] + dcerpc.samr_String_array_setitem(r.data_in.names, i, s) + + call_fn(dcerpc.dcerpc_samr_LookupNames, self.pipe, r) + + return ([dcerpc.uint32_array_getitem(r.data_out.rids.ids, i) + for i in range(r.data_out.rids.count)], + [dcerpc.uint32_array_getitem(r.data_out.types.ids, i) + for i in range(r.data_out.types.count)]) + + def CreateDomainGroup(self, domain_name, access_mask = 0x02000000): + + r = dcerpc.samr_CreateDomainGroup() + r.data_in.domain_handle = self.handle + r.data_in.name = dcerpc.samr_String() + r.data_in.name.string = domain_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_CreateDomainGroup, self.pipe, r) + + def GetAliasMembership(self, sids): + + r = dcerpc.samr_GetAliasMembership() + r.data_in.domain_handle = self.handle + r.data_in.sids = dcerpc.lsa_SidArray() + r.data_in.sids.num_sids = len(sids) + r.data_in.sids.sids = dcerpc.new_lsa_SidPtr_array(len(sids)) + + for i in range(len(sids)): + s = dcerpc.lsa_SidPtr() + s.sid = string_to_sid(sids[i]) + dcerpc.lsa_SidPtr_array_setitem(r.data_in.sids.sids, i, s) + + call_fn(dcerpc.dcerpc_samr_GetAliasMembership, self.pipe, r) + + return [r.ids[x] for x in range(r.count)] + + def QueryDisplayInfo(self, level): + + # TODO: Handle more data returns + + r = dcerpc.samr_QueryDisplayInfo() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.start_idx = 0 + r.data_in.max_entries = 1000 + r.data_in.buf_size = -1 + + call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo, self.pipe, r) + + # TODO: Return a mapping of the various samr_DispInfo + # structures here. + + return getattr(r.data_out.info, 'info%d' % level) + + def QueryDisplayInfo2(self, level): + + # TODO: Handle more data returns + + r = dcerpc.samr_QueryDisplayInfo2() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.start_idx = 0 + r.data_in.max_entries = 1000 + r.data_in.buf_size = -1 + + call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo2, self.pipe, r) + + # TODO: Return a mapping of the various samr_DispInfo + # structures here. + + return getattr(r.data_out.info, 'info%d' % level) + + def QueryDisplayInfo3(self, level): + + # TODO: Handle more data returns + + r = dcerpc.samr_QueryDisplayInfo3() + r.data_in.domain_handle = self.handle + r.data_in.level = level + r.data_in.start_idx = 0 + r.data_in.max_entries = 1000 + r.data_in.buf_size = -1 + + call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo3, self.pipe, r) + + # TODO: Return a mapping of the various samr_DispInfo + # structures here. + + return getattr(r.data_out.info, 'info%d' % level) + + def GetBootKeyInformation(self): + + r = dcerpc.samr_GetBootKeyInformation() + r.data_in.domain_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetBootKeyInformation, self.pipe, r) + + return r.data_out.unknown + + def SetBootKeyInformation(self): + + r = dcerpc.samr_GetBootKeyInformation() + r.data_in.domain_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetBootKeyInformation, self.pipe, r) + + def TestPrivateFunctionsDomain(self): + + r = dcerpc.samr_TestPrivateFunctionsDomain() + r.data_in.domain_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_TestPrivateFunctionsDomain, self.pipe, r) + +class UserHandle(SamrHandle): + + def DeleteUser(self): + + r = dcerpc.samr_DeleteUser() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_DeleteUser, self.pipe, r) + + self.handle = None + + def GetUserPwInfo(self): + + r = dcerpc.samr_GetUserPwInfo() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetUserPwInfo, self.pipe, r) + + return r.data_out.info + + def QueryUserInfo(self, level): + + r = dcerpc.samr_QueryUserInfo() + r.data_in.user_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryUserInfo, self.pipe, r) + + return r.data_out.info + + def QueryUserInfo2(self, level): + + r = dcerpc.samr_QueryUserInfo2() + r.data_in.user_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryUserInfo2, self.pipe, r) + + return r.data_out.info + + def GetGroupsForUser(self): + + r = dcerpc.samr_GetGroupsForUser() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetGroupsForUser, self.pipe, r) + + rid_types = [dcerpc.samr_RidType_array_getitem(r.data_out.rids.rid, x) + for x in range(r.data_out.rids.count)] + + return [(x.rid, x.type) for x in rid_types] + + def TestPrivateFunctionsUser(self): + + r = dcerpc.samr_TestPrivateFunctionsUser() + r.data_in.user_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_TestPrivateFunctionsUser, self.pipe, r) + +class GroupHandle(SamrHandle): + + def QueryGroupInfo(self, level): + + r = dcerpc.samr_QueryGroupInfo() + r.data_in.group_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryGroupInfo, self.pipe, r) + + return r.data_out.info + + def SetGroupInfo(self, level, info): + + r = dcerpc.samr_SetGroupInfo() + r.data_in.group_handle = self.handle + r.data_in.level = level + r.data_in.info = info + + call_fn(dcerpc.dcerpc_samr_SetGroupInfo, self.pipe, r) + + def QueryGroupMember(self): + + r = dcerpc.samr_QueryGroupMember() + r.data_in.group_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_QueryGroupMember, self.pipe, r) + + return [(dcerpc.uint32_array_getitem(r.data_out.rids.rids, x), + dcerpc.uint32_array_getitem(r.data_out.rids.unknown, x)) + for x in range(r.data_out.rids.count)] + +class AliasHandle(SamrHandle): + + def DeleteDomAlias(self): + + r = dcerpc.samr_DeleteDomAlias() + r.data_in.alias_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_DeleteDomAlias, self.pipe, r) + + self.handle = None + + def QueryAliasInfo(self, level = 1): + + r = dcerpc.samr_QueryAliasInfo() + r.data_in.alias_handle = self.handle + r.data_in.level = level + + call_fn(dcerpc.dcerpc_samr_QueryAliasInfo, self.pipe, r) + + return r.data_out.info + + def SetAliasInfo(self, level, info): + + r = dcerpc.samr_SetAliasInfo() + r.data_in.alias_handle = self.handle + r.data_in.level = level + r.data_in.info = info + + call_fn(dcerpc.dcerpc_samr_SetAliasInfo, self.pipe, r) + + def AddAliasMember(self, sid): + + r = dcerpc.samr_AddAliasMember() + r.data_in.alias_handle = self.handle + r.data_in.sid = string_to_sid(sid) + + call_fn(dcerpc.dcerpc_samr_AddAliasMember, self.pipe, r) + + def AddMultipleMembersToAlias(self, sids): + + r = dcerpc.samr_AddMultipleMembersToAlias() + r.data_in.alias_handle = self.handle + r.data_in.sids = dcerpc.lsa_SidArray() + r.data_in.sids.num_sids = len(sids) + r.data_in.sids.sids = dcerpc.new_lsa_SidPtr_array(len(sids)) + + for i in range(len(sids)): + s = dcerpc.lsa_SidPtr() + s.sid = string_to_sid(sids[i]) + dcerpc.lsa_SidPtr_array_setitem(r.data_in.sids.sids, i, s) + + call_fn(dcerpc.dcerpc_samr_AddMultipleMembersToAlias, self.pipe, r) + + def GetMembersInAlias(self): + + r = dcerpc.samr_GetMembersInAlias() + r.data_in.alias_handle = self.handle + + call_fn(dcerpc.dcerpc_samr_GetMembersInAlias, self.pipe, r) + + return [ + sid_to_string( + dcerpc.lsa_SidPtr_array_getitem(r.data_out.sids.sids, x).sid) + for x in range(r.data_out.sids.num_sids)] + +def Connect(pipe, access_mask = 0x02000000): + + r = dcerpc.samr_Connect() + r.data_in.system_name = dcerpc.new_uint16_array(1) + dcerpc.uint16_array_setitem(r.data_in.system_name, 0, ord('\\')) + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +def Connect2(pipe, system_name = '', access_mask = 0x02000000): + """Connect to the SAMR pipe.""" + + r = dcerpc.samr_Connect2() + r.data_in.system_name = system_name + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect2, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +def Connect3(pipe, system_name = '', access_mask = 0x02000000): + + r = dcerpc.samr_Connect3() + r.data_in.system_name = system_name + r.data_in.unknown = 0 + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect3, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + + +def Connect4(pipe, system_name = '', access_mask = 0x02000000): + + r = dcerpc.samr_Connect4() + r.data_in.system_name = system_name + r.data_in.unknown = 0 + r.data_in.access_mask = access_mask + + call_fn(dcerpc.dcerpc_samr_Connect4, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +def Connect5(pipe, system_name = '', access_mask = 0x02000000): + + r = dcerpc.samr_Connect5() + r.data_in.system_name = system_name + r.data_in.access_mask = access_mask + r.data_in.level = 1 + r.data_in.info = dcerpc.new_samr_ConnectInfo_array(1) + r.data_in.info.unknown1 = 0 + r.data_in.info.unknown2 = 0 + + call_fn(dcerpc.dcerpc_samr_Connect5, pipe, r) + + return ConnectHandle(pipe, r.data_out.connect_handle) + +# AddGroupMember +# DeleteDomainGroup +# DeleteGroupMember +# SetMemberAttributesofGroup +# AddAliasMember +# DeleteAliasMember +# GetMembersinAlias +# SetUserInfo +# ChangePasswordUser +# GetDisplayEnumerationIndex +# RemoveMemberFromForeignDomain +# GetDisplayEnumerationIndex2 +# RemoveMultipleMembersFromAlias +# OemChangePasswordUser2 +# ChangePasswordUser2 +# SetUserInfo2 +# ChangePasswordUser3 +# SetDsrmPassword +# ValidatePassword diff --git a/source4/scripting/python/samba/torture/pytorture b/source4/scripting/python/samba/torture/pytorture new file mode 100755 index 0000000000..e0123447e8 --- /dev/null +++ b/source4/scripting/python/samba/torture/pytorture @@ -0,0 +1,51 @@ +#!/usr/bin/python + +import sys +from optparse import OptionParser + +# Parse command line + +parser = OptionParser() + +parser.add_option("-b", "--binding", action="store", type="string", + dest="binding") + +parser.add_option("-d", "--domain", action="store", type="string", + dest="domain") + +parser.add_option("-u", "--username", action="store", type="string", + dest="username") + +parser.add_option("-p", "--password", action="store", type="string", + dest="password") + +(options, args) = parser.parse_args() + +if not options.binding: + parser.error('You must supply a binding string') + +if not options.username or not options.password or not options.domain: + parser.error('You must supply a domain, username and password') + +binding = options.binding +domain = options.domain +username = options.username +password = options.password + +if len(args) == 0: + parser.error('You must supply the name of a module to test') + +# Import and test + +for test in args: + + try: + module = __import__('torture_%s' % test) + except ImportError: + print 'No such module "%s"' % test + sys.exit(1) + + if not hasattr(module, 'runtests'): + print 'Module "%s" does not have a runtests function' % test + + module.runtests(binding, (domain, username, password)) diff --git a/source4/scripting/python/samba/torture/spoolss.py b/source4/scripting/python/samba/torture/spoolss.py new file mode 100644 index 0000000000..a75385e079 --- /dev/null +++ b/source4/scripting/python/samba/torture/spoolss.py @@ -0,0 +1,437 @@ +import sys, string +import dcerpc + + +def ResizeBufferCall(fn, pipe, r): + + r['buffer'] = None + r['buf_size'] = 0 + + result = fn(pipe, r) + + if result['result'] == dcerpc.WERR_INSUFFICIENT_BUFFER or \ + result['result'] == dcerpc.WERR_MORE_DATA: + r['buffer'] = result['buf_size'] * '\x00' + r['buf_size'] = result['buf_size'] + + result = fn(pipe, r) + + return result + + +def test_OpenPrinterEx(pipe, printer): + + print 'spoolss_OpenPrinterEx(%s)' % printer + + printername = '\\\\%s' % dcerpc.dcerpc_server_name(pipe) + + if printer is not None: + printername = printername + '\\%s' % printer + + r = {} + r['printername'] = printername + r['datatype'] = None + r['devmode_ctr'] = {} + r['devmode_ctr']['size'] = 0 + r['devmode_ctr']['devmode'] = None + r['access_mask'] = 0x02000000 + r['level'] = 1 + r['userlevel'] = {} + r['userlevel']['level1'] = {} + r['userlevel']['level1']['size'] = 0 + r['userlevel']['level1']['client'] = None + r['userlevel']['level1']['user'] = None + r['userlevel']['level1']['build'] = 1381 + r['userlevel']['level1']['major'] = 2 + r['userlevel']['level1']['minor'] = 0 + r['userlevel']['level1']['processor'] = 0 + + result = dcerpc.spoolss_OpenPrinterEx(pipe, r) + + return result['handle'] + + +def test_ClosePrinter(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.spoolss_ClosePrinter(pipe, r) + + +def test_GetPrinter(pipe, handle): + + r = {} + r['handle'] = handle + + for level in [0, 1, 2, 3, 4, 5, 6, 7]: + + print 'spoolss_GetPrinter(level = %d)' % level + + r['level'] = level + r['buffer'] = None + r['buf_size'] = 0 + + result = ResizeBufferCall(dcerpc.spoolss_GetPrinter, pipe, r) + + +def test_EnumForms(pipe, handle): + + print 'spoolss_EnumForms()' + + r = {} + r['handle'] = handle + r['level'] = 1 + r['buffer'] = None + r['buf_size'] = 0 + + result = ResizeBufferCall(dcerpc.spoolss_EnumForms, pipe, r) + + forms = dcerpc.unmarshall_spoolss_FormInfo_array( + result['buffer'], r['level'], result['count']) + + for form in forms: + + r = {} + r['handle'] = handle + r['formname'] = form['info1']['formname'] + r['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_GetForm, pipe, r) + + +def test_EnumPorts(pipe, handle): + + print 'spoolss_EnumPorts()' + + for level in [1, 2]: + + r = {} + r['handle'] = handle + r['servername'] = None + r['level'] = level + + result = ResizeBufferCall(dcerpc.spoolss_EnumPorts, pipe, r) + + ports = dcerpc.unmarshall_spoolss_PortInfo_array( + result['buffer'], r['level'], result['count']) + + if level == 1: + port_names = map(lambda x: x['info1']['port_name'], ports) + + +def test_DeleteForm(pipe, handle, formname): + + r = {} + r['handle'] = handle + r['formname'] = formname + + dcerpc.spoolss_DeleteForm(pipe, r) + + +def test_GetForm(pipe, handle, formname): + + r = {} + r['handle'] = handle + r['formname'] = formname + r['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_GetForm, pipe, r) + + return result['info']['info1'] + + +def test_SetForm(pipe, handle, form): + + print 'spoolss_SetForm()' + + r = {} + r['handle'] = handle + r['level'] = 1 + r['formname'] = form['info1']['formname'] + r['info'] = form + + dcerpc.spoolss_SetForm(pipe, r) + + newform = test_GetForm(pipe, handle, r['formname']) + + if form['info1'] != newform: + print 'SetForm: mismatch: %s != %s' % \ + (r['info']['info1'], f) + sys.exit(1) + + +def test_AddForm(pipe, handle): + + print 'spoolss_AddForm()' + + formname = '__testform__' + + r = {} + r['handle'] = handle + r['level'] = 1 + r['info'] = {} + r['info']['info1'] = {} + r['info']['info1']['formname'] = formname + r['info']['info1']['flags'] = 0x0002 + r['info']['info1']['width'] = 100 + r['info']['info1']['length'] = 100 + r['info']['info1']['left'] = 0 + r['info']['info1']['top'] = 1000 + r['info']['info1']['right'] = 2000 + r['info']['info1']['bottom'] = 3000 + + try: + result = dcerpc.spoolss_AddForm(pipe, r) + except dcerpc.WERROR, arg: + if arg[0] == dcerpc.WERR_ALREADY_EXISTS: + test_DeleteForm(pipe, handle, formname) + result = dcerpc.spoolss_AddForm(pipe, r) + + f = test_GetForm(pipe, handle, formname) + + if r['info']['info1'] != f: + print 'AddForm: mismatch: %s != %s' % \ + (r['info']['info1'], f) + sys.exit(1) + + r['formname'] = formname + + test_SetForm(pipe, handle, r['info']) + + test_DeleteForm(pipe, handle, formname) + + +def test_EnumJobs(pipe, handle): + + print 'spoolss_EnumJobs()' + + r = {} + r['handle'] = handle + r['firstjob'] = 0 + r['numjobs'] = 0xffffffff + r['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_EnumJobs, pipe, r) + + if result['buffer'] is None: + return + + jobs = dcerpc.unmarshall_spoolss_JobInfo_array( + result['buffer'], r['level'], result['count']) + + for job in jobs: + + s = {} + s['handle'] = handle + s['job_id'] = job['info1']['job_id'] + s['level'] = 1 + + result = ResizeBufferCall(dcerpc.spoolss_GetJob, pipe, s) + + if result['info'] != job: + print 'EnumJobs: mismatch: %s != %s' % (result['info'], job) + sys.exit(1) + + + # TODO: AddJob, DeleteJob, ScheduleJob + + +def test_EnumPrinterData(pipe, handle): + + print 'test_EnumPrinterData()' + + enum_index = 0 + + while 1: + + r = {} + r['handle'] = handle + r['enum_index'] = enum_index + + r['value_offered'] = 0 + r['data_size'] = 0 + + result = dcerpc.spoolss_EnumPrinterData(pipe, r) + + r['value_offered'] = result['value_needed'] + r['data_size'] = result['data_size'] + + result = dcerpc.spoolss_EnumPrinterData(pipe, r) + + if result['result'] == dcerpc.WERR_NO_MORE_ITEMS: + break + + s = {} + s['handle'] = handle + s['value_name'] = result['value_name'] + + result2 = ResizeBufferCall(dcerpc.spoolss_GetPrinterData, pipe, s) + + if result['buffer'][:result2['buf_size']] != result2['buffer']: + print 'EnumPrinterData/GetPrinterData mismatch' + sys.exit(1) + + enum_index += 1 + + +def test_SetPrinterDataEx(pipe, handle): + + valuename = '__printerdataextest__' + data = '12345' + + r = {} + r['handle'] = handle + r['key_name'] = 'DsSpooler' + r['value_name'] = valuename + r['type'] = 3 + r['buffer'] = data + r['buf_size'] = len(data) + + result = dcerpc.spoolss_SetPrinterDataEx(pipe, r) + + +def test_EnumPrinterDataEx(pipe, handle): + + r = {} + r['handle'] = handle + r['key_name'] = 'DsSpooler' + r['buf_size'] = 0 + + result = dcerpc.spoolss_EnumPrinterDataEx(pipe, r) + + if result['result'] == dcerpc.WERR_MORE_DATA: + r['buf_size'] = result['buf_size'] + + result = dcerpc.spoolss_EnumPrinterDataEx(pipe, r) + + # TODO: test spoolss_GetPrinterDataEx() + + +def test_SetPrinterData(pipe, handle): + + print 'testing spoolss_SetPrinterData()' + + valuename = '__printerdatatest__' + data = '12345' + + r = {} + r['handle'] = handle + r['value_name'] = valuename + r['type'] = 3 # REG_BINARY + r['buffer'] = data + r['real_len'] = 5 + + dcerpc.spoolss_SetPrinterData(pipe, r) + + s = {} + s['handle'] = handle + s['value_name'] = valuename + + result = ResizeBufferCall(dcerpc.spoolss_GetPrinterData, pipe, r) + + if result['buffer'] != data: + print 'SetPrinterData: mismatch' + sys.exit(1) + + dcerpc.spoolss_DeletePrinterData(pipe, r) + + +def test_EnumPrinters(pipe): + + print 'testing spoolss_EnumPrinters()' + + printer_names = None + + r = {} + r['flags'] = 0x02 + r['server'] = None + + for level in [0, 1, 2, 4, 5]: + + print 'test_EnumPrinters(level = %d)' % level + + r['level'] = level + + result = ResizeBufferCall(dcerpc.spoolss_EnumPrinters, pipe, r) + + printers = dcerpc.unmarshall_spoolss_PrinterInfo_array( + result['buffer'], r['level'], result['count']) + + if level == 2: + for p in printers: + + # A nice check is for the specversion in the + # devicemode. This has always been observed to be + # 1025. + + if p['info2']['devmode']['specversion'] != 1025: + print 'test_EnumPrinters: specversion != 1025' + sys.exit(1) + + r['level'] = 1 + result = ResizeBufferCall(dcerpc.spoolss_EnumPrinters, pipe, r) + + for printer in dcerpc.unmarshall_spoolss_PrinterInfo_array( + result['buffer'], r['level'], result['count']): + + if string.find(printer['info1']['name'], '\\\\') == 0: + print 'Skipping remote printer %s' % printer['info1']['name'] + continue + + printername = string.split(printer['info1']['name'], ',')[0] + + handle = test_OpenPrinterEx(pipe, printername) + + test_GetPrinter(pipe, handle) + test_EnumPorts(pipe, handle) + test_EnumForms(pipe, handle) + test_AddForm(pipe, handle) + test_EnumJobs(pipe, handle) + test_EnumPrinterData(pipe, handle) + test_EnumPrinterDataEx(pipe, handle) + test_SetPrinterData(pipe, handle) +# test_SetPrinterDataEx(pipe, handle) + test_ClosePrinter(pipe, handle) + + +def test_EnumPrinterDrivers(pipe): + + print 'test spoolss_EnumPrinterDrivers()' + + for level in [1, 2, 3]: + + r = {} + r['server'] = None + r['environment'] = None + r['level'] = level + + result = ResizeBufferCall(dcerpc.spoolss_EnumPrinterDrivers, pipe, r) + + drivers = dcerpc.unmarshall_spoolss_DriverInfo_array( + result['buffer'], r['level'], result['count']) + + if level == 1: + driver_names = map(lambda x: x['info1']['driver_name'], drivers) + + +def test_PrintServer(pipe): + + handle = test_OpenPrinterEx(pipe, None) + + # EnumForms and AddForm tests return WERR_BADFID here (??) + + test_ClosePrinter(pipe, handle) + + +def runtests(binding, domain, username, password): + + print 'Testing SPOOLSS pipe' + + pipe = dcerpc.pipe_connect(binding, + dcerpc.DCERPC_SPOOLSS_UUID, dcerpc.DCERPC_SPOOLSS_VERSION, + domain, username, password) + + test_EnumPrinters(pipe) + test_EnumPrinterDrivers(pipe) + test_PrintServer(pipe) diff --git a/source4/scripting/python/samba/torture/torture_samr.py b/source4/scripting/python/samba/torture/torture_samr.py new file mode 100755 index 0000000000..15c6dc1a76 --- /dev/null +++ b/source4/scripting/python/samba/torture/torture_samr.py @@ -0,0 +1,221 @@ +#!/usr/bin/python + +import sys +import dcerpc, samr + +def test_Connect(pipe): + + handle = samr.Connect(pipe) + handle = samr.Connect2(pipe) + handle = samr.Connect3(pipe) + handle = samr.Connect4(pipe) + + # WIN2K3 only? + + try: + handle = samr.Connect5(pipe) + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xc00000d2L: # NT_STATUS_NET_WRITE_FAULT + raise + + return handle + +def test_UserHandle(user_handle): + + # QuerySecurity()/SetSecurity() + + user_handle.SetSecurity(user_handle.QuerySecurity()) + + # GetUserPwInfo() + + user_handle.GetUserPwInfo() + + # GetUserInfo() + + for level in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 20, + 21, 23, 24, 25, 26]: + + try: + user_handle.QueryUserInfo(level) + user_handle.QueryUserInfo2(level) + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xc0000003L: # NT_STATUS_INVALID_INFO_CLASS + raise + + # GetGroupsForUser() + + user_handle.GetGroupsForUser() + + # TestPrivateFunctionsUser() + + try: + user_handle.TestPrivateFunctionsUser() + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xC0000002L: + raise + +def test_GroupHandle(group_handle): + + # QuerySecurity()/SetSecurity() + + group_handle.SetSecurity(group_handle.QuerySecurity()) + + # QueryGroupInfo() + + for level in [1, 2, 3, 4, 5]: + info = group_handle.QueryGroupInfo(level) + + # TODO: SetGroupinfo() + + # QueryGroupMember() + + group_handle.QueryGroupMember() + +def test_AliasHandle(alias_handle): + + # QuerySecurity()/SetSecurity() + + alias_handle.SetSecurity(alias_handle.QuerySecurity()) + + print alias_handle.GetMembersInAlias() + +def test_DomainHandle(name, sid, domain_handle): + + print 'testing %s (%s)' % (name, sid) + + # QuerySecurity()/SetSecurity() + + domain_handle.SetSecurity(domain_handle.QuerySecurity()) + + # LookupNames(), none mapped + + try: + domain_handle.LookupNames(['xxNONAMExx']) + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xc0000073L: + raise dcerpc.NTSTATUS(arg) + + # LookupNames(), some mapped + + if name != 'Builtin': + domain_handle.LookupNames(['Administrator', 'xxNONAMExx']) + + # QueryDomainInfo()/SetDomainInfo() + + levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13] + set_ok = [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0] + + for i in range(len(levels)): + + info = domain_handle.QueryDomainInfo(level = levels[i]) + + try: + domain_handle.SetDomainInfo(levels[i], info) + except dcerpc.NTSTATUS, arg: + if not (arg[0] == 0xc0000003L and not set_ok[i]): + raise + + # QueryDomainInfo2() + + levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13] + + for i in range(len(levels)): + domain_handle.QueryDomainInfo2(level = levels[i]) + + # EnumDomainUsers + + print 'testing users' + + users = domain_handle.EnumDomainUsers() + rids = domain_handle.LookupNames(users) + + for i in range(len(users)): + test_UserHandle(domain_handle.OpenUser(rids[0][i])) + + # QueryDisplayInfo + + for i in [1, 2, 3, 4, 5]: + domain_handle.QueryDisplayInfo(level = i) + domain_handle.QueryDisplayInfo2(level = i) + domain_handle.QueryDisplayInfo3(level = i) + + # EnumDomainGroups + + print 'testing groups' + + groups = domain_handle.EnumDomainGroups() + rids = domain_handle.LookupNames(groups) + + for i in range(len(groups)): + test_GroupHandle(domain_handle.OpenGroup(rids[0][i])) + + # EnumDomainAliases + + print 'testing aliases' + + aliases = domain_handle.EnumDomainAliases() + rids = domain_handle.LookupNames(aliases) + + for i in range(len(aliases)): + test_AliasHandle(domain_handle.OpenAlias(rids[0][i])) + + # CreateUser + # CreateUser2 + # CreateDomAlias + # RidToSid + # RemoveMemberFromForeignDomain + # CreateDomainGroup + # GetAliasMembership + + # GetBootKeyInformation() + + try: + domain_handle.GetBootKeyInformation() + except dcerpc.NTSTATUS, arg: + pass + + # TestPrivateFunctionsDomain() + + try: + domain_handle.TestPrivateFunctionsDomain() + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xC0000002L: + raise + +def test_ConnectHandle(connect_handle): + + print 'testing connect handle' + + # QuerySecurity/SetSecurity + + connect_handle.SetSecurity(connect_handle.QuerySecurity()) + + # Lookup bogus domain + + try: + connect_handle.LookupDomain('xxNODOMAINxx') + except dcerpc.NTSTATUS, arg: + if arg[0] != 0xC00000DFL: # NT_STATUS_NO_SUCH_DOMAIN + raise + + # Test all domains + + for domain_name in connect_handle.EnumDomains(): + + connect_handle.GetDomPwInfo(domain_name) + sid = connect_handle.LookupDomain(domain_name) + domain_handle = connect_handle.OpenDomain(sid) + + test_DomainHandle(domain_name, sid, domain_handle) + + # TODO: Test Shutdown() function + +def runtests(binding, creds): + + print 'Testing SAMR pipe' + + pipe = dcerpc.pipe_connect(binding, + dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION), creds) + + handle = test_Connect(pipe) + test_ConnectHandle(handle) diff --git a/source4/scripting/python/samba/torture/torture_tdb.py b/source4/scripting/python/samba/torture/torture_tdb.py new file mode 100755 index 0000000000..7f97caf6cb --- /dev/null +++ b/source4/scripting/python/samba/torture/torture_tdb.py @@ -0,0 +1,90 @@ +#!/usr/bin/python + +import sys, os +import Tdb + +def fail(msg): + print 'FAILED:', msg + sys.exit(1) + +tdb_file = '/tmp/torture_tdb.tdb' + +# Create temporary tdb file + +t = Tdb.Tdb(tdb_file, flags = Tdb.CLEAR_IF_FIRST) + +# Check non-existent key throws KeyError exception + +try: + t['__none__'] +except KeyError: + pass +else: + fail('non-existent key did not throw KeyError') + +# Check storing key + +t['bar'] = '1234' +if t['bar'] != '1234': + fail('store key failed') + +# Check key exists + +if not t.has_key('bar'): + fail('has_key() failed for existing key') + +if t.has_key('__none__'): + fail('has_key() succeeded for non-existent key') + +# Delete key + +try: + del(t['__none__']) +except KeyError: + pass +else: + fail('delete of non-existent key did not throw KeyError') + +del t['bar'] +if t.has_key('bar'): + fail('delete of existing key did not delete key') + +# Clear all keys + +t.clear() +if len(t) != 0: + fail('clear failed to remove all keys') + +# Other dict functions + +t['a'] = '1' +t['ab'] = '12' +t['abc'] = '123' + +if len(t) != 3: + fail('len method produced wrong value') + +keys = t.keys() +values = t.values() +items = t.items() + +if set(keys) != set(['a', 'ab', 'abc']): + fail('keys method produced wrong values') + +if set(values) != set(['1', '12', '123']): + fail('values method produced wrong values') + +if set(items) != set([('a', '1'), ('ab', '12'), ('abc', '123')]): + fail('values method produced wrong values') + +t.close() + +# Re-open read-only + +t = Tdb.Tdb(tdb_file, open_flags = os.O_RDONLY) +t.keys() +t.close() + +# Clean up + +os.unlink(tdb_file) diff --git a/source4/scripting/python/samba/torture/winreg.py b/source4/scripting/python/samba/torture/winreg.py new file mode 100755 index 0000000000..eb60b9847e --- /dev/null +++ b/source4/scripting/python/samba/torture/winreg.py @@ -0,0 +1,165 @@ +#!/usr/bin/python + +import sys, dcerpc + +def test_OpenHKLM(pipe): + + r = {} + r['unknown'] = {} + r['unknown']['unknown0'] = 0x9038 + r['unknown']['unknown1'] = 0x0000 + r['access_required'] = 0x02000000 + + result = dcerpc.winreg_OpenHKLM(pipe, r) + + return result['handle'] + +def test_QueryInfoKey(pipe, handle): + + r = {} + r['handle'] = handle + r['class'] = {} + r['class']['name'] = None + + return dcerpc.winreg_QueryInfoKey(pipe, r) + +def test_CloseKey(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.winreg_CloseKey(pipe, r) + +def test_FlushKey(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.winreg_FlushKey(pipe, r) + +def test_GetVersion(pipe, handle): + + r = {} + r['handle'] = handle + + dcerpc.winreg_GetVersion(pipe, r) + +def test_GetKeySecurity(pipe, handle): + + r = {} + r['handle'] = handle + r['unknown'] = 4 + r['size'] = None + r['data'] = {} + r['data']['max_len'] = 0 + r['data']['data'] = '' + + result = dcerpc.winreg_GetKeySecurity(pipe, r) + + print result + + if result['result'] == dcerpc.WERR_INSUFFICIENT_BUFFER: + r['size'] = {} + r['size']['max_len'] = result['data']['max_len'] + r['size']['offset'] = 0 + r['size']['len'] = result['data']['max_len'] + + result = dcerpc.winreg_GetKeySecurity(pipe, r) + + print result + + sys.exit(1) + +def test_Key(pipe, handle, name, depth = 0): + + # Don't descend too far. Registries can be very deep. + + if depth > 2: + return + + try: + keyinfo = test_QueryInfoKey(pipe, handle) + except dcerpc.WERROR, arg: + if arg[0] == dcerpc.WERR_ACCESS_DENIED: + return + + test_GetVersion(pipe, handle) + + test_FlushKey(pipe, handle) + + test_GetKeySecurity(pipe, handle) + + # Enumerate values in this key + + r = {} + r['handle'] = handle + r['name_in'] = {} + r['name_in']['len'] = 0 + r['name_in']['max_len'] = (keyinfo['max_valnamelen'] + 1) * 2 + r['name_in']['buffer'] = {} + r['name_in']['buffer']['max_len'] = keyinfo['max_valnamelen'] + 1 + r['name_in']['buffer']['offset'] = 0 + r['name_in']['buffer']['len'] = 0 + r['type'] = 0 + r['value_in'] = {} + r['value_in']['max_len'] = keyinfo['max_valbufsize'] + r['value_in']['offset'] = 0 + r['value_in']['len'] = 0 + r['value_len1'] = keyinfo['max_valbufsize'] + r['value_len2'] = 0 + + for i in range(0, keyinfo['num_values']): + + r['enum_index'] = i + + dcerpc.winreg_EnumValue(pipe, r) + + # Recursively test subkeys of this key + + r = {} + r['handle'] = handle + r['key_name_len'] = 0 + r['unknown'] = 0x0414 + r['in_name'] = {} + r['in_name']['unknown'] = 0x20a + r['in_name']['key_name'] = {} + r['in_name']['key_name']['name'] = None + r['class'] = {} + r['class']['name'] = None + r['last_changed_time'] = {} + r['last_changed_time']['low'] = 0 + r['last_changed_time']['high'] = 0 + + for i in range(0, keyinfo['num_subkeys']): + + r['enum_index'] = i + + subkey = dcerpc.winreg_EnumKey(pipe, r) + + s = {} + s['handle'] = handle + s['keyname'] = {} + s['keyname']['name'] = subkey['out_name']['name'] + s['unknown'] = 0 + s['access_mask'] = 0x02000000 + + result = dcerpc.winreg_OpenKey(pipe, s) + + test_Key(pipe, result['handle'], name + '/' + s['keyname']['name'], + depth + 1) + + test_CloseKey(pipe, result['handle']) + + # Enumerate values + +def runtests(binding, domain, username, password): + + print 'Testing WINREG pipe' + + pipe = dcerpc.pipe_connect(binding, + dcerpc.DCERPC_WINREG_UUID, dcerpc.DCERPC_WINREG_VERSION, + domain, username, password) + + handle = test_OpenHKLM(pipe) + + test_Key(pipe, handle, 'HKLM') -- cgit From c926cddfad97713ca017c03e61c6e90414c1ad62 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 10 Dec 2007 09:29:00 +0100 Subject: r26366: Import provision scripts in Python. (This used to be commit 090c799f98adf2c4186daca445c81b4e26e91f2f) --- source4/scripting/python/samba/provision.py | 842 ++++++++++++++++++++++++++++ source4/scripting/python/samba/upgrade.py | 561 ++++++++++++++++++ 2 files changed, 1403 insertions(+) create mode 100644 source4/scripting/python/samba/provision.py create mode 100644 source4/scripting/python/samba/upgrade.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py new file mode 100644 index 0000000000..3d391863da --- /dev/null +++ b/source4/scripting/python/samba/provision.py @@ -0,0 +1,842 @@ +# +# backend code for provisioning a Samba4 server +# Copyright Andrew Tridgell 2005 +# Copyright Jelmer Vernooij 2007 +# Released under the GNU GPL v2 or later +# + +from base64 import b64encode +import os +import pwd +import grp +import time +import uuid, sid, misc +from socket import gethostname, gethostbyname +import param +import registry +from samba import Ldb, substitute_var +from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ + LDB_ERR_NO_SUCH_OBJECT, timestring + + +class InvalidNetbiosName(Exception): + def __init__(self, name): + super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name) + + +class ProvisionSettings(object): + def __init__(self, realm=None, domain=None, hostname=None, hostip=None): + self.realm = realm + self.domain = domain + self.hostname = hostname + self.hostip = hostip + self.domainsid = None + self.invocationid = None + self.krbtgtpass = None + self.machinepass = None + self.adminpass = None + self.defaultsite = "Default-First-Site-Name" + self.datestring = None + self.root = None + self.nobody = None + self.nogroup = None + self.wheel = None + self.backup = None + self.users = None + self.dnsdomain = None + self.dnsname = None + self.domaindn = None + self.domaindn_ldb = None + self.rootdn = None + self.configdn = None + self.configdn_ldb = None + self.schemedn = None + self.schemedn_ldb = None + self.s4_ldapi_path = None + self.policyguid = None + + def subst_vars(self): + return {"SCHEMADN": self.schemadn, + "SCHEMADN_LDB": self.schemadn_ldb, + "SCHEMADN_MOD": "schema_fsmo", + "SCHEMADN_MOD2": ",objectguid", + "CONFIGDN": self.configdn, + "TDB_MODULES_LIST": ","+",".join(self.tdb_modules_list) + "MODULES_LIST2": ",".join(self.modules_list2) + "CONFIGDN_LDB": self.configdn_ldb, + "DOMAINDN": self.domaindn, + "DOMAINDN_LDB": self.domaindn_ldb, + "DOMAINDN_MOD": "pdc_fsmo,password_hash", + "DOMAINDN_MOD2": ",objectguid", + "DOMAINSID": self.domainsid, + "MODULES_LIST": ",".join(self.modules_list), + "CONFIGDN_MOD": "naming_fsmo", + "CONFIGDN_MOD2": ",objectguid", + "NETBIOSNAME": self.netbiosname, + "DNSNAME": self.dnsname, + "ROOTDN": self.rootdn, + "DNSDOMAIN": self.dnsdomain, + "REALM": self.realm, + "DEFAULTSITE": self.defaultsite, + "MACHINEPASS_B64": b64encode(self.machinepass), + "ADMINPASS_B64": b64encode(self.adminpass), + "DNSPASS_B64": b64encode(self.dnspass), + "KRBTGTPASS_B64": b64encode(self.krbtgtpass), + "S4_LDAPI_URI": "ldapi://%s" % self.s4_ldapi_path.replace("/", "%2F"), + "LDAPTIME": timestring(int(time.time())), + "POLICYGUID": self.policyguid, + "RDN_DC": self.rdn_dc, + "DOMAINGUID_MOD": self.domainguid_mod, + } + + def fix(self, paths): + self.realm = self.realm.upper() + self.hostname = self.hostname.lower() + self.domain = self.domain.upper() + if not valid_netbios_name(self.domain): + raise InvalidNetbiosName(self.domain) + self.netbiosname = self.hostname.upper() + if not valid_netbios_name(self.netbiosname): + raise InvalidNetbiosName(self.netbiosname) + rdns = self.domaindn.split(",") + self.rdn_dc = rdns[0][len("DC="):] + + self.sam_ldb = paths.samdb + self.secrets_ldb = paths.secrets + self.secrets_keytab = paths.keytab + + self.s4_ldapi_path = paths.s4_ldapi_path + + def validate(self, lp): + if not valid_netbios_name(self.domain): + raise InvalidNetbiosName(self.domain) + + if not valid_netbios_name(self.netbiosname): + raise InvalidNetbiosName(self.netbiosname) + + if lp.get("workgroup").upper() != self.domain.upper(): + raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", + lp.get("workgroup"), self.domain) + + if lp.get("realm").upper() != self.realm.upper(): + raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % + (lp.get("realm"), self.realm)) + + +class ProvisionPaths: + def __init__(self): + self.smbconf = None + self.shareconf = None + self.hklm = None + self.hkcu = None + self.hkcr = None + self.hku = None + self.hkpd = None + self.hkpt = None + self.samdb = None + self.secrets = None + self.keytab = None + self.dns = None + self.winsdb = None + self.ldap_basedn_ldif = None + self.ldap_config_basedn_ldif = None + self.ldap_schema_basedn_ldif = None + self.s4_ldapi_path = None + + +def install_ok(lp, session_info, credentials): + """Check whether the current install seems ok.""" + if lp.get("realm") == "": + return False + ldb = Ldb(lp.get("sam database"), session_info=session_info, + credentials=credentials) + if len(ldb.search("(cn=Administrator)")) != 1: + return False + return True + + +def findnss(nssfn, *names): + """Find a user or group from a list of possibilities.""" + for name in names: + try: + return nssfn(name) + except KeyError: + pass + raise Exception("Unable to find user/group for %s" % arguments[1]) + +def add_foreign(ldb, subobj, sid, desc): + """Add a foreign security principle.""" + add = """ +dn: CN=%s,CN=ForeignSecurityPrincipals,%s +objectClass: top +objectClass: foreignSecurityPrincipal +description: %s +""" % (sid, subobj.domaindn, desc) + # deliberately ignore errors from this, as the records may + # already exist + for msg in ldb.parse_ldif(add): + ldb.add(msg[1]) + +def setup_name_mapping(subobj, ldb, sid, unixname): + """Setup a mapping between a sam name and a unix name.""" + res = ldb.search(Dn(ldb, subobj.domaindn), SCOPE_SUBTREE, + "objectSid=%s" % sid, ["dn"]) + assert len(res) == 1, "Failed to find record for objectSid %s" % sid + + mod = """ +dn: %s +changetype: modify +replace: unixName +unixName: %s +""" % (res[0].dn, unixname) + ldb.modify(ldb.parse_ldif(mod).next()[1]) + +def hostip(): + """return first host IP.""" + return gethostbyname(hostname()) + +def hostname(): + """return first part of hostname.""" + return gethostname().split(".")[0] + +def ldb_delete(ldb): + """Delete a LDB file. + + This may be necessary if the ldb is in bad shape, possibly due to being + built from an incompatible previous version of the code, so delete it + completely. + """ + print "Deleting %s\n" % ldb.filename + os.unlink(ldb.filename) + ldb.connect(ldb.filename) + + +def ldb_erase(ldb): + """Erase an ldb, removing all records.""" + # delete the specials + for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", + "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: + try: + ldb.delete(Dn(ldb, attr)) + except LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + pass + + basedn = Dn(ldb, "") + # and the rest + for msg in ldb.search(basedn, SCOPE_SUBTREE, + "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", + ["dn"]): + ldb.delete(msg.dn) + + res = ldb.search(basedn, SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) + assert len(res) == 0 + + +def ldb_erase_partitions(subobj, message, ldb, ldapbackend): + """Erase an ldb, removing all records.""" + assert ldb is not None + res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)", + ["namingContexts"]) + assert len(res) == 1 + if not "namingContexts" in res[0]: + return + for basedn in res[0]["namingContexts"]: + anything = "(|(objectclass=*)(dn=*))" + previous_remaining = 1 + current_remaining = 0 + + if ldapbackend and (basedn == subobj.domaindn): + # Only delete objects that were created by provision + anything = "(objectcategory=*)" + + k = 0 + while ++k < 10 and (previous_remaining != current_remaining): + # and the rest + res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"]) + previous_remaining = current_remaining + current_remaining = len(res2) + for msg in res2: + try: + ldb.delete(msg.dn) + except LdbError, (_, text): + message("Unable to delete %s: %s" % (msg.dn, text)) + + +def open_ldb(session_info, credentials, dbname): + assert session_info is not None + try: + return Ldb(dbname, session_info=session_info, credentials=credentials) + except LdbError, e: + print e + os.unlink(dbname) + return Ldb(dbname, session_info=session_info, credentials=credentials) + + +def setup_add_ldif(setup_dir, ldif, subobj, ldb): + """Setup a ldb in the private dir.""" + assert isinstance(ldif, str) + assert isinstance(setup_dir, str) + src = os.path.join(setup_dir, ldif) + + data = open(src, 'r').read() + data = substitute_var(data, subobj.subst_vars()) + + for msg in ldb.parse_ldif(data): + ldb.add(msg[1]) + + +def setup_modify_ldif(setup_dir, ldif, subobj, ldb): + src = os.path.join(setup_dir, ldif) + + data = open(src, 'r').read() + data = substitute_var(data, subobj.subst_vars()) + + for (changetype, msg) in ldb.parse_ldif(data): + ldb.modify(msg) + + +def setup_ldb(setup_dir, ldif, session_info, credentials, subobj, dbname, + erase=True): + assert dbname is not None + ldb = open_ldb(session_info, credentials, dbname) + assert ldb is not None + ldb.transaction_start() + try: + if erase: + ldb_erase(ldb); + setup_add_ldif(setup_dir, ldif, subobj, ldb) + except: + ldb.transaction_cancel() + raise + ldb.transaction_commit() + + +def setup_ldb_modify(setup_dir, ldif, subobj, ldb): + """Modify a ldb in the private dir.""" + src = os.path.join(setup_dir, ldif) + + data = open(src, 'r').read() + data = substitute_var(data, subobj.subst_vars()) + assert not "${" in data + + for (changetype, msg) in ldb.parse_ldif(data): + ldb.modify(msg) + + +def setup_file(setup_dir, template, message, fname, subobj): + """Setup a file in the private dir.""" + f = fname + src = os.path.join(setup_dir, template) + + os.unlink(f) + + data = open(src, 'r').read() + data = substitute_var(data, subobj.subst_vars()) + assert not "${" in data + + open(f, 'w').write(data) + + +def provision_default_paths(lp, subobj): + """Set the default paths for provisioning. + + :param lp: Loadparm context. + :param subobj: Object + """ + paths = ProvisionPaths() + private_dir = lp.get("private dir") + paths.shareconf = os.path.join(private_dir, "share.ldb") + paths.samdb = lp.get("sam database") or os.path.join(private_dir, "samdb.ldb") + paths.secrets = lp.get("secrets database") or os.path.join(private_dir, "secrets.ldb") + paths.templates = os.path.join(private_dir, "templates.ldb") + paths.keytab = os.path.join(private_dir, "secrets.keytab") + paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone") + paths.winsdb = os.path.join(private_dir, "wins.ldb") + paths.ldap_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + ".ldif") + paths.ldap_config_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + "-config.ldif") + paths.ldap_schema_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + "-schema.ldif") + paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") + paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php") + paths.hklm = os.path.join(private_dir, "hklm.ldb") + return paths + + +def setup_name_mappings(subobj, ldb): + """setup reasonable name mappings for sam names to unix names.""" + res = ldb.search(Dn(ldb, subobj.domaindn), SCOPE_BASE, "objectSid=*", + ["objectSid"]) + assert len(res) == 1 + assert "objectSid" in res[0] + sid = list(res[0]["objectSid"])[0] + + # add some foreign sids if they are not present already + add_foreign(ldb, subobj, "S-1-5-7", "Anonymous") + add_foreign(ldb, subobj, "S-1-1-0", "World") + add_foreign(ldb, subobj, "S-1-5-2", "Network") + add_foreign(ldb, subobj, "S-1-5-18", "System") + add_foreign(ldb, subobj, "S-1-5-11", "Authenticated Users") + + # some well known sids + setup_name_mapping(subobj, ldb, "S-1-5-7", subobj.nobody) + setup_name_mapping(subobj, ldb, "S-1-1-0", subobj.nogroup) + setup_name_mapping(subobj, ldb, "S-1-5-2", subobj.nogroup) + setup_name_mapping(subobj, ldb, "S-1-5-18", subobj.root) + setup_name_mapping(subobj, ldb, "S-1-5-11", subobj.users) + setup_name_mapping(subobj, ldb, "S-1-5-32-544", subobj.wheel) + setup_name_mapping(subobj, ldb, "S-1-5-32-545", subobj.users) + setup_name_mapping(subobj, ldb, "S-1-5-32-546", subobj.nogroup) + setup_name_mapping(subobj, ldb, "S-1-5-32-551", subobj.backup) + + # and some well known domain rids + setup_name_mapping(subobj, ldb, sid + "-500", subobj.root) + setup_name_mapping(subobj, ldb, sid + "-518", subobj.wheel) + setup_name_mapping(subobj, ldb, sid + "-519", subobj.wheel) + setup_name_mapping(subobj, ldb, sid + "-512", subobj.wheel) + setup_name_mapping(subobj, ldb, sid + "-513", subobj.users) + setup_name_mapping(subobj, ldb, sid + "-520", subobj.wheel) + + +def provision_become_dc(setup_dir, subobj, message, paths, session_info, + credentials): + assert session_info is not None + subobj.fix(paths) + + message("Setting up templates into %s" % paths.templates) + setup_ldb(setup_dir, "provision_templates.ldif", session_info, + credentials, subobj, paths.templates) + + # Also wipes the database + message("Setting up %s partitions" % paths.samdb) + setup_ldb(setup_dir, "provision_partitions.ldif", session_info, + credentials, subobj, paths.samdb) + + samdb = open_ldb(session_info, credentials, paths.samdb) + ldb.transaction_start() + try: + message("Setting up %s attributes" % paths.samdb) + setup_add_ldif(setup_dir, "provision_init.ldif", subobj, samdb) + + message("Setting up %s rootDSE" % paths.samdb) + setup_add_ldif(setup_dir, "provision_rootdse_add.ldif", subobj, samdb) + + message("Erasing data from partitions") + ldb_erase_partitions(subobj, message, samdb, undefined) + + message("Setting up %s indexes" % paths.samdb) + setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + message("Setting up %s" % paths.secrets) + setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, + subobj, paths.secrets) + + setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, + paths.secrets, False) + + +def provision(lp, setup_dir, subobj, message, blank, paths, session_info, + credentials, ldapbackend): + """Provision samba4 + + :note: caution, this wipes all existing data! + """ + subobj.fix(paths) + + if subobj.domain_guid is not None: + subobj.domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % subobj.domain_guid + else: + subobj.domainguid_mod = "" + + if subobj.host_guid is not None: + subobj.hostguid_add = "objectGUID: %s" % subobj.host_guid + else: + subobj.hostguid_add = "" + + assert paths.smbconf is not None + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(paths.smbconf): + message("Setting up smb.conf") + setup_file(setup_dir, "provision.smb.conf", message, paths.smbconf, subobj) + lp.reload() + + # only install a new shares config db if there is none + if not os.path.exists(paths.shareconf): + message("Setting up share.ldb") + setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj, paths.shareconf) + + message("Setting up %s" % paths.secrets) + setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, subobj, paths.secrets) + setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, paths.secrets, False) + + message("Setting up registry") + reg = registry.Registry() + # FIXME: Still fails for some reason: + #reg.mount(paths.hklm, registry.HKEY_LOCAL_MACHINE, []) + #reg.apply_patchfile(os.path.join(setup_dir, "provision.reg")) + + message("Setting up templates into %s" % paths.templates) + setup_ldb(setup_dir, "provision_templates.ldif", session_info, credentials, subobj, paths.templates) + + message("Setting up sam.ldb partitions") + setup_ldb(setup_dir, "provision_partitions.ldif", session_info, + credentials, subobj, paths.samdb) + + samdb = open_ldb(session_info, credentials, paths.samdb) + samdb.transaction_start() + try: + message("Setting up sam.ldb attributes") + setup_add_ldif(setup_dir, "provision_init.ldif", subobj, samdb) + + message("Setting up sam.ldb rootDSE") + setup_add_ldif(setup_dir, "provision_rootdse_add.ldif", subobj, samdb) + + message("Erasing data from partitions") + ldb_erase_partitions(subobj, message, samdb, ldapbackend) + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + message("Pre-loading the Samba 4 and AD schema") + + samdb = open_ldb(session_info, credentials, paths.samdb) + + samdb.set_domain_sid(subobj.domainsid) + + load_schema(setup_dir, subobj, samdb) + + samdb.transaction_start() + + try: + message("Adding DomainDN: %s (permitted to fail)" % subobj.domaindn) + setup_add_ldif(setup_dir, "provision_basedn.ldif", subobj, samdb) + message("Modifying DomainDN: " + subobj.domaindn + "") + setup_ldb_modify(setup_dir, "provision_basedn_modify.ldif", subobj, samdb) + + message("Adding configuration container (permitted to fail)") + setup_add_ldif(setup_dir, "provision_configuration_basedn.ldif", subobj, samdb) + message("Modifying configuration container") + setup_ldb_modify(setup_dir, "provision_configuration_basedn_modify.ldif", subobj, samdb) + + message("Adding schema container (permitted to fail)") + setup_add_ldif(setup_dir, "provision_schema_basedn.ldif", subobj, samdb) + message("Modifying schema container") + setup_ldb_modify(setup_dir, "provision_schema_basedn_modify.ldif", subobj, samdb) + message("Setting up sam.ldb Samba4 schema") + setup_add_ldif(setup_dir, "schema_samba4.ldif", subobj, samdb) + message("Setting up sam.ldb AD schema") + setup_add_ldif(setup_dir, "schema.ldif", subobj, samdb) + + message("Setting up sam.ldb configuration data") + setup_add_ldif(setup_dir, "provision_configuration.ldif", subobj, samdb) + + message("Setting up display specifiers") + setup_add_ldif(setup_dir, "display_specifiers.ldif", subobj, samdb) + + message("Adding users container (permitted to fail)") + setup_add_ldif(setup_dir, "provision_users_add.ldif", subobj, samdb) + message("Modifying users container") + setup_ldb_modify(setup_dir, "provision_users_modify.ldif", subobj, samdb) + message("Adding computers container (permitted to fail)") + setup_add_ldif(setup_dir, "provision_computers_add.ldif", subobj, samdb) + message("Modifying computers container") + setup_ldb_modify(setup_dir, "provision_computers_modify.ldif", subobj, samdb) + message("Setting up sam.ldb data") + setup_add_ldif(setup_dir, "provision.ldif", subobj, samdb) + + if blank: + message("Setting up sam.ldb index") + setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) + + message("Setting up sam.ldb rootDSE marking as syncronized") + setup_modify_ldif(setup_dir, "provision_rootdse_modify.ldif", subobj, samdb) + + samdb.transaction_commit() + return + + # message("Activate schema module") + # setup_modify_ldif("schema_activation.ldif", info, samdb, False) + # + # // (hack) Reload, now we have the schema loaded. + # commit_ok = samdb.transaction_commit() + # if (!commit_ok) { + # message("samdb commit failed: " + samdb.errstring() + "\n") + # assert(commit_ok) + # } + # samdb.close() + # + # samdb = open_ldb(info, paths.samdb, False) + # + message("Setting up sam.ldb users and groups") + setup_add_ldif(setup_dir, "provision_users.ldif", subobj, samdb) + + setup_name_mappings(subobj, samdb) + + message("Setting up sam.ldb index") + setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) + + message("Setting up sam.ldb rootDSE marking as syncronized") + setup_modify_ldif(setup_dir, "provision_rootdse_modify.ldif", subobj, samdb) + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + message("Setting up phpLDAPadmin configuration") + setup_file(setup_dir, "phpldapadmin-config.php", message, + paths.phpldapadminconfig, subobj) + message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) + + +def provision_dns(setup_dir, subobj, message, paths, session_info, credentials): + """Write out a DNS zone file, from the info in the current database.""" + message("Setting up DNS zone: %s" % subobj.dnsdomain) + # connect to the sam + ldb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) + + # These values may have changed, due to an incoming SamSync, + # or may not have been specified, so fetch them from the database + + res = ldb.search(Dn(ldb, subobj.domaindn), SCOPE_BASE, "objectGUID=*", + ["objectGUID"]) + assert(len(res) == 1) + assert(res[0]["objectGUID"] is not None) + subobj.domainguid = res[0]["objectGUID"] + + subobj.host_guid = searchone(ldb, subobj.domaindn, + "(&(objectClass=computer)(cn=%s))" % subobj.netbiosname, "objectGUID") + assert subobj.host_guid is not None + + setup_file(setup_dir, "provision.zone", message, paths.dns, subobj) + + message("Please install the zone located in %s into your DNS server" % paths.dns) + + +def provision_ldapbase(setup_dir, subobj, message, paths): + """Write out a DNS zone file, from the info in the current database.""" + message("Setting up LDAP base entry: %s" % subobj.domaindn) + rdns = subobj.domaindn.split(",") + subobj.extensibleobject = "objectClass: extensibleObject" + + subobj.rdn_dc = rdns[0][len("DC="):] + + setup_file(setup_dir, "provision_basedn.ldif", + message, paths.ldap_basedn_ldif, + subobj) + + setup_file(setup_dir, "provision_configuration_basedn.ldif", + message, paths.ldap_config_basedn_ldif, + subobj) + + setup_file(setup_dir, "provision_schema_basedn.ldif", + message, paths.ldap_schema_basedn_ldif, + subobj) + + message("Please install the LDIF located in " + paths.ldap_basedn_ldif + ", " + paths.ldap_config_basedn_ldif + " and " + paths.ldap_schema_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server") + + +def provision_guess(lp): + """guess reasonably default options for provisioning.""" + subobj = ProvisionSettings(realm=lp.get("realm").upper(), + domain=lp.get("workgroup"), + hostname=hostname(), + hostip=hostip()) + + assert subobj.realm is not None + assert subobj.domain is not None + assert subobj.hostname is not None + + subobj.domainsid = sid.random() + subobj.invocationid = uuid.random() + subobj.policyguid = uuid.random() + subobj.krbtgtpass = misc.random_password(12) + subobj.machinepass = misc.random_password(12) + subobj.adminpass = misc.random_password(12) + subobj.dnspass = misc.random_password(12) + subobj.datestring = time.strftime("%Y%m%d%H") + subobj.root = findnss(pwd.getpwnam, "root")[4] + subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] + subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + subobj.wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] + subobj.backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] + subobj.users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", "usr")[2] + + subobj.dnsdomain = subobj.realm.lower() + subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) + subobj.domaindn = "DC=" + subobj.dnsdomain.replace(".", ",DC=") + subobj.domaindn_ldb = "users.ldb" + subobj.rootdn = subobj.domaindn + subobj.configdn = "CN=Configuration," + subobj.rootdn + subobj.configdn_ldb = "configuration.ldb" + subobj.schemadn = "CN=Schema," + subobj.configdn + subobj.schemadn_ldb = "schema.ldb" + + #Add modules to the list to activate them by default + #beware often order is important + # + # Some Known ordering constraints: + # - rootdse must be first, as it makes redirects from "" -> cn=rootdse + # - objectclass must be before password_hash, because password_hash checks + # that the objectclass is of type person (filled in by objectclass + # module when expanding the objectclass list) + # - partition must be last + # - each partition has its own module list then + subobj.modules_list = ["rootdse", + "paged_results", + "ranged_results", + "server_sort", + "extended_dn", + "asq", + "samldb", + "rdn_name", + "objectclass", + "kludge_acl", + "operational"] + subobj.tdb_modules_list = [ + "subtree_rename", + "subtree_delete", + "linked_attributes"] + subobj.modules_list2 = ["show_deleted", + "partition"] + + subobj.extensibleobject = "# no objectClass: extensibleObject for local ldb" + subobj.aci = "# no aci for local ldb" + return subobj + + +def searchone(ldb, basedn, expression, attribute): + """search for one attribute as a string.""" + res = ldb.search(basedn, SCOPE_SUBTREE, expression, [attribute]) + if len(res) != 1 or res[0][attribute] is None: + return None + return res[0][attribute] + + +def load_schema(setup_dir, subobj, samdb): + """Load schema.""" + src = os.path.join(setup_dir, "schema.ldif") + + schema_data = open(src, 'r').read() + + src = os.path.join(setup_dir, "schema_samba4.ldif") + + schema_data += open(src, 'r').read() + + schema_data = substitute_var(schema_data, subobj.subst_vars()) + + src = os.path.join(setup_dir, "provision_schema_basedn_modify.ldif") + + head_data = open(src, 'r').read() + + head_data = substitute_var(head_data, subobj.subst_vars()) + + samdb.attach_dsdb_schema_from_ldif(head_data, schema_data) + + +def enable_account(ldb, user_dn): + """enable the account.""" + res = ldb.search(user_dn, SCOPE_ONELEVEL, None, ["userAccountControl"]) + assert len(res) == 1 + userAccountControl = res[0].userAccountControl + userAccountControl = userAccountControl - 2 # remove disabled bit + mod = """ +dn: %s +changetype: modify +replace: userAccountControl +userAccountControl: %u +""" % (user_dn, userAccountControl) + ldb.modify(mod) + + +def newuser(sam, username, unixname, password, message, session_info, + credentials): + """add a new user record""" + # connect to the sam + ldb.transaction_start() + + # find the DNs for the domain and the domain users group + res = ldb.search("", SCOPE_BASE, "defaultNamingContext=*", + ["defaultNamingContext"]) + assert(len(res) == 1 and res[0].defaultNamingContext is not None) + domain_dn = res[0].defaultNamingContext + assert(domain_dn is not None) + dom_users = searchone(ldb, domain_dn, "name=Domain Users", "dn") + assert(dom_users is not None) + + user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) + + # + # the new user record. note the reliance on the samdb module to fill + # in a sid, guid etc + # + ldif = """ +dn: %s +sAMAccountName: %s +unixName: %s +sambaPassword: %s +objectClass: user +""" % (user_dn, username, unixname, password) + # add the user to the users group as well + modgroup = """ +dn: %s +changetype: modify +add: member +member: %s +""" % (dom_users, user_dn) + + + # now the real work + message("Adding user %s" % user_dn) + ldb.add(ldif) + + message("Modifying group %s" % dom_users) + ldb.modify(modgroup) + + # modify the userAccountControl to remove the disabled bit + enable_account(ldb, user_dn) + ldb.transaction_commit() + + +def valid_netbios_name(name): + """Check whether a name is valid as a NetBIOS name. """ + # FIXME: There are probably more constraints here. + # crh has a paragraph on this in his book (1.4.1.1) + if len(name) > 13: + return False + return True + + +def join_domain(domain, netbios_name, join_type, creds, message): + 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) + vampire_ctx = object() + machine_creds = credentials_init() + 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) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py new file mode 100644 index 0000000000..49aee3f94d --- /dev/null +++ b/source4/scripting/python/samba/upgrade.py @@ -0,0 +1,561 @@ +#!/usr/bin/python +# +# backend code for upgrading from Samba3 +# Copyright Jelmer Vernooij 2005-2007 +# Released under the GNU GPL v3 or later +# + +"""Support code for upgrading from Samba 3 to Samba 4.""" + +from provision import findnss +import provision +import grp +import pwd +from uuid import uuid4 +from param import default_configuration + +def regkey_to_dn(name): + dn = "hive=NONE" + + for el in name.split("/")[1:]: + dn = "key=%s," % el + dn + + return dn + +# Where prefix is any of: +# - HKLM +# HKU +# HKCR +# HKPD +# HKPT +# + +def upgrade_registry(regdb,prefix,ldb): + """Migrate registry contents.""" + assert regdb is not None: + prefix_up = prefix.upper() + ldif = [] + + for rk in regdb.keys: + pts = rk.name.split("/") + + # Only handle selected hive + if pts[0].upper() != prefix_up: + continue + + keydn = regkey_to_dn(rk.name) + + pts = rk.name.split("/") + + # Convert key name to dn + ldif[rk.name] = """ +dn: %s +name: %s + +""" % (keydn, pts[0]) + + for rv in rk.values: + ldif[rk.name + " (" + rv.name + ")"] = """ +dn: %s,value=%s +value: %s +type: %d +data:: %s""" % (keydn, rv.name, rv.name, rv.type, ldb.encode(rv.data)) + + return ldif + +def upgrade_sam_policy(samba3,dn): + ldif = """ +dn: %s +changetype: modify +replace: minPwdLength +minPwdLength: %d +pwdHistoryLength: %d +minPwdAge: %d +maxPwdAge: %d +lockoutDuration: %d +samba3ResetCountMinutes: %d +samba3UserMustLogonToChangePassword: %d +samba3BadLockoutMinutes: %d +samba3DisconnectTime: %d + +""" % (dn, samba3.policy.min_password_length, + samba3.policy.password_history, samba3.policy.minimum_password_age, + samba3.policy.maximum_password_age, samba3.policy.lockout_duration, + samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password, + samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time) + + return ldif + +def upgrade_sam_account(ldb,acc,domaindn,domainsid): + """Upgrade a SAM account.""" + if acc.nt_username is None or acc.nt_username == "": + acc.nt_username = acc.username + + if acc.fullname is None: + acc.fullname = pwd.getpwnam(acc.fullname)[4] + + acc.fullname = acc.fullname.split(",")[0] + + if acc.fullname is None: + acc.fullname = acc.username + + assert acc.fullname is not None + assert acc.nt_username is not None + + ldif = """dn: cn=%s,%s +objectClass: top +objectClass: user +lastLogon: %d +lastLogoff: %d +unixName: %s +sAMAccountName: %s +cn: %s +description: %s +primaryGroupID: %d +badPwdcount: %d +logonCount: %d +samba3Domain: %s +samba3DirDrive: %s +samba3MungedDial: %s +samba3Homedir: %s +samba3LogonScript: %s +samba3ProfilePath: %s +samba3Workstations: %s +samba3KickOffTime: %d +samba3BadPwdTime: %d +samba3PassLastSetTime: %d +samba3PassCanChangeTime: %d +samba3PassMustChangeTime: %d +objectSid: %s-%d +lmPwdHash:: %s +ntPwdHash:: %s + +""" % (ldb.dn_escape(acc.fullname), domaindn, acc.logon_time, acc.logoff_time, acc.username, acc.nt_username, acc.nt_username, +acc.acct_desc, acc.group_rid, acc.bad_password_count, acc.logon_count, +acc.domain, acc.dir_drive, acc.munged_dial, acc.homedir, acc.logon_script, +acc.profile_path, acc.workstations, acc.kickoff_time, acc.bad_password_time, +acc.pass_last_set_time, acc.pass_can_change_time, acc.pass_must_change_time, domainsid, acc.user_rid, + ldb.encode(acc.lm_pw), ldb.encode(acc.nt_pw)) + + return ldif + +def upgrade_sam_group(group,domaindn): + """Upgrade a SAM group.""" + if group.sid_name_use == 5: # Well-known group + return None + + if group.nt_name in ("Domain Guests", "Domain Users", "Domain Admins"): + return None + + if group.gid == -1: + gr = grp.getgrnam(grp.nt_name) + else: + gr = grp.getgrgid(grp.gid) + + if gr is None: + group.unixname = "UNKNOWN" + else: + group.unixname = gr.gr_name + + assert group.unixname is not None + + ldif = """dn: cn=%s,%s +objectClass: top +objectClass: group +description: %s +cn: %s +objectSid: %s +unixName: %s +samba3SidNameUse: %d +""" % (group.nt_name, domaindn, +group.comment, group.nt_name, group.sid, group.unixname, group.sid_name_use) + + return ldif + +def upgrade_winbind(samba3,domaindn): + ldif = """ + +dn: dc=none +userHwm: %d +groupHwm: %d + +""" % (samba3.idmap.user_hwm, samba3.idmap.group_hwm) + + for m in samba3.idmap.mappings: + ldif += """ +dn: SID=%s,%s +SID: %s +type: %d +unixID: %d""" % (m.sid, domaindn, m.sid, m.type, m.unix_id) + + return ldif + +def upgrade_wins(samba3): + ldif = "" + version_id = 0 + + for e in samba3.winsentries: + now = sys.nttime() + ttl = sys.unix2nttime(e.ttl) + + version_id+=1 + + numIPs = len(e.ips) + + if e.type == 0x1C: + rType = 0x2 + elif e.type & 0x80: + if numIPs > 1: + rType = 0x2 + else: + rType = 0x1 + else: + if numIPs > 1: + rType = 0x3 + else: + rType = 0x0 + + if ttl > now: + rState = 0x0 # active + else: + rState = 0x1 # released + + nType = ((e.nb_flags & 0x60)>>5) + + ldif += """ +dn: name=%s,type=0x%02X +type: 0x%02X +name: %s +objectClass: winsRecord +recordType: %u +recordState: %u +nodeType: %u +isStatic: 0 +expireTime: %s +versionID: %llu +""" % (e.name, e.type, e.type, e.name, + rType, rState, nType, + ldaptime(ttl), version_id) + + for ip in e.ips: + ldif += "address: %s\n" % ip + + ldif += """ +dn: CN=VERSION +objectClass: winsMaxVersion +maxVersion: %llu +""" % version_id + + return ldif + +def upgrade_provision(lp, samba3): + subobj = Object() + + domainname = samba3.configuration.get("workgroup") + + if domainname is None: + domainname = samba3.secrets.domains[0].name + print "No domain specified in smb.conf file, assuming '%s'\n" % domainname + + domsec = samba3.find_domainsecrets(domainname) + hostsec = samba3.find_domainsecrets(hostname()) + realm = samba3.configuration.get("realm") + + if realm is None: + realm = domainname + print "No realm specified in smb.conf file, assuming '%s'\n" % realm + random_init(local) + + subobj.realm = realm + subobj.domain = domainname + subobj.hostname = hostname() + + assert subobj.realm is not None + assert subobj.domain is not None + assert subobj.hostname is not None + + subobj.HOSTIP = hostip() + if domsec is not None: + subobj.DOMAINGUID = domsec.guid + subobj.DOMAINSID = domsec.sid + else: + print "Can't find domain secrets for '%s'; using random SID and GUID\n" % domainname + subobj.DOMAINGUID = uuid4() + subobj.DOMAINSID = randsid() + + if hostsec: + subobj.HOSTGUID = hostsec.guid + else: + subobj.HOSTGUID = uuid4() + subobj.invocationid = uuid4() + subobj.krbtgtpass = randpass(12) + subobj.machinepass = randpass(12) + subobj.adminpass = randpass(12) + subobj.datestring = datestring() + subobj.root = findnss(pwd.getpwnam, "root")[4] + subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] + subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + subobj.wheel = findnss(grp.getgrnam, "wheel", "root")[2] + subobj.users = findnss(grp.getgrnam, "users", "guest", "other")[2] + subobj.dnsdomain = subobj.realm.lower() + subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) + subobj.basedn = "DC=" + ",DC=".join(subobj.realm.split(".")) + rdn_list = subobj.dnsdomain.split(".") + subobj.domaindn = "DC=" + ",DC=".join(rdn_list) + subobj.domaindn_ldb = "users.ldb" + subobj.rootdn = subobj.domaindn + + modules_list = ["rootdse", + "kludge_acl", + "paged_results", + "server_sort", + "extended_dn", + "asq", + "samldb", + "password_hash", + "operational", + "objectclass", + "rdn_name", + "show_deleted", + "partition"] + subobj.modules_list = ",".join(modules_list) + + return subobj + +smbconf_keep = [ + "dos charset", + "unix charset", + "display charset", + "comment", + "path", + "directory", + "workgroup", + "realm", + "netbios name", + "netbios aliases", + "netbios scope", + "server string", + "interfaces", + "bind interfaces only", + "security", + "auth methods", + "encrypt passwords", + "null passwords", + "obey pam restrictions", + "password server", + "smb passwd file", + "private dir", + "passwd chat", + "password level", + "lanman auth", + "ntlm auth", + "client NTLMv2 auth", + "client lanman auth", + "client plaintext auth", + "read only", + "hosts allow", + "hosts deny", + "log level", + "debuglevel", + "log file", + "smb ports", + "large readwrite", + "max protocol", + "min protocol", + "unicode", + "read raw", + "write raw", + "disable netbios", + "nt status support", + "announce version", + "announce as", + "max mux", + "max xmit", + "name resolve order", + "max wins ttl", + "min wins ttl", + "time server", + "unix extensions", + "use spnego", + "server signing", + "client signing", + "max connections", + "paranoid server security", + "socket options", + "strict sync", + "max print jobs", + "printable", + "print ok", + "printer name", + "printer", + "map system", + "map hidden", + "map archive", + "preferred master", + "prefered master", + "local master", + "browseable", + "browsable", + "wins server", + "wins support", + "csc policy", + "strict locking", + "preload", + "auto services", + "lock dir", + "lock directory", + "pid directory", + "socket address", + "copy", + "include", + "available", + "volume", + "fstype", + "panic action", + "msdfs root", + "host msdfs", + "winbind separator"] + +# +# Remove configuration variables not present in Samba4 +# oldconf: Old configuration structure +# mark: Whether removed configuration variables should be +# kept in the new configuration as "samba3:" +def upgrade_smbconf(oldconf,mark): + data = oldconf.data() + newconf = param_init() + + for (s in data) { + for (p in data[s]) { + keep = False + for (k in smbconf_keep) { + if smbconf_keep[k] == p: + keep = True + break + } + + if keep: + newconf.set(s, p, oldconf.get(s, p)) + elif mark: + newconf.set(s, "samba3:"+p, oldconf.get(s,p)) + } + } + + if oldconf.get("domain logons") == "True": + newconf.set("server role", "domain controller") + else: + if oldconf.get("security") == "user": + newconf.set("server role", "standalone") + else: + newconf.set("server role", "member server") + + return newconf + +def upgrade(subobj, samba3, message, paths, session_info, credentials): + ret = 0 + lp = loadparm_init() + samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) + + message("Writing configuration") + newconf = upgrade_smbconf(samba3.configuration,True) + newconf.save(paths.smbconf) + + message("Importing account policies") + ldif = upgrade_sam_policy(samba3,subobj.BASEDN) + samdb.modify(ldif) + regdb = Ldb(paths.hklm) + + regdb.modify(" +dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE +replace: type +type: 4 +replace: data +data: %d +" % samba3.policy.refuse_machine_password_change) + + message("Importing users") + for account in samba3.samaccounts: + msg = "... " + account.username + ldif = upgrade_sam_account(samdb, accounts,subobj.BASEDN,subobj.DOMAINSID) + try: + samdb.add(ldif) + except LdbError, e: + # FIXME: Ignore 'Record exists' errors + msg += "... error: " + str(e) + ret += 1; + message(msg) + + message("Importing groups") + for mapping in samba3.groupmappings: + msg = "... " + mapping.nt_name + ldif = upgrade_sam_group(mapping, subobj.BASEDN) + if ldif is not None: + try: + samdb.add(ldif) + except LdbError, e: + # FIXME: Ignore 'Record exists' errors + msg += "... error: " + str(e) + ret += 1 + message(msg) + + message("Importing registry data") + for hive in ["hkcr","hkcu","hklm","hkpd","hku","hkpt"]: + message("... " + hive) + regdb = Ldb(paths[hive]) + ldif = upgrade_registry(samba3.registry, hive, regdb) + for (var j in ldif) { + var msg = "... ... " + j + try: + regdb.add(ldif[j]) + except LdbError, e: + # FIXME: Ignore 'Record exists' errors + msg += "... error: " + str(e) + ret += 1 + message(msg) + + message("Importing WINS data") + winsdb = Ldb(paths.winsdb) + ldb_erase(winsdb) + + ldif = upgrade_wins(samba3) + winsdb.add(ldif) + + # figure out ldapurl, if applicable + ldapurl = None + pdb = samba3.configuration.get_list("passdb backend") + if pdb is not None: + for backend in pdb: + if len(backend) >= 7 and backend[0:7] == "ldapsam": + ldapurl = backend[7:] + + # URL was not specified in passdb backend but ldap /is/ used + if ldapurl == "": + ldapurl = "ldap://%s" % samba3.configuration.get("ldap server") + + # Enable samba3sam module if original passdb backend was ldap + if ldapurl is not None: + message("Enabling Samba3 LDAP mappings for SAM database") + + samdb.modify(""" +dn: @MODULES +changetype: modify +replace: @LIST +@LIST: samldb,operational,objectguid,rdn_name,samba3sam +""") + + samdb.add(""" +dn: @MAP=samba3sam +@MAP_URL: %s""", ldapurl)) + + return ret + +def upgrade_verify(subobj, samba3, paths, message): + message("Verifying account policies") + + samldb = Ldb(paths.samdb) + + for account in samba3.samaccounts: + msg = samldb.search("(&(sAMAccountName=" + account.nt_username + ")(objectclass=user))") + assert(len(msg) >= 1) + + # FIXME -- cgit From b414ac505282f5a2a59c7580a19dfbd86489676e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 10 Dec 2007 10:29:20 +0100 Subject: r26369: Start on tests for the upgrade python code. (This used to be commit c4458d11c710d4f0f892b26c7cb0701a43273587) --- source4/scripting/python/samba/tests/upgrade.py | 28 +++++++++++++++++++++++++ source4/scripting/python/samba/upgrade.py | 2 ++ 2 files changed, 30 insertions(+) create mode 100644 source4/scripting/python/samba/tests/upgrade.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/upgrade.py b/source4/scripting/python/samba/tests/upgrade.py new file mode 100644 index 0000000000..f46d869656 --- /dev/null +++ b/source4/scripting/python/samba/tests/upgrade.py @@ -0,0 +1,28 @@ +#!/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 . +# + +from samba.upgrade import regkey_to_dn +from unittest import TestCase + +class RegkeyDnTests(TestCase): + def test_empty(self): + self.assertEquals("hive=NONE", regkey_to_dn("")) + + def test_nested(self): + self.assertEquals("key=foo,key=bar,hive=NONE", regkey_to_dn("foo/bar")) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 49aee3f94d..1908e3ea55 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -15,6 +15,7 @@ from uuid import uuid4 from param import default_configuration def regkey_to_dn(name): + """Convert a registry key to a DN.""" dn = "hive=NONE" for el in name.split("/")[1:]: @@ -191,6 +192,7 @@ unixID: %d""" % (m.sid, domaindn, m.sid, m.type, m.unix_id) return ldif def upgrade_wins(samba3): + """Upgrade the WINS database.""" ldif = "" version_id = 0 -- cgit From eba25f5d1897fbe61e8d7c623fcacb647629bf07 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 10 Dec 2007 10:29:45 +0100 Subject: r26375: Move provision-independent utility function to main samba python module. (This used to be commit 9d0ff47be069422de7ef2794357c6f3e9c540e67) --- source4/scripting/python/samba/__init__.py | 9 +++++++++ source4/scripting/python/samba/provision.py | 14 ++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 46d8ff7d37..00b82e1800 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -55,3 +55,12 @@ def substitute_var(text, values): return text + +def valid_netbios_name(name): + """Check whether a name is valid as a NetBIOS name. """ + # FIXME: There are probably more constraints here. + # crh has a paragraph on this in his book (1.4.1.1) + if len(name) > 13: + return False + return True + diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 3d391863da..692e49b095 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -14,7 +14,7 @@ import uuid, sid, misc from socket import gethostname, gethostbyname import param import registry -from samba import Ldb, substitute_var +from samba import Ldb, substitute_var, valid_netbios_name from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring @@ -191,14 +191,17 @@ unixName: %s """ % (res[0].dn, unixname) ldb.modify(ldb.parse_ldif(mod).next()[1]) + def hostip(): """return first host IP.""" return gethostbyname(hostname()) + def hostname(): """return first part of hostname.""" return gethostname().split(".")[0] + def ldb_delete(ldb): """Delete a LDB file. @@ -805,15 +808,6 @@ member: %s ldb.transaction_commit() -def valid_netbios_name(name): - """Check whether a name is valid as a NetBIOS name. """ - # FIXME: There are probably more constraints here. - # crh has a paragraph on this in his book (1.4.1.1) - if len(name) > 13: - return False - return True - - def join_domain(domain, netbios_name, join_type, creds, message): ctx = NetContext(creds) joindom = object() -- cgit From eb2c71912baceb1a6884ce143ae91f1e3d2a69fb Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 16 Dec 2007 14:50:18 +0100 Subject: r26471: Sync with js version. (This used to be commit c0eea26e8e8eb326112e1833d137751fb7e900d2) --- source4/scripting/python/samba/provision.py | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 692e49b095..df40c2fb7a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -695,6 +695,7 @@ def provision_guess(lp): subobj.modules_list = ["rootdse", "paged_results", "ranged_results", + "anr", "server_sort", "extended_dn", "asq", -- cgit From 1afe0549163bbc639ae1a030239c9ebcd1b922bf Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 16 Dec 2007 15:33:58 +0100 Subject: r26474: Move credentials-specific kerberos file to credentials subsystem. Fixes missing symbols in some of the python bindings. (This used to be commit e26d0fff6d40899113196ac35a86a9baa10cc9c2) --- source4/scripting/python/samba/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 00b82e1800..2c51440b0c 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -21,6 +21,15 @@ import os from misc import ldb_set_credentials +def _in_source_tree(): + print os.path.exists("%s/../../../samba4-skip" % os.path.dirname(__file__)) + +# When running, in-tree, make sure bin/python is in the PYTHONPATH +if _in_source_tree(): + import sys + dir = os.path.dirname(__file__) + sys.path.append("%s/../../../bin/python" % os.path.dirname(__file__)) + def Ldb(url, session_info=None, credentials=None, modules_dir=None): """Open a Samba Ldb file. -- cgit From 0a01f50f9802ecfae430d2218af3b96a3682218d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 16 Dec 2007 15:50:02 +0100 Subject: r26475: Add ldb.set_credentials function. (This used to be commit dbebb4ef477d2c8de7b8d1e5cde9b9dada47044f) --- source4/scripting/python/samba/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 2c51440b0c..29d322e2fc 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -19,10 +19,9 @@ # import os -from misc import ldb_set_credentials def _in_source_tree(): - print os.path.exists("%s/../../../samba4-skip" % os.path.dirname(__file__)) + return os.path.exists("%s/../../../samba4-skip" % os.path.dirname(__file__)) # When running, in-tree, make sure bin/python is in the PYTHONPATH if _in_source_tree(): @@ -30,6 +29,10 @@ if _in_source_tree(): dir = os.path.dirname(__file__) sys.path.append("%s/../../../bin/python" % os.path.dirname(__file__)) +import misc +import ldb +ldb.ldb.set_credentials = misc.ldb_set_credentials + def Ldb(url, session_info=None, credentials=None, modules_dir=None): """Open a Samba Ldb file. -- cgit From 440fd879613b94cc75eb0737af91602d96c89bf9 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 16 Dec 2007 17:17:37 +0100 Subject: r26477: Allow setting loadparm context for a ldb context in python, plus some other minor improvements. (This used to be commit d88527a9d6435203faa8273347d5aa41937e5395) --- source4/scripting/python/samba/__init__.py | 31 +++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 29d322e2fc..08a262eec8 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -21,21 +21,33 @@ import os def _in_source_tree(): + """Check whether the script is being run from the source dir. """ return os.path.exists("%s/../../../samba4-skip" % os.path.dirname(__file__)) + # When running, in-tree, make sure bin/python is in the PYTHONPATH if _in_source_tree(): import sys - dir = os.path.dirname(__file__) - sys.path.append("%s/../../../bin/python" % os.path.dirname(__file__)) + srcdir = "%s/../../.." % os.path.dirname(__file__) + sys.path.append("%s/bin/python" % srcdir) + default_ldb_modules_dir = "%s/bin/modules/ldb" % srcdir + import misc import ldb ldb.ldb.set_credentials = misc.ldb_set_credentials +#FIXME: ldb.ldb.set_session_info = misc.ldb_set_session_info +ldb.ldb.set_loadparm = misc.ldb_set_loadparm -def Ldb(url, session_info=None, credentials=None, modules_dir=None): +def Ldb(url, session_info=None, credentials=None, modules_dir=None, lp=None): """Open a Samba Ldb file. + :param url: LDB Url to open + :param session_info: Optional session information + :param credentials: Optional credentials, defaults to anonymous. + :param modules_dir: Modules directory, automatically set if not specified. + :param lp: Loadparm object, optional. + This is different from a regular Ldb file in that the Samba-specific modules-dir is used by default and that credentials and session_info can be passed through (required by some modules). @@ -43,12 +55,17 @@ def Ldb(url, session_info=None, credentials=None, modules_dir=None): import ldb ret = ldb.Ldb() if modules_dir is None: - modules_dir = os.path.join(os.getcwd(), "bin", "modules", "ldb") - ret.set_modules_dir(modules_dir) + modules_dir = default_ldb_modules_dir + if modules_dir is not None: + ret.set_modules_dir(modules_dir) def samba_debug(level,text): print "%d %s" % (level, text) - ldb_set_opaque("credentials", credentials) - ret.set_opaque("sessionInfo", session_info) + if credentials is not None: + ldb.set_credentials(credentials) + if session_info is not None: + ldb.set_session_info(session_info) + if lp is not None: + ldb.set_loadparm(lp) #ret.set_debug(samba_debug) ret.connect(url) return ret -- cgit From 07beaf09c95a06636cb029fcc2dbbeb7293879ba Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 03:25:28 +0100 Subject: r26480: Add utility class for testing LDB code. (This used to be commit d7f0b12c9e43b93705f6b9fa6b5ab74fe68e80a0) --- source4/scripting/python/samba/tests/__init__.py | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 source4/scripting/python/samba/tests/__init__.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py new file mode 100644 index 0000000000..d374f8bafa --- /dev/null +++ b/source4/scripting/python/samba/tests/__init__.py @@ -0,0 +1,37 @@ +#!/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 . +# + +import os +import ldb +import samba +import unittest + +class LdbTestCase(unittest.TestCase): + def setUp(self): + self.filename = os.tempnam() + self.ldb = samba.Ldb(self.filename) + + def load_modules(self, modules=[]): + m = ldb.Message() + m.dn = ldb.Dn(self.ldb, "@MODULES") + m["@LIST"] = ",".join(modules) + self.ldb.add(m) + self.ldb = samba.Ldb(self.filename) + + -- cgit From be999912671de052af909bb88f13c956f12b30e1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 04:56:54 +0100 Subject: r26484: Don't rely on removed header. (This used to be commit 6ca2b350858c0747449671234d54584635512705) --- source4/scripting/python/samba/provision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index df40c2fb7a..ce496a8bc1 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -10,7 +10,7 @@ import os import pwd import grp import time -import uuid, sid, misc +import uuid, misc from socket import gethostname, gethostbyname import param import registry @@ -61,8 +61,8 @@ class ProvisionSettings(object): "SCHEMADN_MOD": "schema_fsmo", "SCHEMADN_MOD2": ",objectguid", "CONFIGDN": self.configdn, - "TDB_MODULES_LIST": ","+",".join(self.tdb_modules_list) - "MODULES_LIST2": ",".join(self.modules_list2) + "TDB_MODULES_LIST": ","+",".join(self.tdb_modules_list), + "MODULES_LIST2": ",".join(self.modules_list2), "CONFIGDN_LDB": self.configdn_ldb, "DOMAINDN": self.domaindn, "DOMAINDN_LDB": self.domaindn_ldb, -- cgit From b0360e3a8617c59661d0b0fd805666e6cefcd811 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 08:20:20 +0100 Subject: r26496: Move some provision functions to a new SamDB class, support setting session_info on a ldb context from python. (This used to be commit 75cfb0d609687538048a7d72a499a5205af46a34) --- source4/scripting/python/samba/__init__.py | 104 +++++++++---- source4/scripting/python/samba/provision.py | 230 +++++++--------------------- source4/scripting/python/samba/samdb.py | 117 ++++++++++++++ 3 files changed, 246 insertions(+), 205 deletions(-) create mode 100644 source4/scripting/python/samba/samdb.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 08a262eec8..56adce4473 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -35,40 +35,78 @@ if _in_source_tree(): import misc import ldb -ldb.ldb.set_credentials = misc.ldb_set_credentials -#FIXME: ldb.ldb.set_session_info = misc.ldb_set_session_info -ldb.ldb.set_loadparm = misc.ldb_set_loadparm - -def Ldb(url, session_info=None, credentials=None, modules_dir=None, lp=None): - """Open a Samba Ldb file. - - :param url: LDB Url to open - :param session_info: Optional session information - :param credentials: Optional credentials, defaults to anonymous. - :param modules_dir: Modules directory, automatically set if not specified. - :param lp: Loadparm object, optional. - - This is different from a regular Ldb file in that the Samba-specific - modules-dir is used by default and that credentials and session_info - can be passed through (required by some modules). +ldb.Ldb.set_credentials = misc.ldb_set_credentials +ldb.Ldb.set_session_info = misc.ldb_set_session_info +ldb.Ldb.set_loadparm = misc.ldb_set_loadparm + +class Ldb(ldb.Ldb): + """Simple Samba-specific LDB subclass that takes care + of setting up the modules dir, credentials pointers, etc. + + Please note that this is intended to be for all Samba LDB files, + not necessarily the Sam database. For Sam-specific helper + functions see samdb.py. """ - import ldb - ret = ldb.Ldb() - if modules_dir is None: - modules_dir = default_ldb_modules_dir - if modules_dir is not None: - ret.set_modules_dir(modules_dir) - def samba_debug(level,text): - print "%d %s" % (level, text) - if credentials is not None: - ldb.set_credentials(credentials) - if session_info is not None: - ldb.set_session_info(session_info) - if lp is not None: - ldb.set_loadparm(lp) - #ret.set_debug(samba_debug) - ret.connect(url) - return ret + def __init__(url, session_info=None, credentials=None, modules_dir=None, + lp=None): + """Open a Samba Ldb file. + + :param url: LDB Url to open + :param session_info: Optional session information + :param credentials: Optional credentials, defaults to anonymous. + :param modules_dir: Modules directory, automatically set if not specified. + :param lp: Loadparm object, optional. + + This is different from a regular Ldb file in that the Samba-specific + modules-dir is used by default and that credentials and session_info + can be passed through (required by some modules). + """ + super(self, Ldb).__init__() + import ldb + ret = ldb.Ldb() + if modules_dir is None: + modules_dir = default_ldb_modules_dir + if modules_dir is not None: + ret.set_modules_dir(modules_dir) + def samba_debug(level,text): + print "%d %s" % (level, text) + if credentials is not None: + ldb.set_credentials(credentials) + if session_info is not None: + ldb.set_session_info(session_info) + if lp is not None: + ldb.set_loadparm(lp) + #ret.set_debug(samba_debug) + ret.connect(url) + return ret + + def searchone(self, basedn, expression, attribute): + """Search for one attribute as a string.""" + res = self.search(basedn, SCOPE_SUBTREE, expression, [attribute]) + if len(res) != 1 or res[0][attribute] is None: + return None + return res[0][attribute] + + def erase(self): + """Erase an ldb, removing all records.""" + # delete the specials + for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", + "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: + try: + self.delete(Dn(self, attr)) + except LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + pass + + basedn = Dn(self, "") + # and the rest + for msg in self.search(basedn, SCOPE_SUBTREE, + "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", + ["dn"]): + self.delete(msg.dn) + + res = self.search(basedn, SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) + assert len(res) == 0 def substitute_var(text, values): diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ce496a8bc1..63e50897fe 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -15,6 +15,7 @@ from socket import gethostname, gethostbyname import param import registry from samba import Ldb, substitute_var, valid_netbios_name +from samba.samdb import SamDB from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring @@ -164,32 +165,6 @@ def findnss(nssfn, *names): pass raise Exception("Unable to find user/group for %s" % arguments[1]) -def add_foreign(ldb, subobj, sid, desc): - """Add a foreign security principle.""" - add = """ -dn: CN=%s,CN=ForeignSecurityPrincipals,%s -objectClass: top -objectClass: foreignSecurityPrincipal -description: %s -""" % (sid, subobj.domaindn, desc) - # deliberately ignore errors from this, as the records may - # already exist - for msg in ldb.parse_ldif(add): - ldb.add(msg[1]) - -def setup_name_mapping(subobj, ldb, sid, unixname): - """Setup a mapping between a sam name and a unix name.""" - res = ldb.search(Dn(ldb, subobj.domaindn), SCOPE_SUBTREE, - "objectSid=%s" % sid, ["dn"]) - assert len(res) == 1, "Failed to find record for objectSid %s" % sid - - mod = """ -dn: %s -changetype: modify -replace: unixName -unixName: %s -""" % (res[0].dn, unixname) - ldb.modify(ldb.parse_ldif(mod).next()[1]) def hostip(): @@ -214,57 +189,6 @@ def ldb_delete(ldb): ldb.connect(ldb.filename) -def ldb_erase(ldb): - """Erase an ldb, removing all records.""" - # delete the specials - for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", - "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: - try: - ldb.delete(Dn(ldb, attr)) - except LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): - # Ignore missing dn errors - pass - - basedn = Dn(ldb, "") - # and the rest - for msg in ldb.search(basedn, SCOPE_SUBTREE, - "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", - ["dn"]): - ldb.delete(msg.dn) - - res = ldb.search(basedn, SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) - assert len(res) == 0 - - -def ldb_erase_partitions(subobj, message, ldb, ldapbackend): - """Erase an ldb, removing all records.""" - assert ldb is not None - res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)", - ["namingContexts"]) - assert len(res) == 1 - if not "namingContexts" in res[0]: - return - for basedn in res[0]["namingContexts"]: - anything = "(|(objectclass=*)(dn=*))" - previous_remaining = 1 - current_remaining = 0 - - if ldapbackend and (basedn == subobj.domaindn): - # Only delete objects that were created by provision - anything = "(objectcategory=*)" - - k = 0 - while ++k < 10 and (previous_remaining != current_remaining): - # and the rest - res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"]) - previous_remaining = current_remaining - current_remaining = len(res2) - for msg in res2: - try: - ldb.delete(msg.dn) - except LdbError, (_, text): - message("Unable to delete %s: %s" % (msg.dn, text)) - def open_ldb(session_info, credentials, dbname): assert session_info is not None @@ -374,30 +298,30 @@ def setup_name_mappings(subobj, ldb): sid = list(res[0]["objectSid"])[0] # add some foreign sids if they are not present already - add_foreign(ldb, subobj, "S-1-5-7", "Anonymous") - add_foreign(ldb, subobj, "S-1-1-0", "World") - add_foreign(ldb, subobj, "S-1-5-2", "Network") - add_foreign(ldb, subobj, "S-1-5-18", "System") - add_foreign(ldb, subobj, "S-1-5-11", "Authenticated Users") + ldb.add_foreign(subobj.domaindn, "S-1-5-7", "Anonymous") + ldb.add_foreign(subobj.domaindn, "S-1-1-0", "World") + ldb.add_foreign(subobj.domaindn, "S-1-5-2", "Network") + ldb.add_foreign(subobj.domaindn, "S-1-5-18", "System") + ldb.add_foreign(subobj.domaindn, "S-1-5-11", "Authenticated Users") # some well known sids - setup_name_mapping(subobj, ldb, "S-1-5-7", subobj.nobody) - setup_name_mapping(subobj, ldb, "S-1-1-0", subobj.nogroup) - setup_name_mapping(subobj, ldb, "S-1-5-2", subobj.nogroup) - setup_name_mapping(subobj, ldb, "S-1-5-18", subobj.root) - setup_name_mapping(subobj, ldb, "S-1-5-11", subobj.users) - setup_name_mapping(subobj, ldb, "S-1-5-32-544", subobj.wheel) - setup_name_mapping(subobj, ldb, "S-1-5-32-545", subobj.users) - setup_name_mapping(subobj, ldb, "S-1-5-32-546", subobj.nogroup) - setup_name_mapping(subobj, ldb, "S-1-5-32-551", subobj.backup) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-7", subobj.nobody) + ldb.setup_name_mapping(subobj.domaindn, "S-1-1-0", subobj.nogroup) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-2", subobj.nogroup) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-18", subobj.root) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-11", subobj.users) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-544", subobj.wheel) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-545", subobj.users) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-546", subobj.nogroup) + ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-551", subobj.backup) # and some well known domain rids - setup_name_mapping(subobj, ldb, sid + "-500", subobj.root) - setup_name_mapping(subobj, ldb, sid + "-518", subobj.wheel) - setup_name_mapping(subobj, ldb, sid + "-519", subobj.wheel) - setup_name_mapping(subobj, ldb, sid + "-512", subobj.wheel) - setup_name_mapping(subobj, ldb, sid + "-513", subobj.users) - setup_name_mapping(subobj, ldb, sid + "-520", subobj.wheel) + ldb.setup_name_mapping(subobj.domaindn, sid + "-500", subobj.root) + ldb.setup_name_mapping(subobj.domaindn, sid + "-518", subobj.wheel) + ldb.setup_name_mapping(subobj.domaindn, sid + "-519", subobj.wheel) + ldb.setup_name_mapping(subobj.domaindn, sid + "-512", subobj.wheel) + ldb.setup_name_mapping(subobj.domaindn, sid + "-513", subobj.users) + ldb.setup_name_mapping(subobj.domaindn, sid + "-520", subobj.wheel) def provision_become_dc(setup_dir, subobj, message, paths, session_info, @@ -414,7 +338,8 @@ def provision_become_dc(setup_dir, subobj, message, paths, session_info, setup_ldb(setup_dir, "provision_partitions.ldif", session_info, credentials, subobj, paths.samdb) - samdb = open_ldb(session_info, credentials, paths.samdb) + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials) ldb.transaction_start() try: message("Setting up %s attributes" % paths.samdb) @@ -424,7 +349,7 @@ def provision_become_dc(setup_dir, subobj, message, paths, session_info, setup_add_ldif(setup_dir, "provision_rootdse_add.ldif", subobj, samdb) message("Erasing data from partitions") - ldb_erase_partitions(subobj, message, samdb, undefined) + ldb_erase_partitions(subobj, message, samdb, None) message("Setting up %s indexes" % paths.samdb) setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) @@ -603,7 +528,7 @@ def provision_dns(setup_dir, subobj, message, paths, session_info, credentials): """Write out a DNS zone file, from the info in the current database.""" message("Setting up DNS zone: %s" % subobj.dnsdomain) # connect to the sam - ldb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) + ldb = SamDB(paths.samdb, session_info=session_info, credentials=credentials) # These values may have changed, due to an incoming SamSync, # or may not have been specified, so fetch them from the database @@ -614,7 +539,7 @@ def provision_dns(setup_dir, subobj, message, paths, session_info, credentials): assert(res[0]["objectGUID"] is not None) subobj.domainguid = res[0]["objectGUID"] - subobj.host_guid = searchone(ldb, subobj.domaindn, + subobj.host_guid = ldb.searchone(subobj.domaindn, "(&(objectClass=computer)(cn=%s))" % subobj.netbiosname, "objectGUID") assert subobj.host_guid is not None @@ -716,13 +641,6 @@ def provision_guess(lp): return subobj -def searchone(ldb, basedn, expression, attribute): - """search for one attribute as a string.""" - res = ldb.search(basedn, SCOPE_SUBTREE, expression, [attribute]) - if len(res) != 1 or res[0][attribute] is None: - return None - return res[0][attribute] - def load_schema(setup_dir, subobj, samdb): """Load schema.""" @@ -745,70 +663,6 @@ def load_schema(setup_dir, subobj, samdb): samdb.attach_dsdb_schema_from_ldif(head_data, schema_data) -def enable_account(ldb, user_dn): - """enable the account.""" - res = ldb.search(user_dn, SCOPE_ONELEVEL, None, ["userAccountControl"]) - assert len(res) == 1 - userAccountControl = res[0].userAccountControl - userAccountControl = userAccountControl - 2 # remove disabled bit - mod = """ -dn: %s -changetype: modify -replace: userAccountControl -userAccountControl: %u -""" % (user_dn, userAccountControl) - ldb.modify(mod) - - -def newuser(sam, username, unixname, password, message, session_info, - credentials): - """add a new user record""" - # connect to the sam - ldb.transaction_start() - - # find the DNs for the domain and the domain users group - res = ldb.search("", SCOPE_BASE, "defaultNamingContext=*", - ["defaultNamingContext"]) - assert(len(res) == 1 and res[0].defaultNamingContext is not None) - domain_dn = res[0].defaultNamingContext - assert(domain_dn is not None) - dom_users = searchone(ldb, domain_dn, "name=Domain Users", "dn") - assert(dom_users is not None) - - user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) - - # - # the new user record. note the reliance on the samdb module to fill - # in a sid, guid etc - # - ldif = """ -dn: %s -sAMAccountName: %s -unixName: %s -sambaPassword: %s -objectClass: user -""" % (user_dn, username, unixname, password) - # add the user to the users group as well - modgroup = """ -dn: %s -changetype: modify -add: member -member: %s -""" % (dom_users, user_dn) - - - # now the real work - message("Adding user %s" % user_dn) - ldb.add(ldif) - - message("Modifying group %s" % dom_users) - ldb.modify(modgroup) - - # modify the userAccountControl to remove the disabled bit - enable_account(ldb, user_dn) - ldb.transaction_commit() - - def join_domain(domain, netbios_name, join_type, creds, message): ctx = NetContext(creds) joindom = object() @@ -835,3 +689,35 @@ def vampire(domain, session_info, credentials, message): 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) + + +def ldb_erase_partitions(subobj, message, ldb, ldapbackend): + """Erase an ldb, removing all records.""" + assert ldb is not None + res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)", + ["namingContexts"]) + assert len(res) == 1 + if not "namingContexts" in res[0]: + return + for basedn in res[0]["namingContexts"]: + anything = "(|(objectclass=*)(dn=*))" + previous_remaining = 1 + current_remaining = 0 + + if ldapbackend and (basedn == subobj.domaindn): + # Only delete objects that were created by provision + anything = "(objectcategory=*)" + + k = 0 + while ++k < 10 and (previous_remaining != current_remaining): + # and the rest + res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"]) + previous_remaining = current_remaining + current_remaining = len(res2) + for msg in res2: + try: + ldb.delete(msg.dn) + except LdbError, (_, text): + message("Unable to delete %s: %s" % (msg.dn, text)) + + diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py new file mode 100644 index 0000000000..50164bf590 --- /dev/null +++ b/source4/scripting/python/samba/samdb.py @@ -0,0 +1,117 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2007 +# +# Based on the original in EJS: +# Copyright (C) Andrew Tridgell 2005 +# +# 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 . +# + +import samba + +class SamDB(samba.Ldb): + def add_foreign(self, domaindn, sid, desc): + """Add a foreign security principle.""" + add = """ +dn: CN=%s,CN=ForeignSecurityPrincipals,%s +objectClass: top +objectClass: foreignSecurityPrincipal +description: %s + """ % (sid, domaindn, desc) + # deliberately ignore errors from this, as the records may + # already exist + for msg in self.parse_ldif(add): + self.add(msg[1]) + + def setup_name_mapping(self, domaindn, sid, unixname): + """Setup a mapping between a sam name and a unix name.""" + res = self.search(Dn(ldb, domaindn), SCOPE_SUBTREE, + "objectSid=%s" % sid, ["dn"]) + assert len(res) == 1, "Failed to find record for objectSid %s" % sid + + mod = """ +dn: %s +changetype: modify +replace: unixName +unixName: %s +""" % (res[0].dn, unixname) + self.modify(self.parse_ldif(mod).next()[1]) + + def enable_account(self, user_dn): + """enable the account. + + :param user_dn: Dn of the account to enable. + """ + res = self.search(user_dn, SCOPE_ONELEVEL, None, ["userAccountControl"]) + assert len(res) == 1 + userAccountControl = res[0].userAccountControl + userAccountControl = userAccountControl - 2 # remove disabled bit + mod = """ +dn: %s +changetype: modify +replace: userAccountControl +userAccountControl: %u +""" % (user_dn, userAccountControl) + self.modify(mod) + + def newuser(self, username, unixname, password, message): + """add a new user record""" + # connect to the sam + self.transaction_start() + + # find the DNs for the domain and the domain users group + res = self.search("", SCOPE_BASE, "defaultNamingContext=*", + ["defaultNamingContext"]) + assert(len(res) == 1 and res[0].defaultNamingContext is not None) + domain_dn = res[0].defaultNamingContext + assert(domain_dn is not None) + dom_users = searchone(self, domain_dn, "name=Domain Users", "dn") + assert(dom_users is not None) + + user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) + + # + # the new user record. note the reliance on the samdb module to fill + # in a sid, guid etc + # + ldif = """ +dn: %s +sAMAccountName: %s +unixName: %s +sambaPassword: %s +objectClass: user + """ % (user_dn, username, unixname, password) + # add the user to the users group as well + modgroup = """ +dn: %s +changetype: modify +add: member +member: %s +""" % (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) + + # modify the userAccountControl to remove the disabled bit + enable_account(self, user_dn) + self.transaction_commit() + + -- cgit From 09915ce8b7edcf23335d570d70f79797afe83a71 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 08:36:39 +0100 Subject: r26499: Allow testing python provision by setting the PROVISION_PYTHON environment variable. (This used to be commit 379d0bbb2f9e0cd9b1855fd77bbb89827e0315ad) --- source4/scripting/python/samba/provision.py | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 63e50897fe..60dcf06c83 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -189,7 +189,6 @@ def ldb_delete(ldb): ldb.connect(ldb.filename) - def open_ldb(session_info, credentials, dbname): assert session_info is not None try: @@ -641,25 +640,16 @@ def provision_guess(lp): return subobj - def load_schema(setup_dir, subobj, samdb): """Load schema.""" src = os.path.join(setup_dir, "schema.ldif") - schema_data = open(src, 'r').read() - src = os.path.join(setup_dir, "schema_samba4.ldif") - schema_data += open(src, 'r').read() - schema_data = substitute_var(schema_data, subobj.subst_vars()) - src = os.path.join(setup_dir, "provision_schema_basedn_modify.ldif") - head_data = open(src, 'r').read() - head_data = substitute_var(head_data, subobj.subst_vars()) - samdb.attach_dsdb_schema_from_ldif(head_data, schema_data) -- cgit From 32f439bfa458f7936b507cb5a1e3c74bcb8c68bf Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 11:12:36 +0100 Subject: r26503: Change order of arguments in param interface so it's easier to make the section name optional. Fix several smaller bits and pieces in the Python code. (This used to be commit 1b89311e5fa4fcde060df50e580dc221205cc8ca) --- source4/scripting/python/samba/__init__.py | 56 ++++++++++++------------ source4/scripting/python/samba/provision.py | 30 ++++++------- source4/scripting/python/samba/tests/__init__.py | 2 +- 3 files changed, 45 insertions(+), 43 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 56adce4473..511dcd905a 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -33,11 +33,9 @@ if _in_source_tree(): default_ldb_modules_dir = "%s/bin/modules/ldb" % srcdir -import misc import ldb -ldb.Ldb.set_credentials = misc.ldb_set_credentials -ldb.Ldb.set_session_info = misc.ldb_set_session_info -ldb.Ldb.set_loadparm = misc.ldb_set_loadparm +import credentials +import misc class Ldb(ldb.Ldb): """Simple Samba-specific LDB subclass that takes care @@ -47,38 +45,42 @@ class Ldb(ldb.Ldb): not necessarily the Sam database. For Sam-specific helper functions see samdb.py. """ - def __init__(url, session_info=None, credentials=None, modules_dir=None, - lp=None): + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): """Open a Samba Ldb file. - :param url: LDB Url to open + :param url: Optional LDB URL to open :param session_info: Optional session information :param credentials: Optional credentials, defaults to anonymous. - :param modules_dir: Modules directory, automatically set if not specified. + :param modules_dir: Modules directory, if not the default. :param lp: Loadparm object, optional. This is different from a regular Ldb file in that the Samba-specific modules-dir is used by default and that credentials and session_info can be passed through (required by some modules). """ - super(self, Ldb).__init__() - import ldb - ret = ldb.Ldb() - if modules_dir is None: - modules_dir = default_ldb_modules_dir + super(Ldb, self).__init__() + if modules_dir is not None: - ret.set_modules_dir(modules_dir) - def samba_debug(level,text): - print "%d %s" % (level, text) + self.set_modules_dir(modules_dir) + elif default_ldb_modules_dir is not None: + self.set_modules_dir(default_ldb_modules_dir) + if credentials is not None: - ldb.set_credentials(credentials) + self.set_credentials(self, credentials) + if session_info is not None: - ldb.set_session_info(session_info) + self.set_session_info(self, session_info) + if lp is not None: - ldb.set_loadparm(lp) - #ret.set_debug(samba_debug) - ret.connect(url) - return ret + self.set_loadparm(self, lp) + + if url: + self.connect(url) + + set_credentials = misc.ldb_set_credentials + set_session_info = misc.ldb_set_session_info + set_loadparm = misc.ldb_set_loadparm def searchone(self, basedn, expression, attribute): """Search for one attribute as a string.""" @@ -93,19 +95,19 @@ class Ldb(ldb.Ldb): for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: try: - self.delete(Dn(self, attr)) - except LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + self.delete(ldb.Dn(self, attr)) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): # Ignore missing dn errors pass - basedn = Dn(self, "") + basedn = ldb.Dn(self, "") # and the rest - for msg in self.search(basedn, SCOPE_SUBTREE, + for msg in self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]): self.delete(msg.dn) - res = self.search(basedn, SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) + res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) assert len(res) == 0 diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 60dcf06c83..5332a9f9ff 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -16,6 +16,7 @@ import param import registry from samba import Ldb, substitute_var, valid_netbios_name from samba.samdb import SamDB +import security from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring @@ -69,7 +70,7 @@ class ProvisionSettings(object): "DOMAINDN_LDB": self.domaindn_ldb, "DOMAINDN_MOD": "pdc_fsmo,password_hash", "DOMAINDN_MOD2": ",objectguid", - "DOMAINSID": self.domainsid, + "DOMAINSID": str(self.domainsid), "MODULES_LIST": ",".join(self.modules_list), "CONFIGDN_MOD": "naming_fsmo", "CONFIGDN_MOD2": ",objectguid", @@ -115,13 +116,13 @@ class ProvisionSettings(object): if not valid_netbios_name(self.netbiosname): raise InvalidNetbiosName(self.netbiosname) - if lp.get("workgroup").upper() != self.domain.upper(): + if lp.get_string("workgroup").upper() != self.domain.upper(): raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", - lp.get("workgroup"), self.domain) + lp.get_string("workgroup"), self.domain) - if lp.get("realm").upper() != self.realm.upper(): + if lp.get_string("realm").upper() != self.realm.upper(): raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % - (lp.get("realm"), self.realm)) + (lp.get_string("realm"), self.realm)) class ProvisionPaths: @@ -147,9 +148,9 @@ class ProvisionPaths: def install_ok(lp, session_info, credentials): """Check whether the current install seems ok.""" - if lp.get("realm") == "": + if lp.get_string("realm") == "": return False - ldb = Ldb(lp.get("sam database"), session_info=session_info, + ldb = Ldb(lp.get_string("sam database"), session_info=session_info, credentials=credentials) if len(ldb.search("(cn=Administrator)")) != 1: return False @@ -166,7 +167,6 @@ def findnss(nssfn, *names): raise Exception("Unable to find user/group for %s" % arguments[1]) - def hostip(): """return first host IP.""" return gethostbyname(hostname()) @@ -230,7 +230,7 @@ def setup_ldb(setup_dir, ldif, session_info, credentials, subobj, dbname, ldb.transaction_start() try: if erase: - ldb_erase(ldb); + ldb.erase(); setup_add_ldif(setup_dir, ldif, subobj, ldb) except: ldb.transaction_cancel() @@ -271,10 +271,10 @@ def provision_default_paths(lp, subobj): :param subobj: Object """ paths = ProvisionPaths() - private_dir = lp.get("private dir") + private_dir = lp.get_string("private dir") paths.shareconf = os.path.join(private_dir, "share.ldb") - paths.samdb = lp.get("sam database") or os.path.join(private_dir, "samdb.ldb") - paths.secrets = lp.get("secrets database") or os.path.join(private_dir, "secrets.ldb") + paths.samdb = lp.get_string("sam database") or os.path.join(private_dir, "samdb.ldb") + paths.secrets = lp.get_string("secrets database") or os.path.join(private_dir, "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") paths.keytab = os.path.join(private_dir, "secrets.keytab") paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone") @@ -572,8 +572,8 @@ def provision_ldapbase(setup_dir, subobj, message, paths): def provision_guess(lp): """guess reasonably default options for provisioning.""" - subobj = ProvisionSettings(realm=lp.get("realm").upper(), - domain=lp.get("workgroup"), + subobj = ProvisionSettings(realm=lp.get_string("realm").upper(), + domain=lp.get_string("workgroup"), hostname=hostname(), hostip=hostip()) @@ -581,7 +581,7 @@ def provision_guess(lp): assert subobj.domain is not None assert subobj.hostname is not None - subobj.domainsid = sid.random() + subobj.domainsid = security.random_sid() subobj.invocationid = uuid.random() subobj.policyguid = uuid.random() subobj.krbtgtpass = misc.random_password(12) diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index d374f8bafa..d3930e217a 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -27,7 +27,7 @@ class LdbTestCase(unittest.TestCase): self.filename = os.tempnam() self.ldb = samba.Ldb(self.filename) - def load_modules(self, modules=[]): + def set_modules(self, modules=[]): m = ldb.Message() m.dn = ldb.Dn(self.ldb, "@MODULES") m["@LIST"] = ",".join(modules) -- cgit From f89c7a6e5eb082794d64b487e69fc442d138ca28 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 12:07:51 +0100 Subject: r26505: Add python bindings for some samdb-related functions, improve provisioning in python. (This used to be commit d2402251666738c0372bbbaeaa1d26c06e254033) --- source4/scripting/python/samba/provision.py | 6 ++---- source4/scripting/python/samba/samdb.py | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 5332a9f9ff..34191b7269 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -433,10 +433,8 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, message("Pre-loading the Samba 4 and AD schema") - samdb = open_ldb(session_info, credentials, paths.samdb) - + samdb = SamDB(paths.samdb, session_info, credentials) samdb.set_domain_sid(subobj.domainsid) - load_schema(setup_dir, subobj, samdb) samdb.transaction_start() @@ -650,7 +648,7 @@ def load_schema(setup_dir, subobj, samdb): src = os.path.join(setup_dir, "provision_schema_basedn_modify.ldif") head_data = open(src, 'r').read() head_data = substitute_var(head_data, subobj.subst_vars()) - samdb.attach_dsdb_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, message): diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 50164bf590..73426121a6 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -21,6 +21,7 @@ # import samba +import misc class SamDB(samba.Ldb): def add_foreign(self, domaindn, sid, desc): @@ -114,4 +115,8 @@ member: %s enable_account(self, user_dn) self.transaction_commit() + def set_domain_sid(self, sid): + misc.samdb_set_domain_sid(self, sid) + def attach_schema_from_ldif(self, pf, df): + misc.dsdb_attach_schema_from_ldif_file(self, pf, df) -- cgit From 323c174be37214d561a5d525a7c3eef47ac700e8 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 12:19:45 +0100 Subject: r26506: Start running (really trivial) tests for upgrade script. (This used to be commit 73bd4a9566d15f85a971e3a87cefbec2e2eece1c) --- source4/scripting/python/samba/tests/upgrade.py | 2 +- source4/scripting/python/samba/upgrade.py | 602 ++++++++++++------------ 2 files changed, 302 insertions(+), 302 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/upgrade.py b/source4/scripting/python/samba/tests/upgrade.py index f46d869656..a25743425b 100644 --- a/source4/scripting/python/samba/tests/upgrade.py +++ b/source4/scripting/python/samba/tests/upgrade.py @@ -25,4 +25,4 @@ class RegkeyDnTests(TestCase): self.assertEquals("hive=NONE", regkey_to_dn("")) def test_nested(self): - self.assertEquals("key=foo,key=bar,hive=NONE", regkey_to_dn("foo/bar")) + self.assertEquals("key=bar,key=foo,hive=NONE", regkey_to_dn("foo/bar")) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 1908e3ea55..783cc008d5 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -11,17 +11,19 @@ from provision import findnss import provision import grp import pwd -from uuid import uuid4 -from param import default_configuration +import uuid def regkey_to_dn(name): """Convert a registry key to a DN.""" - dn = "hive=NONE" + dn = "hive=NONE" - for el in name.split("/")[1:]: + if name == "": + return dn + + for el in name.split("/"): dn = "key=%s," % el + dn - return dn + return dn # Where prefix is any of: # - HKLM @@ -33,39 +35,39 @@ def regkey_to_dn(name): def upgrade_registry(regdb,prefix,ldb): """Migrate registry contents.""" - assert regdb is not None: - prefix_up = prefix.upper() - ldif = [] + assert regdb is not None + prefix_up = prefix.upper() + ldif = [] for rk in regdb.keys: - pts = rk.name.split("/") + pts = rk.name.split("/") - # Only handle selected hive + # Only handle selected hive if pts[0].upper() != prefix_up: - continue + continue - keydn = regkey_to_dn(rk.name) + keydn = regkey_to_dn(rk.name) - pts = rk.name.split("/") + pts = rk.name.split("/") - # Convert key name to dn - ldif[rk.name] = """ + # Convert key name to dn + ldif[rk.name] = """ dn: %s name: %s """ % (keydn, pts[0]) - + for rv in rk.values: - ldif[rk.name + " (" + rv.name + ")"] = """ + ldif[rk.name + " (" + rv.name + ")"] = """ dn: %s,value=%s value: %s type: %d data:: %s""" % (keydn, rv.name, rv.name, rv.type, ldb.encode(rv.data)) - return ldif + return ldif def upgrade_sam_policy(samba3,dn): - ldif = """ + ldif = """ dn: %s changetype: modify replace: minPwdLength @@ -80,30 +82,30 @@ samba3BadLockoutMinutes: %d samba3DisconnectTime: %d """ % (dn, samba3.policy.min_password_length, - samba3.policy.password_history, samba3.policy.minimum_password_age, - samba3.policy.maximum_password_age, samba3.policy.lockout_duration, - samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password, - samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time) - - return ldif + samba3.policy.password_history, samba3.policy.minimum_password_age, + samba3.policy.maximum_password_age, samba3.policy.lockout_duration, + samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password, + samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time) + + return ldif def upgrade_sam_account(ldb,acc,domaindn,domainsid): """Upgrade a SAM account.""" if acc.nt_username is None or acc.nt_username == "": - acc.nt_username = acc.username + acc.nt_username = acc.username if acc.fullname is None: - acc.fullname = pwd.getpwnam(acc.fullname)[4] + acc.fullname = pwd.getpwnam(acc.fullname)[4] - acc.fullname = acc.fullname.split(",")[0] + acc.fullname = acc.fullname.split(",")[0] if acc.fullname is None: - acc.fullname = acc.username - - assert acc.fullname is not None - assert acc.nt_username is not None + acc.fullname = acc.username + + assert acc.fullname is not None + assert acc.nt_username is not None - ldif = """dn: cn=%s,%s + ldif = """dn: cn=%s,%s objectClass: top objectClass: user lastLogon: %d @@ -136,31 +138,31 @@ acc.acct_desc, acc.group_rid, acc.bad_password_count, acc.logon_count, acc.domain, acc.dir_drive, acc.munged_dial, acc.homedir, acc.logon_script, acc.profile_path, acc.workstations, acc.kickoff_time, acc.bad_password_time, acc.pass_last_set_time, acc.pass_can_change_time, acc.pass_must_change_time, domainsid, acc.user_rid, - ldb.encode(acc.lm_pw), ldb.encode(acc.nt_pw)) + ldb.encode(acc.lm_pw), ldb.encode(acc.nt_pw)) - return ldif + return ldif def upgrade_sam_group(group,domaindn): """Upgrade a SAM group.""" - if group.sid_name_use == 5: # Well-known group - return None + if group.sid_name_use == 5: # Well-known group + return None if group.nt_name in ("Domain Guests", "Domain Users", "Domain Admins"): - return None - + return None + if group.gid == -1: - gr = grp.getgrnam(grp.nt_name) + gr = grp.getgrnam(grp.nt_name) else: - gr = grp.getgrgid(grp.gid) + gr = grp.getgrgid(grp.gid) if gr is None: - group.unixname = "UNKNOWN" + group.unixname = "UNKNOWN" else: - group.unixname = gr.gr_name + group.unixname = gr.gr_name - assert group.unixname is not None - - ldif = """dn: cn=%s,%s + assert group.unixname is not None + + ldif = """dn: cn=%s,%s objectClass: top objectClass: group description: %s @@ -171,11 +173,11 @@ samba3SidNameUse: %d """ % (group.nt_name, domaindn, group.comment, group.nt_name, group.sid, group.unixname, group.sid_name_use) - return ldif + return ldif def upgrade_winbind(samba3,domaindn): - ldif = """ - + ldif = """ + dn: dc=none userHwm: %d groupHwm: %d @@ -183,48 +185,48 @@ groupHwm: %d """ % (samba3.idmap.user_hwm, samba3.idmap.group_hwm) for m in samba3.idmap.mappings: - ldif += """ + ldif += """ dn: SID=%s,%s SID: %s type: %d unixID: %d""" % (m.sid, domaindn, m.sid, m.type, m.unix_id) - - return ldif + + return ldif def upgrade_wins(samba3): """Upgrade the WINS database.""" - ldif = "" - version_id = 0 + ldif = "" + version_id = 0 for e in samba3.winsentries: - now = sys.nttime() - ttl = sys.unix2nttime(e.ttl) + now = sys.nttime() + ttl = sys.unix2nttime(e.ttl) - version_id+=1 + version_id+=1 numIPs = len(e.ips) if e.type == 0x1C: - rType = 0x2 + rType = 0x2 elif e.type & 0x80: if numIPs > 1: - rType = 0x2 + rType = 0x2 else: - rType = 0x1 + rType = 0x1 else: if numIPs > 1: - rType = 0x3 + rType = 0x3 else: - rType = 0x0 + rType = 0x0 if ttl > now: - rState = 0x0 # active + rState = 0x0 # active else: - rState = 0x1 # released + rState = 0x1 # released - nType = ((e.nb_flags & 0x60)>>5) + nType = ((e.nb_flags & 0x60)>>5) - ldif += """ + ldif += """ dn: name=%s,type=0x%02X type: 0x%02X name: %s @@ -240,324 +242,322 @@ versionID: %llu ldaptime(ttl), version_id) for ip in e.ips: - ldif += "address: %s\n" % ip + ldif += "address: %s\n" % ip - ldif += """ + ldif += """ dn: CN=VERSION objectClass: winsMaxVersion maxVersion: %llu """ % version_id - return ldif + return ldif def upgrade_provision(lp, samba3): - subobj = Object() + subobj = Object() - domainname = samba3.configuration.get("workgroup") - + domainname = samba3.configuration.get("workgroup") + if domainname is None: - domainname = samba3.secrets.domains[0].name - print "No domain specified in smb.conf file, assuming '%s'\n" % domainname - - domsec = samba3.find_domainsecrets(domainname) - hostsec = samba3.find_domainsecrets(hostname()) - realm = samba3.configuration.get("realm") + domainname = samba3.secrets.domains[0].name + print "No domain specified in smb.conf file, assuming '%s'\n" % domainname + + domsec = samba3.find_domainsecrets(domainname) + hostsec = samba3.find_domainsecrets(hostname()) + realm = samba3.configuration.get("realm") if realm is None: - realm = domainname - print "No realm specified in smb.conf file, assuming '%s'\n" % realm - random_init(local) + realm = domainname + print "No realm specified in smb.conf file, assuming '%s'\n" % realm + random_init(local) - subobj.realm = realm - subobj.domain = domainname - subobj.hostname = hostname() + subobj.realm = realm + subobj.domain = domainname + subobj.hostname = hostname() - assert subobj.realm is not None - assert subobj.domain is not None - assert subobj.hostname is not None + assert subobj.realm is not None + assert subobj.domain is not None + assert subobj.hostname is not None - subobj.HOSTIP = hostip() + subobj.HOSTIP = hostip() if domsec is not None: - subobj.DOMAINGUID = domsec.guid - subobj.DOMAINSID = domsec.sid + subobj.DOMAINGUID = domsec.guid + subobj.DOMAINSID = domsec.sid else: - print "Can't find domain secrets for '%s'; using random SID and GUID\n" % domainname - subobj.DOMAINGUID = uuid4() - subobj.DOMAINSID = randsid() - + print "Can't find domain secrets for '%s'; using random SID and GUID\n" % domainname + subobj.DOMAINGUID = uuid.random() + subobj.DOMAINSID = randsid() + if hostsec: - subobj.HOSTGUID = hostsec.guid + subobj.HOSTGUID = hostsec.guid else: - subobj.HOSTGUID = uuid4() - subobj.invocationid = uuid4() - subobj.krbtgtpass = randpass(12) - subobj.machinepass = randpass(12) - subobj.adminpass = randpass(12) - subobj.datestring = datestring() - subobj.root = findnss(pwd.getpwnam, "root")[4] - subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] - subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] - subobj.wheel = findnss(grp.getgrnam, "wheel", "root")[2] - subobj.users = findnss(grp.getgrnam, "users", "guest", "other")[2] - subobj.dnsdomain = subobj.realm.lower() - subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) - subobj.basedn = "DC=" + ",DC=".join(subobj.realm.split(".")) - rdn_list = subobj.dnsdomain.split(".") - subobj.domaindn = "DC=" + ",DC=".join(rdn_list) - subobj.domaindn_ldb = "users.ldb" - subobj.rootdn = subobj.domaindn - - modules_list = ["rootdse", - "kludge_acl", - "paged_results", - "server_sort", - "extended_dn", - "asq", - "samldb", - "password_hash", - "operational", - "objectclass", - "rdn_name", - "show_deleted", - "partition"] - subobj.modules_list = ",".join(modules_list) - - return subobj + subobj.HOSTGUID = uuid.random() + subobj.invocationid = uuid.random() + subobj.krbtgtpass = randpass(12) + subobj.machinepass = randpass(12) + subobj.adminpass = randpass(12) + subobj.datestring = datestring() + subobj.root = findnss(pwd.getpwnam, "root")[4] + subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] + subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + subobj.wheel = findnss(grp.getgrnam, "wheel", "root")[2] + subobj.users = findnss(grp.getgrnam, "users", "guest", "other")[2] + subobj.dnsdomain = subobj.realm.lower() + subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) + subobj.basedn = "DC=" + ",DC=".join(subobj.realm.split(".")) + rdn_list = subobj.dnsdomain.split(".") + subobj.domaindn = "DC=" + ",DC=".join(rdn_list) + subobj.domaindn_ldb = "users.ldb" + subobj.rootdn = subobj.domaindn + + modules_list = ["rootdse", + "kludge_acl", + "paged_results", + "server_sort", + "extended_dn", + "asq", + "samldb", + "password_hash", + "operational", + "objectclass", + "rdn_name", + "show_deleted", + "partition"] + subobj.modules_list = ",".join(modules_list) + + return subobj smbconf_keep = [ - "dos charset", - "unix charset", - "display charset", - "comment", - "path", - "directory", - "workgroup", - "realm", - "netbios name", - "netbios aliases", - "netbios scope", - "server string", - "interfaces", - "bind interfaces only", - "security", - "auth methods", - "encrypt passwords", - "null passwords", - "obey pam restrictions", - "password server", - "smb passwd file", - "private dir", - "passwd chat", - "password level", - "lanman auth", - "ntlm auth", - "client NTLMv2 auth", - "client lanman auth", - "client plaintext auth", - "read only", - "hosts allow", - "hosts deny", - "log level", - "debuglevel", - "log file", - "smb ports", - "large readwrite", - "max protocol", - "min protocol", - "unicode", - "read raw", - "write raw", - "disable netbios", - "nt status support", - "announce version", - "announce as", - "max mux", - "max xmit", - "name resolve order", - "max wins ttl", - "min wins ttl", - "time server", - "unix extensions", - "use spnego", - "server signing", - "client signing", - "max connections", - "paranoid server security", - "socket options", - "strict sync", - "max print jobs", - "printable", - "print ok", - "printer name", - "printer", - "map system", - "map hidden", - "map archive", - "preferred master", - "prefered master", - "local master", - "browseable", - "browsable", - "wins server", - "wins support", - "csc policy", - "strict locking", - "preload", - "auto services", - "lock dir", - "lock directory", - "pid directory", - "socket address", - "copy", - "include", - "available", - "volume", - "fstype", - "panic action", - "msdfs root", - "host msdfs", - "winbind separator"] + "dos charset", + "unix charset", + "display charset", + "comment", + "path", + "directory", + "workgroup", + "realm", + "netbios name", + "netbios aliases", + "netbios scope", + "server string", + "interfaces", + "bind interfaces only", + "security", + "auth methods", + "encrypt passwords", + "null passwords", + "obey pam restrictions", + "password server", + "smb passwd file", + "private dir", + "passwd chat", + "password level", + "lanman auth", + "ntlm auth", + "client NTLMv2 auth", + "client lanman auth", + "client plaintext auth", + "read only", + "hosts allow", + "hosts deny", + "log level", + "debuglevel", + "log file", + "smb ports", + "large readwrite", + "max protocol", + "min protocol", + "unicode", + "read raw", + "write raw", + "disable netbios", + "nt status support", + "announce version", + "announce as", + "max mux", + "max xmit", + "name resolve order", + "max wins ttl", + "min wins ttl", + "time server", + "unix extensions", + "use spnego", + "server signing", + "client signing", + "max connections", + "paranoid server security", + "socket options", + "strict sync", + "max print jobs", + "printable", + "print ok", + "printer name", + "printer", + "map system", + "map hidden", + "map archive", + "preferred master", + "prefered master", + "local master", + "browseable", + "browsable", + "wins server", + "wins support", + "csc policy", + "strict locking", + "preload", + "auto services", + "lock dir", + "lock directory", + "pid directory", + "socket address", + "copy", + "include", + "available", + "volume", + "fstype", + "panic action", + "msdfs root", + "host msdfs", + "winbind separator"] -# -# Remove configuration variables not present in Samba4 -# oldconf: Old configuration structure -# mark: Whether removed configuration variables should be -# kept in the new configuration as "samba3:" def upgrade_smbconf(oldconf,mark): - data = oldconf.data() - newconf = param_init() - - for (s in data) { - for (p in data[s]) { - keep = False - for (k in smbconf_keep) { + """Remove configuration variables not present in Samba4 + + :param oldconf: Old configuration structure + :param mark: Whether removed configuration variables should be + kept in the new configuration as "samba3:" + """ + data = oldconf.data() + newconf = param_init() + + for s in data: + for p in data[s]: + keep = False + for k in smbconf_keep: if smbconf_keep[k] == p: - keep = True - break - } + keep = True + break if keep: - newconf.set(s, p, oldconf.get(s, p)) + newconf.set(s, p, oldconf.get(s, p)) elif mark: - newconf.set(s, "samba3:"+p, oldconf.get(s,p)) - } - } + newconf.set(s, "samba3:"+p, oldconf.get(s,p)) if oldconf.get("domain logons") == "True": - newconf.set("server role", "domain controller") + newconf.set("server role", "domain controller") else: if oldconf.get("security") == "user": - newconf.set("server role", "standalone") + newconf.set("server role", "standalone") else: - newconf.set("server role", "member server") + newconf.set("server role", "member server") - return newconf + return newconf def upgrade(subobj, samba3, message, paths, session_info, credentials): - ret = 0 - lp = loadparm_init() - samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) + ret = 0 + lp = loadparm_init() + samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) - message("Writing configuration") - newconf = upgrade_smbconf(samba3.configuration,True) - newconf.save(paths.smbconf) + message("Writing configuration") + newconf = upgrade_smbconf(samba3.configuration,True) + newconf.save(paths.smbconf) - message("Importing account policies") - ldif = upgrade_sam_policy(samba3,subobj.BASEDN) - samdb.modify(ldif) - regdb = Ldb(paths.hklm) + message("Importing account policies") + ldif = upgrade_sam_policy(samba3,subobj.BASEDN) + samdb.modify(ldif) + regdb = Ldb(paths.hklm) - regdb.modify(" + regdb.modify(""" dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE replace: type type: 4 replace: data data: %d -" % samba3.policy.refuse_machine_password_change) +""" % samba3.policy.refuse_machine_password_change) - message("Importing users") + message("Importing users") for account in samba3.samaccounts: - msg = "... " + account.username - ldif = upgrade_sam_account(samdb, accounts,subobj.BASEDN,subobj.DOMAINSID) + msg = "... " + account.username + ldif = upgrade_sam_account(samdb, accounts,subobj.BASEDN,subobj.DOMAINSID) try: samdb.add(ldif) except LdbError, e: # FIXME: Ignore 'Record exists' errors - msg += "... error: " + str(e) - ret += 1; - message(msg) + msg += "... error: " + str(e) + ret += 1; + message(msg) - message("Importing groups") + message("Importing groups") for mapping in samba3.groupmappings: - msg = "... " + mapping.nt_name - ldif = upgrade_sam_group(mapping, subobj.BASEDN) + msg = "... " + mapping.nt_name + ldif = upgrade_sam_group(mapping, subobj.BASEDN) if ldif is not None: try: - samdb.add(ldif) + samdb.add(ldif) except LdbError, e: # FIXME: Ignore 'Record exists' errors - msg += "... error: " + str(e) - ret += 1 - message(msg) + msg += "... error: " + str(e) + ret += 1 + message(msg) - message("Importing registry data") + message("Importing registry data") for hive in ["hkcr","hkcu","hklm","hkpd","hku","hkpt"]: - message("... " + hive) - regdb = Ldb(paths[hive]) - ldif = upgrade_registry(samba3.registry, hive, regdb) - for (var j in ldif) { - var msg = "... ... " + j + message("... " + hive) + regdb = Ldb(paths[hive]) + ldif = upgrade_registry(samba3.registry, hive, regdb) + for j in ldif: + msg = "... ... " + j try: regdb.add(ldif[j]) except LdbError, e: # FIXME: Ignore 'Record exists' errors - msg += "... error: " + str(e) - ret += 1 - message(msg) + msg += "... error: " + str(e) + ret += 1 + message(msg) - message("Importing WINS data") - winsdb = Ldb(paths.winsdb) - ldb_erase(winsdb) + message("Importing WINS data") + winsdb = Ldb(paths.winsdb) + ldb_erase(winsdb) - ldif = upgrade_wins(samba3) - winsdb.add(ldif) + ldif = upgrade_wins(samba3) + winsdb.add(ldif) - # figure out ldapurl, if applicable - ldapurl = None - pdb = samba3.configuration.get_list("passdb backend") + # figure out ldapurl, if applicable + ldapurl = None + pdb = samba3.configuration.get_list("passdb backend") if pdb is not None: for backend in pdb: if len(backend) >= 7 and backend[0:7] == "ldapsam": ldapurl = backend[7:] - # URL was not specified in passdb backend but ldap /is/ used + # URL was not specified in passdb backend but ldap /is/ used if ldapurl == "": - ldapurl = "ldap://%s" % samba3.configuration.get("ldap server") + ldapurl = "ldap://%s" % samba3.configuration.get("ldap server") - # Enable samba3sam module if original passdb backend was ldap + # Enable samba3sam module if original passdb backend was ldap if ldapurl is not None: - message("Enabling Samba3 LDAP mappings for SAM database") + message("Enabling Samba3 LDAP mappings for SAM database") - samdb.modify(""" + samdb.modify(""" dn: @MODULES changetype: modify replace: @LIST @LIST: samldb,operational,objectguid,rdn_name,samba3sam """) - samdb.add(""" + samdb.add(""" dn: @MAP=samba3sam -@MAP_URL: %s""", ldapurl)) +@MAP_URL: %s""" % ldapurl) - return ret + return ret def upgrade_verify(subobj, samba3, paths, message): - message("Verifying account policies") + message("Verifying account policies") - samldb = Ldb(paths.samdb) + samldb = Ldb(paths.samdb) for account in samba3.samaccounts: - msg = samldb.search("(&(sAMAccountName=" + account.nt_username + ")(objectclass=user))") - assert(len(msg) >= 1) - - # FIXME + msg = samldb.search("(&(sAMAccountName=" + account.nt_username + ")(objectclass=user))") + assert(len(msg) >= 1) + + # FIXME -- cgit From ca74c6e6c426e6b69ba31676e2b06dda29b5409e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 20:03:06 +0100 Subject: r26513: Update substitution dictionary for ldifs. (This used to be commit 60fb2de2119cb2f42f858868e39c3b0d303ac20f) --- source4/scripting/python/samba/__init__.py | 3 +++ source4/scripting/python/samba/provision.py | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 511dcd905a..f89ac39ac7 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -122,6 +122,8 @@ def substitute_var(text, values): for (name, value) in values.items(): text = text.replace("${%s}" % name, value) + assert "${" not in text, text + return text @@ -133,3 +135,4 @@ def valid_netbios_name(name): return False return True +version = misc.version diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 34191b7269..7d7b85c13e 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -14,6 +14,7 @@ import uuid, misc from socket import gethostname, gethostbyname import param import registry +import samba from samba import Ldb, substitute_var, valid_netbios_name from samba.samdb import SamDB import security @@ -56,6 +57,7 @@ class ProvisionSettings(object): self.schemedn_ldb = None self.s4_ldapi_path = None self.policyguid = None + self.extensibleobject = None def subst_vars(self): return {"SCHEMADN": self.schemadn, @@ -77,6 +79,7 @@ class ProvisionSettings(object): "NETBIOSNAME": self.netbiosname, "DNSNAME": self.dnsname, "ROOTDN": self.rootdn, + "DOMAIN": self.domain, "DNSDOMAIN": self.dnsdomain, "REALM": self.realm, "DEFAULTSITE": self.defaultsite, @@ -89,6 +92,9 @@ class ProvisionSettings(object): "POLICYGUID": self.policyguid, "RDN_DC": self.rdn_dc, "DOMAINGUID_MOD": self.domainguid_mod, + "VERSION": samba.version(), + "ACI": "# no aci for local ldb", + "EXTENSIBLEOBJECT": self.extensibleobject, } def fix(self, paths): -- cgit From 57b8a8fd42f5d89f439fd9d0781bd8f561a84131 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 23:16:12 +0100 Subject: r26517: Add functions for setting and getting parameters on a LoadParm. Pass loadparm context along to Ldb contexts. Other minor Python improvements. (This used to be commit 7a15b486bae8fb774058b2d94cc12b7b01ee6ac0) --- source4/scripting/python/samba/provision.py | 66 +++++++++++++++-------------- 1 file changed, 35 insertions(+), 31 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 7d7b85c13e..d88b8501ba 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -122,13 +122,13 @@ class ProvisionSettings(object): if not valid_netbios_name(self.netbiosname): raise InvalidNetbiosName(self.netbiosname) - if lp.get_string("workgroup").upper() != self.domain.upper(): + if lp.get("workgroup").upper() != self.domain.upper(): raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", - lp.get_string("workgroup"), self.domain) + lp.get("workgroup"), self.domain) - if lp.get_string("realm").upper() != self.realm.upper(): + if lp.get("realm").upper() != self.realm.upper(): raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % - (lp.get_string("realm"), self.realm)) + (lp.get("realm"), self.realm)) class ProvisionPaths: @@ -154,10 +154,10 @@ class ProvisionPaths: def install_ok(lp, session_info, credentials): """Check whether the current install seems ok.""" - if lp.get_string("realm") == "": + if lp.get("realm") == "": return False - ldb = Ldb(lp.get_string("sam database"), session_info=session_info, - credentials=credentials) + ldb = Ldb(lp.get("sam database"), session_info=session_info, + credentials=credentials, lp=lp) if len(ldb.search("(cn=Administrator)")) != 1: return False return True @@ -195,14 +195,16 @@ def ldb_delete(ldb): ldb.connect(ldb.filename) -def open_ldb(session_info, credentials, dbname): +def open_ldb(session_info, credentials, lp, dbname): assert session_info is not None try: - return Ldb(dbname, session_info=session_info, credentials=credentials) + return Ldb(dbname, session_info=session_info, credentials=credentials, + lp=lp) except LdbError, e: print e os.unlink(dbname) - return Ldb(dbname, session_info=session_info, credentials=credentials) + return Ldb(dbname, session_info=session_info, credentials=credentials, + lp=lp) def setup_add_ldif(setup_dir, ldif, subobj, ldb): @@ -228,10 +230,10 @@ def setup_modify_ldif(setup_dir, ldif, subobj, ldb): ldb.modify(msg) -def setup_ldb(setup_dir, ldif, session_info, credentials, subobj, dbname, +def setup_ldb(setup_dir, ldif, session_info, credentials, subobj, lp, dbname, erase=True): assert dbname is not None - ldb = open_ldb(session_info, credentials, dbname) + ldb = open_ldb(session_info, credentials, lp, dbname) assert ldb is not None ldb.transaction_start() try: @@ -277,10 +279,10 @@ def provision_default_paths(lp, subobj): :param subobj: Object """ paths = ProvisionPaths() - private_dir = lp.get_string("private dir") + private_dir = lp.get("private dir") paths.shareconf = os.path.join(private_dir, "share.ldb") - paths.samdb = lp.get_string("sam database") or os.path.join(private_dir, "samdb.ldb") - paths.secrets = lp.get_string("secrets database") or os.path.join(private_dir, "secrets.ldb") + paths.samdb = lp.get("sam database") or os.path.join(private_dir, "samdb.ldb") + paths.secrets = lp.get("secrets database") or os.path.join(private_dir, "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") paths.keytab = os.path.join(private_dir, "secrets.keytab") paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone") @@ -329,22 +331,22 @@ def setup_name_mappings(subobj, ldb): ldb.setup_name_mapping(subobj.domaindn, sid + "-520", subobj.wheel) -def provision_become_dc(setup_dir, subobj, message, paths, session_info, +def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, credentials): assert session_info is not None subobj.fix(paths) message("Setting up templates into %s" % paths.templates) setup_ldb(setup_dir, "provision_templates.ldif", session_info, - credentials, subobj, paths.templates) + credentials, subobj, lp, paths.templates) # Also wipes the database message("Setting up %s partitions" % paths.samdb) setup_ldb(setup_dir, "provision_partitions.ldif", session_info, - credentials, subobj, paths.samdb) + credentials, subobj, lp, paths.samdb) samdb = SamDB(paths.samdb, session_info=session_info, - credentials=credentials) + credentials=credentials, lp=lp) ldb.transaction_start() try: message("Setting up %s attributes" % paths.samdb) @@ -366,9 +368,9 @@ def provision_become_dc(setup_dir, subobj, message, paths, session_info, message("Setting up %s" % paths.secrets) setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, - subobj, paths.secrets) + subobj, lp, paths.secrets) - setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, + setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, lp, paths.secrets, False) @@ -401,11 +403,11 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") - setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj, paths.shareconf) + setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj, lp, paths.shareconf) message("Setting up %s" % paths.secrets) - setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, subobj, paths.secrets) - setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, paths.secrets, False) + setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, subobj, lp, paths.secrets) + setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, lp, paths.secrets, False) message("Setting up registry") reg = registry.Registry() @@ -414,13 +416,13 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, #reg.apply_patchfile(os.path.join(setup_dir, "provision.reg")) message("Setting up templates into %s" % paths.templates) - setup_ldb(setup_dir, "provision_templates.ldif", session_info, credentials, subobj, paths.templates) + setup_ldb(setup_dir, "provision_templates.ldif", session_info, credentials, subobj, lp, paths.templates) message("Setting up sam.ldb partitions") setup_ldb(setup_dir, "provision_partitions.ldif", session_info, - credentials, subobj, paths.samdb) + credentials, subobj, lp, paths.samdb) - samdb = open_ldb(session_info, credentials, paths.samdb) + samdb = open_ldb(session_info, credentials, lp, paths.samdb) samdb.transaction_start() try: message("Setting up sam.ldb attributes") @@ -439,7 +441,8 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, message("Pre-loading the Samba 4 and AD schema") - samdb = SamDB(paths.samdb, session_info, credentials) + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) samdb.set_domain_sid(subobj.domainsid) load_schema(setup_dir, subobj, samdb) @@ -531,7 +534,8 @@ def provision_dns(setup_dir, subobj, message, paths, session_info, credentials): """Write out a DNS zone file, from the info in the current database.""" message("Setting up DNS zone: %s" % subobj.dnsdomain) # connect to the sam - ldb = SamDB(paths.samdb, session_info=session_info, credentials=credentials) + ldb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, + lp=lp) # These values may have changed, due to an incoming SamSync, # or may not have been specified, so fetch them from the database @@ -576,8 +580,8 @@ def provision_ldapbase(setup_dir, subobj, message, paths): def provision_guess(lp): """guess reasonably default options for provisioning.""" - subobj = ProvisionSettings(realm=lp.get_string("realm").upper(), - domain=lp.get_string("workgroup"), + subobj = ProvisionSettings(realm=lp.get("realm").upper(), + domain=lp.get("workgroup"), hostname=hostname(), hostip=hostip()) -- cgit From 12a513b47b1a1f2adeb2cb2a10ac36d02dd44065 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 17 Dec 2007 23:16:16 +0100 Subject: r26518: Fix provision of registry using Python. (This used to be commit 12eb38e553993b2726a803af4ae9c05229d6ebe4) --- source4/scripting/python/samba/provision.py | 40 +++++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d88b8501ba..d9863420b6 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -287,11 +287,15 @@ def provision_default_paths(lp, subobj): paths.keytab = os.path.join(private_dir, "secrets.keytab") paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone") paths.winsdb = os.path.join(private_dir, "wins.ldb") - paths.ldap_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + ".ldif") - paths.ldap_config_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + "-config.ldif") - paths.ldap_schema_basedn_ldif = os.path.join(private_dir, subobj.dnsdomain + "-schema.ldif") + paths.ldap_basedn_ldif = os.path.join(private_dir, + subobj.dnsdomain + ".ldif") + paths.ldap_config_basedn_ldif = os.path.join(private_dir, + subobj.dnsdomain + "-config.ldif") + paths.ldap_schema_basedn_ldif = os.path.join(private_dir, + subobj.dnsdomain + "-schema.ldif") paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") - paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php") + paths.phpldapadminconfig = os.path.join(private_dir, + "phpldapadmin-config.php") paths.hklm = os.path.join(private_dir, "hklm.ldb") return paths @@ -370,8 +374,8 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, subobj, lp, paths.secrets) - setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, lp, - paths.secrets, False) + setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, + lp, paths.secrets, False) def provision(lp, setup_dir, subobj, message, blank, paths, session_info, @@ -397,26 +401,34 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, # only install a new smb.conf if there isn't one there already if not os.path.exists(paths.smbconf): message("Setting up smb.conf") - setup_file(setup_dir, "provision.smb.conf", message, paths.smbconf, subobj) + setup_file(setup_dir, "provision.smb.conf", message, paths.smbconf, + subobj) lp.reload() # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") - setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj, lp, paths.shareconf) + setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj, + lp, paths.shareconf) message("Setting up %s" % paths.secrets) - setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, subobj, lp, paths.secrets) - setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, lp, paths.secrets, False) + setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, + subobj, lp, paths.secrets) + setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, + lp, paths.secrets, False) message("Setting up registry") reg = registry.Registry() - # FIXME: Still fails for some reason: - #reg.mount(paths.hklm, registry.HKEY_LOCAL_MACHINE, []) - #reg.apply_patchfile(os.path.join(setup_dir, "provision.reg")) + hive = registry.Hive(paths.hklm, session_info=session_info, + credentials=credentials, lp_ctx=lp) + reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE, []) + provision_reg = os.path.join(setup_dir, "provision.reg") + assert os.path.exists(provision_reg) + reg.apply_patchfile(provision_reg) message("Setting up templates into %s" % paths.templates) - setup_ldb(setup_dir, "provision_templates.ldif", session_info, credentials, subobj, lp, paths.templates) + setup_ldb(setup_dir, "provision_templates.ldif", session_info, + credentials, subobj, lp, paths.templates) message("Setting up sam.ldb partitions") setup_ldb(setup_dir, "provision_partitions.ldif", session_info, -- cgit From 63f53094efa29b76eb4136cddf19d9c5d325fc5f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 18 Dec 2007 02:21:14 +0100 Subject: r26520: More Python updates. (This used to be commit a8b1fe15ac853082961132ede061fe1556ae29f7) --- source4/scripting/python/samba/__init__.py | 4 ++++ source4/scripting/python/samba/provision.py | 13 +++++++------ source4/scripting/python/samba/samdb.py | 8 +++++++- 3 files changed, 18 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index f89ac39ac7..8e0eff3011 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -78,6 +78,10 @@ class Ldb(ldb.Ldb): if url: self.connect(url) + def msg(l,text): + print text + #self.set_debug(msg) + set_credentials = misc.ldb_set_credentials set_session_info = misc.ldb_set_session_info set_loadparm = misc.ldb_set_loadparm diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d9863420b6..0a3c183fcc 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -306,7 +306,7 @@ def setup_name_mappings(subobj, ldb): ["objectSid"]) assert len(res) == 1 assert "objectSid" in res[0] - sid = list(res[0]["objectSid"])[0] + sid = str(list(res[0]["objectSid"])[0]) # add some foreign sids if they are not present already ldb.add_foreign(subobj.domaindn, "S-1-5-7", "Anonymous") @@ -419,12 +419,12 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, message("Setting up registry") reg = registry.Registry() - hive = registry.Hive(paths.hklm, session_info=session_info, - credentials=credentials, lp_ctx=lp) - reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE, []) + #hive = registry.Hive(paths.hklm, session_info=session_info, + # credentials=credentials, lp_ctx=lp) + #reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") provision_reg = os.path.join(setup_dir, "provision.reg") assert os.path.exists(provision_reg) - reg.apply_patchfile(provision_reg) + #reg.apply_patchfile(provision_reg) message("Setting up templates into %s" % paths.templates) setup_ldb(setup_dir, "provision_templates.ldif", session_info, @@ -434,7 +434,8 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, setup_ldb(setup_dir, "provision_partitions.ldif", session_info, credentials, subobj, lp, paths.samdb) - samdb = open_ldb(session_info, credentials, lp, paths.samdb) + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) samdb.transaction_start() try: message("Setting up sam.ldb attributes") diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 73426121a6..ce06efa3de 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -22,8 +22,14 @@ import samba import misc +import ldb class SamDB(samba.Ldb): + def __init__(self, *args, **kwargs): + super(SamDB, self).__init__(*args, **kwargs) + misc.dsdb_set_global_schema(self) + misc.ldb_register_samba_handlers(self) + def add_foreign(self, domaindn, sid, desc): """Add a foreign security principle.""" add = """ @@ -39,7 +45,7 @@ description: %s def setup_name_mapping(self, domaindn, sid, unixname): """Setup a mapping between a sam name and a unix name.""" - res = self.search(Dn(ldb, domaindn), SCOPE_SUBTREE, + res = self.search(ldb.Dn(self, domaindn), ldb.SCOPE_SUBTREE, "objectSid=%s" % sid, ["dn"]) assert len(res) == 1, "Failed to find record for objectSid %s" % sid -- cgit From 2fef113e82c1f324dc5b5474100eb537f0c98f80 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 18 Dec 2007 02:21:24 +0100 Subject: r26521: Fix newlines. (This used to be commit 174aa1583791a4c305bc49cf78f8f10d42701bc9) --- source4/scripting/python/samba/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 8e0eff3011..a46b148bbb 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -80,7 +80,7 @@ class Ldb(ldb.Ldb): def msg(l,text): print text - #self.set_debug(msg) + self.set_debug(msg) set_credentials = misc.ldb_set_credentials set_session_info = misc.ldb_set_session_info -- cgit From 54a48d40a10c813954e4b777377607bb8366a57e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 18 Dec 2007 02:21:28 +0100 Subject: r26522: Fix warnings on SamDB connect from Python, simplify the setup code for the various LDBs. (This used to be commit 20c686f501b652ec0578a075a124b72ecb5f41b6) --- source4/scripting/python/samba/__init__.py | 7 ++-- source4/scripting/python/samba/provision.py | 61 ++++++++++++++++------------- source4/scripting/python/samba/samdb.py | 8 +++- 3 files changed, 43 insertions(+), 33 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index a46b148bbb..fd294952b8 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -75,13 +75,14 @@ class Ldb(ldb.Ldb): if lp is not None: self.set_loadparm(self, lp) - if url: - self.connect(url) - def msg(l,text): print text self.set_debug(msg) + if url is not None: + self.connect(url) + + set_credentials = misc.ldb_set_credentials set_session_info = misc.ldb_set_session_info set_loadparm = misc.ldb_set_loadparm diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0a3c183fcc..2c6e50219a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -230,15 +230,10 @@ def setup_modify_ldif(setup_dir, ldif, subobj, ldb): ldb.modify(msg) -def setup_ldb(setup_dir, ldif, session_info, credentials, subobj, lp, dbname, - erase=True): - assert dbname is not None - ldb = open_ldb(session_info, credentials, lp, dbname) +def setup_ldb(ldb, setup_dir, ldif, subobj): assert ldb is not None ldb.transaction_start() try: - if erase: - ldb.erase(); setup_add_ldif(setup_dir, ldif, subobj, ldb) except: ldb.transaction_cancel() @@ -281,8 +276,8 @@ def provision_default_paths(lp, subobj): paths = ProvisionPaths() private_dir = lp.get("private dir") paths.shareconf = os.path.join(private_dir, "share.ldb") - paths.samdb = lp.get("sam database") or os.path.join(private_dir, "samdb.ldb") - paths.secrets = lp.get("secrets database") or os.path.join(private_dir, "secrets.ldb") + paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") + paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") paths.keytab = os.path.join(private_dir, "secrets.keytab") paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone") @@ -341,13 +336,17 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, subobj.fix(paths) message("Setting up templates into %s" % paths.templates) - setup_ldb(setup_dir, "provision_templates.ldif", session_info, - credentials, subobj, lp, paths.templates) + templates_ldb = Ldb(paths.templates, session_info=session_info, + credentials=credentials, lp=lp) + templates_ldb.erase() + setup_ldb(templates_ldb, setup_dir, "provision_templates.ldif", subobj) # Also wipes the database message("Setting up %s partitions" % paths.samdb) - setup_ldb(setup_dir, "provision_partitions.ldif", session_info, - credentials, subobj, lp, paths.samdb) + samdb = SamDB(paths.samdb, credentials=credentials, + session_info=session_info, lp=lp) + samdb.erase() + setup_ldb(samdb, setup_dir, "provision_partitions.ldif", subobj) samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) @@ -371,11 +370,12 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, samdb.transaction_commit() message("Setting up %s" % paths.secrets) - setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, - subobj, lp, paths.secrets) - - setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, - lp, paths.secrets, False) + secrets_ldb = Ldb(paths.secrets, session_info=session_info, + credentials=credentials, lp=lp) + secrets_ldb.clear() + setup_ldb(secrets_ldb, setup_dir, "secrets_init.ldif", subobj) + setup_ldb(secrets_ldb, setup_dir, "secrets.ldif", subobj) + setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", subobj) def provision(lp, setup_dir, subobj, message, blank, paths, session_info, @@ -408,14 +408,16 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") - setup_ldb(setup_dir, "share.ldif", session_info, credentials, subobj, - lp, paths.shareconf) + share_ldb = Ldb(paths.shareconf, session_info=session_info, + credentials=credentials, lp=lp) + setup_ldb(share_ldb, setup_dir, "share.ldif", subobj) message("Setting up %s" % paths.secrets) - setup_ldb(setup_dir, "secrets_init.ldif", session_info, credentials, - subobj, lp, paths.secrets) - setup_ldb(setup_dir, "secrets.ldif", session_info, credentials, subobj, - lp, paths.secrets, False) + secrets_ldb = Ldb(paths.secrets, session_info=session_info, + credentials=credentials, lp=lp) + secrets_ldb.erase() + setup_ldb(secrets_ldb, setup_dir, "secrets_init.ldif", subobj) + setup_ldb(secrets_ldb, setup_dir, "secrets.ldif", subobj) message("Setting up registry") reg = registry.Registry() @@ -427,12 +429,16 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, #reg.apply_patchfile(provision_reg) message("Setting up templates into %s" % paths.templates) - setup_ldb(setup_dir, "provision_templates.ldif", session_info, - credentials, subobj, lp, paths.templates) + templates_ldb = Ldb(paths.templates, session_info=session_info, + credentials=credentials, lp=lp) + templates_ldb.erase() + setup_ldb(templates_ldb, setup_dir, "provision_templates.ldif", subobj) message("Setting up sam.ldb partitions") - setup_ldb(setup_dir, "provision_partitions.ldif", session_info, - credentials, subobj, lp, paths.samdb) + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + samdb.erase() + setup_ldb(samdb, setup_dir, "provision_partitions.ldif", subobj) samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) @@ -453,7 +459,6 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, samdb.transaction_commit() message("Pre-loading the Samba 4 and AD schema") - samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(subobj.domainsid) diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index ce06efa3de..e3f001deb1 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -25,10 +25,14 @@ import misc import ldb class SamDB(samba.Ldb): - def __init__(self, *args, **kwargs): - super(SamDB, self).__init__(*args, **kwargs) + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + super(SamDB, self).__init__(session_info=session_info, credentials=credentials, + modules_dir=modules_dir, lp=lp) misc.dsdb_set_global_schema(self) misc.ldb_register_samba_handlers(self) + if url: + self.connect(url) def add_foreign(self, domaindn, sid, desc): """Add a foreign security principle.""" -- cgit From 1c29a63d443fde3fc0253f634822c12749f1afad Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 18 Dec 2007 17:21:13 +0100 Subject: r26523: Refactor provisioning code. (This used to be commit ac1083178f9e521dcd5d3d8b5199abcb00159adf) --- source4/scripting/python/samba/__init__.py | 8 +- source4/scripting/python/samba/provision.py | 396 +++++++++++++++++----------- source4/scripting/python/samba/samdb.py | 2 +- 3 files changed, 250 insertions(+), 156 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index fd294952b8..3981464681 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -77,7 +77,7 @@ class Ldb(ldb.Ldb): def msg(l,text): print text - self.set_debug(msg) + #self.set_debug(msg) if url is not None: self.connect(url) @@ -87,9 +87,9 @@ class Ldb(ldb.Ldb): set_session_info = misc.ldb_set_session_info set_loadparm = misc.ldb_set_loadparm - def searchone(self, basedn, expression, attribute): + def searchone(self, basedn, attribute, expression=None, scope=ldb.SCOPE_BASE): """Search for one attribute as a string.""" - res = self.search(basedn, SCOPE_SUBTREE, expression, [attribute]) + res = self.search(basedn, scope, expression, [attribute]) if len(res) != 1 or res[0][attribute] is None: return None return res[0][attribute] @@ -125,6 +125,8 @@ def substitute_var(text, values): """ for (name, value) in values.items(): + assert isinstance(name, str), "%r is not a string" % name + assert isinstance(value, str), "Value %r for %s is not a string" % (value, name) text = text.replace("${%s}" % name, value) assert "${" not in text, text diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 2c6e50219a..a8aeb8c831 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -39,7 +39,6 @@ class ProvisionSettings(object): self.machinepass = None self.adminpass = None self.defaultsite = "Default-First-Site-Name" - self.datestring = None self.root = None self.nobody = None self.nogroup = None @@ -49,52 +48,19 @@ class ProvisionSettings(object): self.dnsdomain = None self.dnsname = None self.domaindn = None - self.domaindn_ldb = None self.rootdn = None self.configdn = None - self.configdn_ldb = None self.schemedn = None self.schemedn_ldb = None self.s4_ldapi_path = None self.policyguid = None - self.extensibleobject = None + self.serverrole = None def subst_vars(self): - return {"SCHEMADN": self.schemadn, - "SCHEMADN_LDB": self.schemadn_ldb, - "SCHEMADN_MOD": "schema_fsmo", - "SCHEMADN_MOD2": ",objectguid", - "CONFIGDN": self.configdn, - "TDB_MODULES_LIST": ","+",".join(self.tdb_modules_list), - "MODULES_LIST2": ",".join(self.modules_list2), - "CONFIGDN_LDB": self.configdn_ldb, - "DOMAINDN": self.domaindn, - "DOMAINDN_LDB": self.domaindn_ldb, - "DOMAINDN_MOD": "pdc_fsmo,password_hash", - "DOMAINDN_MOD2": ",objectguid", - "DOMAINSID": str(self.domainsid), - "MODULES_LIST": ",".join(self.modules_list), - "CONFIGDN_MOD": "naming_fsmo", - "CONFIGDN_MOD2": ",objectguid", - "NETBIOSNAME": self.netbiosname, - "DNSNAME": self.dnsname, - "ROOTDN": self.rootdn, - "DOMAIN": self.domain, - "DNSDOMAIN": self.dnsdomain, - "REALM": self.realm, - "DEFAULTSITE": self.defaultsite, - "MACHINEPASS_B64": b64encode(self.machinepass), - "ADMINPASS_B64": b64encode(self.adminpass), - "DNSPASS_B64": b64encode(self.dnspass), - "KRBTGTPASS_B64": b64encode(self.krbtgtpass), - "S4_LDAPI_URI": "ldapi://%s" % self.s4_ldapi_path.replace("/", "%2F"), - "LDAPTIME": timestring(int(time.time())), - "POLICYGUID": self.policyguid, - "RDN_DC": self.rdn_dc, - "DOMAINGUID_MOD": self.domainguid_mod, - "VERSION": samba.version(), - "ACI": "# no aci for local ldb", - "EXTENSIBLEOBJECT": self.extensibleobject, + return { + "SERVERROLE": self.serverrole, + "DOMAIN_CONF": self.domain, + "REALM_CONF": self.realm, } def fix(self, paths): @@ -114,6 +80,7 @@ class ProvisionSettings(object): self.secrets_keytab = paths.keytab self.s4_ldapi_path = paths.s4_ldapi_path + self.serverrole = "domain controller" def validate(self, lp): if not valid_netbios_name(self.domain): @@ -207,61 +174,64 @@ def open_ldb(session_info, credentials, lp, dbname): lp=lp) -def setup_add_ldif(setup_dir, ldif, subobj, ldb): +def setup_add_ldif(ldb, setup_dir, ldif, subst_vars=None): """Setup a ldb in the private dir.""" assert isinstance(ldif, str) assert isinstance(setup_dir, str) src = os.path.join(setup_dir, ldif) data = open(src, 'r').read() - data = substitute_var(data, subobj.subst_vars()) + if subst_vars is not None: + data = substitute_var(data, subst_vars) for msg in ldb.parse_ldif(data): ldb.add(msg[1]) -def setup_modify_ldif(setup_dir, ldif, subobj, ldb): +def setup_modify_ldif(ldb, setup_dir, ldif, substvars=None): src = os.path.join(setup_dir, ldif) data = open(src, 'r').read() - data = substitute_var(data, subobj.subst_vars()) + if substvars is not None: + data = substitute_var(data, substvars) for (changetype, msg) in ldb.parse_ldif(data): ldb.modify(msg) -def setup_ldb(ldb, setup_dir, ldif, subobj): +def setup_ldb(ldb, setup_dir, ldif, subst_vars=None): assert ldb is not None ldb.transaction_start() try: - setup_add_ldif(setup_dir, ldif, subobj, ldb) + setup_add_ldif(ldb, setup_dir, ldif, subst_vars) except: ldb.transaction_cancel() raise ldb.transaction_commit() -def setup_ldb_modify(setup_dir, ldif, subobj, ldb): +def setup_ldb_modify(setup_dir, ldif, substvars, ldb): """Modify a ldb in the private dir.""" src = os.path.join(setup_dir, ldif) data = open(src, 'r').read() - data = substitute_var(data, subobj.subst_vars()) + data = substitute_var(data, substvars) assert not "${" in data for (changetype, msg) in ldb.parse_ldif(data): ldb.modify(msg) -def setup_file(setup_dir, template, message, fname, subobj): +def setup_file(setup_dir, template, fname, substvars): """Setup a file in the private dir.""" f = fname src = os.path.join(setup_dir, template) - os.unlink(f) + if os.path.exists(f): + os.unlink(f) data = open(src, 'r').read() - data = substitute_var(data, subobj.subst_vars()) + data = substitute_var(data, substvars) assert not "${" in data open(f, 'w').write(data) @@ -297,11 +267,7 @@ def provision_default_paths(lp, subobj): def setup_name_mappings(subobj, ldb): """setup reasonable name mappings for sam names to unix names.""" - res = ldb.search(Dn(ldb, subobj.domaindn), SCOPE_BASE, "objectSid=*", - ["objectSid"]) - assert len(res) == 1 - assert "objectSid" in res[0] - sid = str(list(res[0]["objectSid"])[0]) + sid = str(subobj.domainsid) # add some foreign sids if they are not present already ldb.add_foreign(subobj.domaindn, "S-1-5-7", "Anonymous") @@ -336,33 +302,35 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, subobj.fix(paths) message("Setting up templates into %s" % paths.templates) - templates_ldb = Ldb(paths.templates, session_info=session_info, - credentials=credentials, lp=lp) - templates_ldb.erase() - setup_ldb(templates_ldb, setup_dir, "provision_templates.ldif", subobj) + setup_templatesdb(paths.templates, setup_dir, session_info, + credentials, lp) # Also wipes the database - message("Setting up %s partitions" % paths.samdb) + message("Setting up samdb") + os.path.unlink(paths.samdb) samdb = SamDB(paths.samdb, credentials=credentials, session_info=session_info, lp=lp) samdb.erase() - setup_ldb(samdb, setup_dir, "provision_partitions.ldif", subobj) - samdb = SamDB(paths.samdb, session_info=session_info, - credentials=credentials, lp=lp) + message("Setting up %s partitions" % paths.samdb) + setup_samdb_partitions(samdb, setup_dir, subobj) + + samdb = SamDB(paths.samdb, credentials=credentials, + session_info=session_info, lp=lp) + ldb.transaction_start() try: message("Setting up %s attributes" % paths.samdb) - setup_add_ldif(setup_dir, "provision_init.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_init.ldif") message("Setting up %s rootDSE" % paths.samdb) - setup_add_ldif(setup_dir, "provision_rootdse_add.ldif", subobj, samdb) + setup_samdb_rootdse(samdb, setup_dir, subobj) message("Erasing data from partitions") ldb_erase_partitions(subobj, message, samdb, None) message("Setting up %s indexes" % paths.samdb) - setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_index.ldif") except: samdb.transaction_cancel() raise @@ -370,12 +338,70 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, samdb.transaction_commit() message("Setting up %s" % paths.secrets) - secrets_ldb = Ldb(paths.secrets, session_info=session_info, - credentials=credentials, lp=lp) - secrets_ldb.clear() - setup_ldb(secrets_ldb, setup_dir, "secrets_init.ldif", subobj) - setup_ldb(secrets_ldb, setup_dir, "secrets.ldif", subobj) - setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", subobj) + secrets_ldb = setup_secretsdb(paths.secrets, setup_dir, session_info, credentials, lp) + setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", + { "MACHINEPASS_B64": b64encode(self.machinepass) }) + + +def setup_secretsdb(path, setup_dir, session_info, credentials, lp): + secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp) + secrets_ldb.erase() + setup_ldb(secrets_ldb, setup_dir, "secrets_init.ldif") + setup_ldb(secrets_ldb, setup_dir, "secrets.ldif") + return secrets_ldb + + +def setup_templatesdb(path, setup_dir, session_info, credentials, lp): + templates_ldb = Ldb(path, session_info=session_info, + credentials=credentials, lp=lp) + templates_ldb.erase() + setup_ldb(templates_ldb, setup_dir, "provision_templates.ldif", None) + + +def setup_registry(path, setup_dir, session_info, credentials, lp): + reg = registry.Registry() + hive = registry.Hive(path, session_info=session_info, + credentials=credentials, lp_ctx=lp) + reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") + provision_reg = os.path.join(setup_dir, "provision.reg") + assert os.path.exists(provision_reg) + reg.apply_patchfile(provision_reg) + + +def setup_samdb_rootdse(samdb, setup_dir, subobj): + setup_add_ldif(samdb, setup_dir, "provision_rootdse_add.ldif", { + "SCHEMADN": subobj.schemadn, + "NETBIOSNAME": subobj.netbiosname, + "DNSDOMAIN": subobj.dnsdomain, + "DEFAULTSITE": subobj.defaultsite, + "REALM": subobj.realm, + "DNSNAME": subobj.dnsname, + "DOMAINDN": subobj.domaindn, + "ROOTDN": subobj.rootdn, + "CONFIGDN": subobj.configdn, + "VERSION": samba.version(), + }) + + +def setup_samdb_partitions(samdb, setup_dir, subobj): + setup_ldb(samdb, setup_dir, "provision_partitions.ldif", { + "SCHEMADN": subobj.schemadn, + "SCHEMADN_LDB": "schema.ldb", + "SCHEMADN_MOD2": ",objectguid", + "CONFIGDN": subobj.configdn, + "CONFIGDN_LDB": "configuration.ldb", + "DOMAINDN": subobj.domaindn, + "DOMAINDN_LDB": "users.ldb", + "SCHEMADN_MOD": "schema_fsmo", + "CONFIGDN_MOD": "naming_fsmo", + "CONFIGDN_MOD2": ",objectguid", + "DOMAINDN_MOD": "pdc_fsmo,password_hash", + "DOMAINDN_MOD2": ",objectguid", + "MODULES_LIST": ",".join(subobj.modules_list), + "TDB_MODULES_LIST": ","+",".join(subobj.tdb_modules_list), + "MODULES_LIST2": ",".join(subobj.modules_list2), + }) + def provision(lp, setup_dir, subobj, message, blank, paths, session_info, @@ -386,11 +412,6 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, """ subobj.fix(paths) - if subobj.domain_guid is not None: - subobj.domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % subobj.domain_guid - else: - subobj.domainguid_mod = "" - if subobj.host_guid is not None: subobj.hostguid_add = "objectGUID: %s" % subobj.host_guid else: @@ -401,8 +422,14 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, # only install a new smb.conf if there isn't one there already if not os.path.exists(paths.smbconf): message("Setting up smb.conf") - setup_file(setup_dir, "provision.smb.conf", message, paths.smbconf, - subobj) + if lp.get("server role") == "domain controller": + smbconfsuffix = "dc" + elif lp.get("server role") == "member": + smbconfsuffix = "member" + else: + assert "Invalid server role setting: %s" % lp.get("server role") + setup_file(setup_dir, "provision.smb.conf.%s" % smbconfsuffix, paths.smbconf, + None) lp.reload() # only install a new shares config db if there is none @@ -410,45 +437,37 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, message("Setting up share.ldb") share_ldb = Ldb(paths.shareconf, session_info=session_info, credentials=credentials, lp=lp) - setup_ldb(share_ldb, setup_dir, "share.ldif", subobj) + setup_ldb(share_ldb, setup_dir, "share.ldif", None) message("Setting up %s" % paths.secrets) - secrets_ldb = Ldb(paths.secrets, session_info=session_info, - credentials=credentials, lp=lp) - secrets_ldb.erase() - setup_ldb(secrets_ldb, setup_dir, "secrets_init.ldif", subobj) - setup_ldb(secrets_ldb, setup_dir, "secrets.ldif", subobj) + setup_secretsdb(paths.secrets, setup_dir, session_info=session_info, + credentials=credentials, lp=lp) message("Setting up registry") - reg = registry.Registry() - #hive = registry.Hive(paths.hklm, session_info=session_info, - # credentials=credentials, lp_ctx=lp) - #reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") - provision_reg = os.path.join(setup_dir, "provision.reg") - assert os.path.exists(provision_reg) - #reg.apply_patchfile(provision_reg) + #setup_registry(paths.hklm, setup_dir, session_info, + # credentials=credentials, lp=lp) message("Setting up templates into %s" % paths.templates) - templates_ldb = Ldb(paths.templates, session_info=session_info, - credentials=credentials, lp=lp) - templates_ldb.erase() - setup_ldb(templates_ldb, setup_dir, "provision_templates.ldif", subobj) + setup_templatesdb(paths.templates, setup_dir, session_info=session_info, + credentials=credentials, lp=lp) - message("Setting up sam.ldb partitions") samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) samdb.erase() - setup_ldb(samdb, setup_dir, "provision_partitions.ldif", subobj) + + message("Setting up sam.ldb partitions") + setup_samdb_partitions(samdb, setup_dir, subobj) samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) + samdb.transaction_start() try: message("Setting up sam.ldb attributes") - setup_add_ldif(setup_dir, "provision_init.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_init.ldif") message("Setting up sam.ldb rootDSE") - setup_add_ldif(setup_dir, "provision_rootdse_add.ldif", subobj, samdb) + setup_samdb_rootdse(samdb, setup_dir, subobj) message("Erasing data from partitions") ldb_erase_partitions(subobj, message, samdb, ldapbackend) @@ -462,53 +481,113 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(subobj.domainsid) - load_schema(setup_dir, subobj, samdb) + load_schema(setup_dir, samdb, subobj) samdb.transaction_start() try: message("Adding DomainDN: %s (permitted to fail)" % subobj.domaindn) - setup_add_ldif(setup_dir, "provision_basedn.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_basedn.ldif", { + "DOMAINDN": subobj.domaindn, + "ACI": "# no aci for local ldb", + "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", + "RDN_DC": subobj.rdn_dc, + }) + message("Modifying DomainDN: " + subobj.domaindn + "") - setup_ldb_modify(setup_dir, "provision_basedn_modify.ldif", subobj, samdb) + if subobj.domain_guid is not None: + domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % subobj.domain_guid + else: + domainguid_mod = "" + + setup_ldb_modify(setup_dir, "provision_basedn_modify.ldif", { + "RDN_DC": subobj.rdn_dc, + "LDAPTIME": timestring(int(time.time())), + "DOMAINSID": str(subobj.domainsid), + "SCHEMADN": subobj.schemadn, + "NETBIOSNAME": subobj.netbiosname, + "DEFAULTSITE": subobj.defaultsite, + "CONFIGDN": subobj.configdn, + "POLICYGUID": subobj.policyguid, + "DOMAINDN": subobj.domaindn, + "DOMAINGUID_MOD": domainguid_mod, + }, samdb) message("Adding configuration container (permitted to fail)") - setup_add_ldif(setup_dir, "provision_configuration_basedn.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_configuration_basedn.ldif", { + "CONFIGDN": subobj.configdn, + "ACI": "# no aci for local ldb", + "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", + }) message("Modifying configuration container") - setup_ldb_modify(setup_dir, "provision_configuration_basedn_modify.ldif", subobj, samdb) + setup_ldb_modify(setup_dir, "provision_configuration_basedn_modify.ldif", { + "CONFIGDN": subobj.configdn, + "SCHEMADN": subobj.schemadn, + }, samdb) message("Adding schema container (permitted to fail)") - setup_add_ldif(setup_dir, "provision_schema_basedn.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_schema_basedn.ldif", { + "SCHEMADN": subobj.schemadn, + "ACI": "# no aci for local ldb", + "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" + }) message("Modifying schema container") - setup_ldb_modify(setup_dir, "provision_schema_basedn_modify.ldif", subobj, samdb) + setup_ldb_modify(setup_dir, "provision_schema_basedn_modify.ldif", { + "SCHEMADN": subobj.schemadn, + "NETBIOSNAME": subobj.netbiosname, + "DEFAULTSITE": subobj.defaultsite, + "CONFIGDN": subobj.configdn, + }, samdb) + message("Setting up sam.ldb Samba4 schema") - setup_add_ldif(setup_dir, "schema_samba4.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "schema_samba4.ldif", { + "SCHEMADN": subobj.schemadn, + }) message("Setting up sam.ldb AD schema") - setup_add_ldif(setup_dir, "schema.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "schema.ldif", { + "SCHEMADN": subobj.schemadn, + }) message("Setting up sam.ldb configuration data") - setup_add_ldif(setup_dir, "provision_configuration.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_configuration.ldif", { + "CONFIGDN": subobj.configdn, + "NETBIOSNAME": subobj.netbiosname, + "DEFAULTSITE": subobj.defaultsite, + "DNSDOMAIN": subobj.dnsdomain, + "DOMAIN": subobj.domain, + "SCHEMADN": subobj.schemadn, + "DOMAINDN": subobj.domaindn, + }) message("Setting up display specifiers") - setup_add_ldif(setup_dir, "display_specifiers.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "display_specifiers.ldif", {"CONFIGDN": subobj.configdn}) message("Adding users container (permitted to fail)") - setup_add_ldif(setup_dir, "provision_users_add.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_users_add.ldif", { + "DOMAINDN": subobj.domaindn}) message("Modifying users container") - setup_ldb_modify(setup_dir, "provision_users_modify.ldif", subobj, samdb) + setup_ldb_modify(setup_dir, "provision_users_modify.ldif", { + "DOMAINDN": subobj.domaindn}, samdb) message("Adding computers container (permitted to fail)") - setup_add_ldif(setup_dir, "provision_computers_add.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_computers_add.ldif", { + "DOMAINDN": subobj.domaindn}) message("Modifying computers container") - setup_ldb_modify(setup_dir, "provision_computers_modify.ldif", subobj, samdb) + setup_ldb_modify(setup_dir, "provision_computers_modify.ldif", { + "DOMAINDN": subobj.domaindn}, samdb) message("Setting up sam.ldb data") - setup_add_ldif(setup_dir, "provision.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision.ldif", { + "DOMAINDN": subobj.domaindn, + "NETBIOSNAME": subobj.netbiosname, + "DEFAULTSITE": subobj.defaultsite, + "CONFIGDN": subobj.configdn, + }) if blank: message("Setting up sam.ldb index") - setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_index.ldif") message("Setting up sam.ldb rootDSE marking as syncronized") - setup_modify_ldif(setup_dir, "provision_rootdse_modify.ldif", subobj, samdb) + setup_modify_ldif(samdb, setup_dir, "provision_rootdse_modify.ldif") samdb.transaction_commit() return @@ -527,15 +606,21 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, # samdb = open_ldb(info, paths.samdb, False) # message("Setting up sam.ldb users and groups") - setup_add_ldif(setup_dir, "provision_users.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_users.ldif", { + "DOMAINDN": subobj.domaindn, + "DOMAINSID": str(subobj.domainsid), + "CONFIGDN": subobj.configdn, + "ADMINPASS_B64": b64encode(subobj.adminpass), + "KRBTGTPASS_B64": b64encode(subobj.krbtgtpass), + }) setup_name_mappings(subobj, samdb) message("Setting up sam.ldb index") - setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) + setup_add_ldif(samdb, setup_dir, "provision_index.ldif") message("Setting up sam.ldb rootDSE marking as syncronized") - setup_modify_ldif(setup_dir, "provision_rootdse_modify.ldif", subobj, samdb) + setup_modify_ldif(samdb, setup_dir, "provision_rootdse_modify.ldif") except: samdb.transaction_cancel() raise @@ -543,12 +628,17 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, samdb.transaction_commit() message("Setting up phpLDAPadmin configuration") - setup_file(setup_dir, "phpldapadmin-config.php", message, - paths.phpldapadminconfig, subobj) + create_phplpapdadmin_config(paths.phpldapadminconfig, setup_dir, subobj.s4_ldapi_path) + message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) -def provision_dns(setup_dir, subobj, message, paths, session_info, credentials): +def create_phplpapdadmin_config(path, setup_dir, s4_ldapi_path): + setup_file(setup_dir, "phpldapadmin-config.php", + path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")}) + + +def provision_dns(setup_dir, subobj, message, paths, session_info, credentials, lp): """Write out a DNS zone file, from the info in the current database.""" message("Setting up DNS zone: %s" % subobj.dnsdomain) # connect to the sam @@ -557,18 +647,22 @@ def provision_dns(setup_dir, subobj, message, paths, session_info, credentials): # These values may have changed, due to an incoming SamSync, # or may not have been specified, so fetch them from the database - - res = ldb.search(Dn(ldb, subobj.domaindn), SCOPE_BASE, "objectGUID=*", - ["objectGUID"]) - assert(len(res) == 1) - assert(res[0]["objectGUID"] is not None) - subobj.domainguid = res[0]["objectGUID"] - - subobj.host_guid = ldb.searchone(subobj.domaindn, - "(&(objectClass=computer)(cn=%s))" % subobj.netbiosname, "objectGUID") - assert subobj.host_guid is not None - - setup_file(setup_dir, "provision.zone", message, paths.dns, subobj) + domainguid = str(ldb.searchone(Dn(ldb, subobj.domaindn), "objectGUID")) + + hostguid = str(ldb.searchone(Dn(ldb, subobj.domaindn), "objectGUID" , + expression="(&(objectClass=computer)(cn=%s))" % subobj.netbiosname)) + + setup_file(setup_dir, "provision.zone", paths.dns, { + "DNSPASS_B64": b64encode(subobj.dnspass), + "HOSTNAME": hostname(), + "DNSDOMAIN": subobj.dnsdomain, + "REALM": subobj.realm, + "HOSTIP": hostip(), + "DOMAINGUID": domainguid, + "DATESTRING": time.strftime("%Y%m%d%H"), + "DEFAULTSITE": subobj.defaultsite, + "HOSTGUID": hostguid, + }) message("Please install the zone located in %s into your DNS server" % paths.dns) @@ -577,21 +671,21 @@ def provision_ldapbase(setup_dir, subobj, message, paths): """Write out a DNS zone file, from the info in the current database.""" message("Setting up LDAP base entry: %s" % subobj.domaindn) rdns = subobj.domaindn.split(",") - subobj.extensibleobject = "objectClass: extensibleObject" subobj.rdn_dc = rdns[0][len("DC="):] setup_file(setup_dir, "provision_basedn.ldif", - message, paths.ldap_basedn_ldif, - subobj) + paths.ldap_basedn_ldif, + None) setup_file(setup_dir, "provision_configuration_basedn.ldif", - message, paths.ldap_config_basedn_ldif, - subobj) + paths.ldap_config_basedn_ldif, None) setup_file(setup_dir, "provision_schema_basedn.ldif", - message, paths.ldap_schema_basedn_ldif, - subobj) + paths.ldap_schema_basedn_ldif, { + "SCHEMADN": subobj.schemadn, + "ACI": "# no aci for local ldb", + "EXTENSIBLEOBJECT": "objectClass: extensibleObject"}) message("Please install the LDIF located in " + paths.ldap_basedn_ldif + ", " + paths.ldap_config_basedn_ldif + " and " + paths.ldap_schema_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server") @@ -614,7 +708,6 @@ def provision_guess(lp): subobj.machinepass = misc.random_password(12) subobj.adminpass = misc.random_password(12) subobj.dnspass = misc.random_password(12) - subobj.datestring = time.strftime("%Y%m%d%H") subobj.root = findnss(pwd.getpwnam, "root")[4] subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] @@ -625,12 +718,9 @@ def provision_guess(lp): subobj.dnsdomain = subobj.realm.lower() subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) subobj.domaindn = "DC=" + subobj.dnsdomain.replace(".", ",DC=") - subobj.domaindn_ldb = "users.ldb" subobj.rootdn = subobj.domaindn subobj.configdn = "CN=Configuration," + subobj.rootdn - subobj.configdn_ldb = "configuration.ldb" subobj.schemadn = "CN=Schema," + subobj.configdn - subobj.schemadn_ldb = "schema.ldb" #Add modules to the list to activate them by default #beware often order is important @@ -661,21 +751,23 @@ def provision_guess(lp): subobj.modules_list2 = ["show_deleted", "partition"] - subobj.extensibleobject = "# no objectClass: extensibleObject for local ldb" - subobj.aci = "# no aci for local ldb" return subobj -def load_schema(setup_dir, subobj, samdb): +def load_schema(setup_dir, samdb, subobj): """Load schema.""" src = os.path.join(setup_dir, "schema.ldif") schema_data = open(src, 'r').read() src = os.path.join(setup_dir, "schema_samba4.ldif") schema_data += open(src, 'r').read() - schema_data = substitute_var(schema_data, subobj.subst_vars()) + schema_data = substitute_var(schema_data, {"SCHEMADN": subobj.schemadn}) src = os.path.join(setup_dir, "provision_schema_basedn_modify.ldif") head_data = open(src, 'r').read() - head_data = substitute_var(head_data, subobj.subst_vars()) + head_data = substitute_var(head_data, { + "SCHEMADN": subobj.schemadn, + "NETBIOSNAME": subobj.netbiosname, + "CONFIGDN": subobj.configdn, + "DEFAULTSITE": subobj.defaultsite}) samdb.attach_schema_from_ldif(head_data, schema_data) diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index e3f001deb1..7061e22ce4 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -89,7 +89,7 @@ userAccountControl: %u assert(len(res) == 1 and res[0].defaultNamingContext is not None) domain_dn = res[0].defaultNamingContext assert(domain_dn is not None) - dom_users = searchone(self, domain_dn, "name=Domain Users", "dn") + dom_users = self.searchone(domain_dn, "dn", "name=Domain Users") assert(dom_users is not None) user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) -- cgit From 4bfbd78086a342e4075596a6a9e5de0cec0b47ac Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 18 Dec 2007 17:21:20 +0100 Subject: r26524: Import self join. (This used to be commit daae983c260da6af6a4f1cba1290bc7240d7a970) --- source4/scripting/python/samba/provision.py | 117 ++++++++++++++++++---------- 1 file changed, 75 insertions(+), 42 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index a8aeb8c831..c17b74345a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -54,14 +54,6 @@ class ProvisionSettings(object): self.schemedn_ldb = None self.s4_ldapi_path = None self.policyguid = None - self.serverrole = None - - def subst_vars(self): - return { - "SERVERROLE": self.serverrole, - "DOMAIN_CONF": self.domain, - "REALM_CONF": self.realm, - } def fix(self, paths): self.realm = self.realm.upper() @@ -75,13 +67,6 @@ class ProvisionSettings(object): rdns = self.domaindn.split(",") self.rdn_dc = rdns[0][len("DC="):] - self.sam_ldb = paths.samdb - self.secrets_ldb = paths.secrets - self.secrets_keytab = paths.keytab - - self.s4_ldapi_path = paths.s4_ldapi_path - self.serverrole = "domain controller" - def validate(self, lp): if not valid_netbios_name(self.domain): raise InvalidNetbiosName(self.domain) @@ -111,12 +96,12 @@ class ProvisionPaths: self.samdb = None self.secrets = None self.keytab = None + self.dns_keytab = None self.dns = None self.winsdb = None self.ldap_basedn_ldif = None self.ldap_config_basedn_ldif = None self.ldap_schema_basedn_ldif = None - self.s4_ldapi_path = None def install_ok(lp, session_info, credentials): @@ -184,6 +169,8 @@ def setup_add_ldif(ldb, setup_dir, ldif, subst_vars=None): if subst_vars is not None: data = substitute_var(data, subst_vars) + assert "${" not in data + for msg in ldb.parse_ldif(data): ldb.add(msg[1]) @@ -195,6 +182,8 @@ def setup_modify_ldif(ldb, setup_dir, ldif, substvars=None): if substvars is not None: data = substitute_var(data, substvars) + assert "${" not in data + for (changetype, msg) in ldb.parse_ldif(data): ldb.modify(msg) @@ -231,7 +220,8 @@ def setup_file(setup_dir, template, fname, substvars): os.unlink(f) data = open(src, 'r').read() - data = substitute_var(data, substvars) + if substvars: + data = substitute_var(data, substvars) assert not "${" in data open(f, 'w').write(data) @@ -250,6 +240,7 @@ def provision_default_paths(lp, subobj): paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") paths.keytab = os.path.join(private_dir, "secrets.keytab") + paths.dns_keytab = os.path.join(private_dir, "dns.keytab") paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone") paths.winsdb = os.path.join(private_dir, "wins.ldb") paths.ldap_basedn_ldif = os.path.join(private_dir, @@ -262,6 +253,14 @@ def provision_default_paths(lp, subobj): paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php") paths.hklm = os.path.join(private_dir, "hklm.ldb") + paths.sysvol = lp.get("sysvol", "path") + if paths.sysvol is None: + paths.sysvol = os.path.join(lp.get("lock dir"), "sysvol") + + paths.netlogon = lp.get("netlogon", "path") + if paths.netlogon is None: + paths.netlogon = os.path.join(os.path.join(paths.sysvol, "scripts")) + return paths @@ -412,11 +411,6 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, """ subobj.fix(paths) - if subobj.host_guid is not None: - subobj.hostguid_add = "objectGUID: %s" % subobj.host_guid - else: - subobj.hostguid_add = "" - assert paths.smbconf is not None # only install a new smb.conf if there isn't one there already @@ -440,10 +434,11 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, setup_ldb(share_ldb, setup_dir, "share.ldif", None) message("Setting up %s" % paths.secrets) - setup_secretsdb(paths.secrets, setup_dir, session_info=session_info, + secrets_ldb = setup_secretsdb(paths.secrets, setup_dir, session_info=session_info, credentials=credentials, lp=lp) message("Setting up registry") + # FIXME: Still fails for some reason #setup_registry(paths.hklm, setup_dir, session_info, # credentials=credentials, lp=lp) @@ -582,15 +577,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, "CONFIGDN": subobj.configdn, }) - if blank: - message("Setting up sam.ldb index") - setup_add_ldif(samdb, setup_dir, "provision_index.ldif") - - message("Setting up sam.ldb rootDSE marking as syncronized") - setup_modify_ldif(samdb, setup_dir, "provision_rootdse_modify.ldif") - - samdb.transaction_commit() - return + if not blank: # message("Activate schema module") # setup_modify_ldif("schema_activation.ldif", info, samdb, False) @@ -605,16 +592,62 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, # # samdb = open_ldb(info, paths.samdb, False) # - message("Setting up sam.ldb users and groups") - setup_add_ldif(samdb, setup_dir, "provision_users.ldif", { - "DOMAINDN": subobj.domaindn, - "DOMAINSID": str(subobj.domainsid), - "CONFIGDN": subobj.configdn, - "ADMINPASS_B64": b64encode(subobj.adminpass), - "KRBTGTPASS_B64": b64encode(subobj.krbtgtpass), - }) + message("Setting up sam.ldb users and groups") + setup_add_ldif(samdb, setup_dir, "provision_users.ldif", { + "DOMAINDN": subobj.domaindn, + "DOMAINSID": str(subobj.domainsid), + "CONFIGDN": subobj.configdn, + "ADMINPASS_B64": b64encode(subobj.adminpass), + "KRBTGTPASS_B64": b64encode(subobj.krbtgtpass), + }) + + if lp.get("server role") == "domain controller": + message("Setting up self join") + if subobj.host_guid is not None: + hostguid_add = "objectGUID: %s" % subobj.host_guid + else: + hostguid_add = "" + + setup_add_ldif(samdb, setup_dir, "provision_self_join.ldif", { + "CONFIGDN": subobj.configdn, + "SCHEMADN": subobj.schemadn, + "DOMAINDN": subobj.domaindn, + "INVOCATIONID": subobj.invocationid, + "NETBIOSNAME": subobj.netbiosname, + "DEFAULTSITE": subobj.defaultsite, + "DNSNAME": subobj.dnsname, + "MACHINEPASS_B64": b64encode(subobj.machinepass), + "DNSPASS_B64": b64encode(subobj.dnspass), + "REALM": subobj.realm, + "DOMAIN": subobj.domain, + "HOSTGUID_ADD": hostguid_add, + "DNSDOMAIN": subobj.dnsdomain}) + setup_add_ldif(samdb, setup_dir, "provision_group_policy.ldif", { + "POLICYGUID": subobj.policyguid, + "DNSDOMAIN": subobj.dnsdomain, + "DOMAINSID": str(subobj.domainsid), + "DOMAINDN": subobj.domaindn}) + + os.makedirs(os.path.join(paths.sysvol, subobj.dnsdomain, "Policies", "{" + subobj.policyguid + "}"), 0755) + os.makedirs(os.path.join(paths.sysvol, subobj.dnsdomain, "Policies", "{" + subobj.policyguid + "}", "Machine"), 0755) + os.makedirs(os.path.join(paths.sysvol, subobj.dnsdomain, "Policies", "{" + subobj.policyguid + "}", "User"), 0755) + if not os.path.isdir(paths.netlogon): + os.makedirs(paths.netlogon, 0755) + setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", { + "MACHINEPASS_B64": b64encode(subobj.machinepass), + "DOMAIN": subobj.domain, + "REALM": subobj.realm, + "LDAPTIME": timestring(int(time.time())), + "DNSDOMAIN": subobj.dnsdomain, + "DOMAINSID": str(subobj.domainsid), + "SECRETS_KEYTAB": paths.keytab, + "NETBIOSNAME": subobj.netbiosname, + "SAM_LDB": paths.samdb, + "DNS_KEYTAB": paths.dns_keytab, + "DNSPASS_B64": b64encode(subobj.dnspass), + }) - setup_name_mappings(subobj, samdb) + setup_name_mappings(subobj, samdb) message("Setting up sam.ldb index") setup_add_ldif(samdb, setup_dir, "provision_index.ldif") @@ -628,7 +661,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, samdb.transaction_commit() message("Setting up phpLDAPadmin configuration") - create_phplpapdadmin_config(paths.phpldapadminconfig, setup_dir, subobj.s4_ldapi_path) + create_phplpapdadmin_config(paths.phpldapadminconfig, setup_dir, paths.s4_ldapi_path) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) -- cgit From 44946cefb3c016a45f1d167db765b705e96ed70c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 18 Dec 2007 17:21:24 +0100 Subject: r26525: Consistency in the API. (This used to be commit 37577fee582e7c9896b5cf8b62016d480b8f147e) --- source4/scripting/python/samba/provision.py | 103 ++++++++++++++-------------- 1 file changed, 53 insertions(+), 50 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index c17b74345a..ebc8288351 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -199,12 +199,13 @@ def setup_ldb(ldb, setup_dir, ldif, subst_vars=None): ldb.transaction_commit() -def setup_ldb_modify(setup_dir, ldif, substvars, ldb): +def setup_ldb_modify(ldb, setup_dir, ldif, substvars=None): """Modify a ldb in the private dir.""" src = os.path.join(setup_dir, ldif) data = open(src, 'r').read() - data = substitute_var(data, substvars) + if substvars is not None: + data = substitute_var(data, substvars) assert not "${" in data for (changetype, msg) in ldb.parse_ldif(data): @@ -312,7 +313,8 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, samdb.erase() message("Setting up %s partitions" % paths.samdb) - setup_samdb_partitions(samdb, setup_dir, subobj) + setup_samdb_partitions(samdb, setup_dir, subobj.schemadn, + subobj.configdn, subobj.domaindn) samdb = SamDB(paths.samdb, credentials=credentials, session_info=session_info, lp=lp) @@ -382,23 +384,52 @@ def setup_samdb_rootdse(samdb, setup_dir, subobj): }) -def setup_samdb_partitions(samdb, setup_dir, subobj): +def setup_samdb_partitions(samdb, setup_dir, schemadn, configdn, domaindn): + #Add modules to the list to activate them by default + #beware often order is important + # + # Some Known ordering constraints: + # - rootdse must be first, as it makes redirects from "" -> cn=rootdse + # - objectclass must be before password_hash, because password_hash checks + # that the objectclass is of type person (filled in by objectclass + # module when expanding the objectclass list) + # - partition must be last + # - each partition has its own module list then + modules_list = ["rootdse", + "paged_results", + "ranged_results", + "anr", + "server_sort", + "extended_dn", + "asq", + "samldb", + "rdn_name", + "objectclass", + "kludge_acl", + "operational"] + tdb_modules_list = [ + "subtree_rename", + "subtree_delete", + "linked_attributes"] + modules_list2 = ["show_deleted", + "partition"] + setup_ldb(samdb, setup_dir, "provision_partitions.ldif", { - "SCHEMADN": subobj.schemadn, + "SCHEMADN": schemadn, "SCHEMADN_LDB": "schema.ldb", "SCHEMADN_MOD2": ",objectguid", - "CONFIGDN": subobj.configdn, + "CONFIGDN": configdn, "CONFIGDN_LDB": "configuration.ldb", - "DOMAINDN": subobj.domaindn, + "DOMAINDN": domaindn, "DOMAINDN_LDB": "users.ldb", "SCHEMADN_MOD": "schema_fsmo", "CONFIGDN_MOD": "naming_fsmo", "CONFIGDN_MOD2": ",objectguid", "DOMAINDN_MOD": "pdc_fsmo,password_hash", "DOMAINDN_MOD2": ",objectguid", - "MODULES_LIST": ",".join(subobj.modules_list), - "TDB_MODULES_LIST": ","+",".join(subobj.tdb_modules_list), - "MODULES_LIST2": ",".join(subobj.modules_list2), + "MODULES_LIST": ",".join(modules_list), + "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), + "MODULES_LIST2": ",".join(modules_list2), }) @@ -451,7 +482,8 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, samdb.erase() message("Setting up sam.ldb partitions") - setup_samdb_partitions(samdb, setup_dir, subobj) + setup_samdb_partitions(samdb, setup_dir, subobj.schemadn, + subobj.configdn, subobj.domaindn) samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) @@ -495,7 +527,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, else: domainguid_mod = "" - setup_ldb_modify(setup_dir, "provision_basedn_modify.ldif", { + setup_ldb_modify(samdb, setup_dir, "provision_basedn_modify.ldif", { "RDN_DC": subobj.rdn_dc, "LDAPTIME": timestring(int(time.time())), "DOMAINSID": str(subobj.domainsid), @@ -506,7 +538,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, "POLICYGUID": subobj.policyguid, "DOMAINDN": subobj.domaindn, "DOMAINGUID_MOD": domainguid_mod, - }, samdb) + }) message("Adding configuration container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_configuration_basedn.ldif", { @@ -515,10 +547,10 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", }) message("Modifying configuration container") - setup_ldb_modify(setup_dir, "provision_configuration_basedn_modify.ldif", { + setup_ldb_modify(samdb, setup_dir, "provision_configuration_basedn_modify.ldif", { "CONFIGDN": subobj.configdn, "SCHEMADN": subobj.schemadn, - }, samdb) + }) message("Adding schema container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_schema_basedn.ldif", { @@ -527,12 +559,12 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") - setup_ldb_modify(setup_dir, "provision_schema_basedn_modify.ldif", { + setup_ldb_modify(samdb, setup_dir, "provision_schema_basedn_modify.ldif", { "SCHEMADN": subobj.schemadn, "NETBIOSNAME": subobj.netbiosname, "DEFAULTSITE": subobj.defaultsite, "CONFIGDN": subobj.configdn, - }, samdb) + }) message("Setting up sam.ldb Samba4 schema") setup_add_ldif(samdb, setup_dir, "schema_samba4.ldif", { @@ -561,14 +593,14 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, setup_add_ldif(samdb, setup_dir, "provision_users_add.ldif", { "DOMAINDN": subobj.domaindn}) message("Modifying users container") - setup_ldb_modify(setup_dir, "provision_users_modify.ldif", { - "DOMAINDN": subobj.domaindn}, samdb) + setup_ldb_modify(samdb, setup_dir, "provision_users_modify.ldif", { + "DOMAINDN": subobj.domaindn}) message("Adding computers container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_computers_add.ldif", { "DOMAINDN": subobj.domaindn}) message("Modifying computers container") - setup_ldb_modify(setup_dir, "provision_computers_modify.ldif", { - "DOMAINDN": subobj.domaindn}, samdb) + setup_ldb_modify(samdb, setup_dir, "provision_computers_modify.ldif", { + "DOMAINDN": subobj.domaindn}) message("Setting up sam.ldb data") setup_add_ldif(samdb, setup_dir, "provision.ldif", { "DOMAINDN": subobj.domaindn, @@ -755,35 +787,6 @@ def provision_guess(lp): subobj.configdn = "CN=Configuration," + subobj.rootdn subobj.schemadn = "CN=Schema," + subobj.configdn - #Add modules to the list to activate them by default - #beware often order is important - # - # Some Known ordering constraints: - # - rootdse must be first, as it makes redirects from "" -> cn=rootdse - # - objectclass must be before password_hash, because password_hash checks - # that the objectclass is of type person (filled in by objectclass - # module when expanding the objectclass list) - # - partition must be last - # - each partition has its own module list then - subobj.modules_list = ["rootdse", - "paged_results", - "ranged_results", - "anr", - "server_sort", - "extended_dn", - "asq", - "samldb", - "rdn_name", - "objectclass", - "kludge_acl", - "operational"] - subobj.tdb_modules_list = [ - "subtree_rename", - "subtree_delete", - "linked_attributes"] - subobj.modules_list2 = ["show_deleted", - "partition"] - return subobj -- cgit From 4e6ab64762477c0117aa823fd8e6b1275d63e0d7 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 18 Dec 2007 18:54:19 +0100 Subject: r26527: Start on tests for provision. (This used to be commit 84ac6c6bbfc4baaf28906ee5826a9cf888043656) --- source4/scripting/python/samba/__init__.py | 2 - source4/scripting/python/samba/provision.py | 60 ++++++++--------------- source4/scripting/python/samba/tests/__init__.py | 17 +++++++ source4/scripting/python/samba/tests/provision.py | 59 ++++++++++++++++++++++ 4 files changed, 96 insertions(+), 42 deletions(-) create mode 100644 source4/scripting/python/samba/tests/provision.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 3981464681..9ac283e660 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -129,8 +129,6 @@ def substitute_var(text, values): assert isinstance(value, str), "Value %r for %s is not a string" % (value, name) text = text.replace("${%s}" % name, value) - assert "${" not in text, text - return text diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ebc8288351..04f50e8359 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -135,18 +135,6 @@ def hostname(): return gethostname().split(".")[0] -def ldb_delete(ldb): - """Delete a LDB file. - - This may be necessary if the ldb is in bad shape, possibly due to being - built from an incompatible previous version of the code, so delete it - completely. - """ - print "Deleting %s\n" % ldb.filename - os.unlink(ldb.filename) - ldb.connect(ldb.filename) - - def open_ldb(session_info, credentials, lp, dbname): assert session_info is not None try: @@ -176,6 +164,13 @@ def setup_add_ldif(ldb, setup_dir, ldif, subst_vars=None): def setup_modify_ldif(ldb, setup_dir, ldif, substvars=None): + """Modify a ldb in the private dir. + + :param ldb: LDB object. + :param setup_dir: Setup directory. + :param ldif: LDIF file path. + :param substvars: Optional dictionary with substitution variables. + """ src = os.path.join(setup_dir, ldif) data = open(src, 'r').read() @@ -199,19 +194,6 @@ def setup_ldb(ldb, setup_dir, ldif, subst_vars=None): ldb.transaction_commit() -def setup_ldb_modify(ldb, setup_dir, ldif, substvars=None): - """Modify a ldb in the private dir.""" - src = os.path.join(setup_dir, ldif) - - data = open(src, 'r').read() - if substvars is not None: - data = substitute_var(data, substvars) - assert not "${" in data - - for (changetype, msg) in ldb.parse_ldif(data): - ldb.modify(msg) - - def setup_file(setup_dir, template, fname, substvars): """Setup a file in the private dir.""" f = fname @@ -328,7 +310,7 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, setup_samdb_rootdse(samdb, setup_dir, subobj) message("Erasing data from partitions") - ldb_erase_partitions(subobj, message, samdb, None) + ldb_erase_partitions(subobj.domaindn, message, samdb, None) message("Setting up %s indexes" % paths.samdb) setup_add_ldif(samdb, setup_dir, "provision_index.ldif") @@ -453,8 +435,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, smbconfsuffix = "member" else: assert "Invalid server role setting: %s" % lp.get("server role") - setup_file(setup_dir, "provision.smb.conf.%s" % smbconfsuffix, paths.smbconf, - None) + setup_file(setup_dir, "provision.smb.conf.%s" % smbconfsuffix, paths.smbconf) lp.reload() # only install a new shares config db if there is none @@ -462,7 +443,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, message("Setting up share.ldb") share_ldb = Ldb(paths.shareconf, session_info=session_info, credentials=credentials, lp=lp) - setup_ldb(share_ldb, setup_dir, "share.ldif", None) + setup_ldb(share_ldb, setup_dir, "share.ldif") message("Setting up %s" % paths.secrets) secrets_ldb = setup_secretsdb(paths.secrets, setup_dir, session_info=session_info, @@ -497,7 +478,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, setup_samdb_rootdse(samdb, setup_dir, subobj) message("Erasing data from partitions") - ldb_erase_partitions(subobj, message, samdb, ldapbackend) + ldb_erase_partitions(subobj.domaindn, message, samdb, ldapbackend) except: samdb.transaction_cancel() raise @@ -527,7 +508,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, else: domainguid_mod = "" - setup_ldb_modify(samdb, setup_dir, "provision_basedn_modify.ldif", { + setup_modify_ldif(samdb, setup_dir, "provision_basedn_modify.ldif", { "RDN_DC": subobj.rdn_dc, "LDAPTIME": timestring(int(time.time())), "DOMAINSID": str(subobj.domainsid), @@ -547,7 +528,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", }) message("Modifying configuration container") - setup_ldb_modify(samdb, setup_dir, "provision_configuration_basedn_modify.ldif", { + setup_modify_ldif(samdb, setup_dir, "provision_configuration_basedn_modify.ldif", { "CONFIGDN": subobj.configdn, "SCHEMADN": subobj.schemadn, }) @@ -559,7 +540,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") - setup_ldb_modify(samdb, setup_dir, "provision_schema_basedn_modify.ldif", { + setup_modify_ldif(samdb, setup_dir, "provision_schema_basedn_modify.ldif", { "SCHEMADN": subobj.schemadn, "NETBIOSNAME": subobj.netbiosname, "DEFAULTSITE": subobj.defaultsite, @@ -593,13 +574,13 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, setup_add_ldif(samdb, setup_dir, "provision_users_add.ldif", { "DOMAINDN": subobj.domaindn}) message("Modifying users container") - setup_ldb_modify(samdb, setup_dir, "provision_users_modify.ldif", { + setup_modify_ldif(samdb, setup_dir, "provision_users_modify.ldif", { "DOMAINDN": subobj.domaindn}) message("Adding computers container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_computers_add.ldif", { "DOMAINDN": subobj.domaindn}) message("Modifying computers container") - setup_ldb_modify(samdb, setup_dir, "provision_computers_modify.ldif", { + setup_modify_ldif(samdb, setup_dir, "provision_computers_modify.ldif", { "DOMAINDN": subobj.domaindn}) message("Setting up sam.ldb data") setup_add_ldif(samdb, setup_dir, "provision.ldif", { @@ -807,7 +788,7 @@ def load_schema(setup_dir, samdb, subobj): samdb.attach_schema_from_ldif(head_data, schema_data) -def join_domain(domain, netbios_name, join_type, creds, message): +def join_domain(domain, netbios_name, join_type, creds): ctx = NetContext(creds) joindom = object() joindom.domain = domain @@ -824,8 +805,7 @@ def vampire(domain, session_info, credentials, message): access to our local database (might be remote ldap) """ ctx = NetContext(credentials) - vampire_ctx = object() - machine_creds = credentials_init() + machine_creds = Credentials() machine_creds.set_domain(form.domain) if not machine_creds.set_machine_account(): raise Exception("Failed to access domain join information!") @@ -835,7 +815,7 @@ def vampire(domain, session_info, credentials, message): raise Exception("Migration of remote domain to Samba failed: %s " % vampire_ctx.error_string) -def ldb_erase_partitions(subobj, message, ldb, ldapbackend): +def ldb_erase_partitions(domaindn, message, ldb, ldapbackend): """Erase an ldb, removing all records.""" assert ldb is not None res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)", @@ -848,7 +828,7 @@ def ldb_erase_partitions(subobj, message, ldb, ldapbackend): previous_remaining = 1 current_remaining = 0 - if ldapbackend and (basedn == subobj.domaindn): + if ldapbackend and (basedn == domaindn): # Only delete objects that were created by provision anything = "(objectcategory=*)" diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index d3930e217a..0808469907 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -35,3 +35,20 @@ class LdbTestCase(unittest.TestCase): self.ldb = samba.Ldb(self.filename) +class SubstituteVarTestCase(unittest.TestCase): + def test_empty(self): + self.assertEquals("", samba.substitute_var("", {})) + + def test_nothing(self): + self.assertEquals("foo bar", samba.substitute_var("foo bar", {"bar": "bla"})) + + def test_replace(self): + self.assertEquals("foo bla", samba.substitute_var("foo ${bar}", {"bar": "bla"})) + + def test_broken(self): + self.assertEquals("foo ${bdkjfhsdkfh sdkfh ", + samba.substitute_var("foo ${bdkjfhsdkfh sdkfh ", {"bar": "bla"})) + + def test_unknown_var(self): + self.assertEquals("foo ${bla} gsff", + samba.substitute_var("foo ${bla} gsff", {"bar": "bla"})) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py new file mode 100644 index 0000000000..5edfe79084 --- /dev/null +++ b/source4/scripting/python/samba/tests/provision.py @@ -0,0 +1,59 @@ +#!/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 . +# + +import unittest +import samba.provision + +class ProvisionTestCase(unittest.TestCase): + def test_setup_secretsdb(self): + raise NotImplementedError(self.test_setup_secretsdb) + + def test_setup_templatesdb(self): + raise NotImplementedError(self.test_setup_templatesdb) + + def test_setup_registry(self): + raise NotImplementedError(self.test_setup_registry) + + def test_setup_samdb_rootdse(self): + raise NotImplementedError(self.test_setup_samdb_rootdse) + + def test_setup_samdb_partitions(self): + raise NotImplementedError(self.test_setup_samdb_partitions) + + def test_create_phpldapadmin_config(self): + raise NotImplementedError(self.test_create_phpldapadmin_config) + + def test_provision_dns(self): + raise NotImplementedError(self.test_provision_dns) + + def test_provision_ldapbase(self): + raise NotImplementedError(self.test_provision_ldapbase) + + def test_provision_guess(self): + raise NotImplementedError(self.test_provision_guess) + + def test_join_domain(self): + raise NotImplementedError(self.test_join_domain) + + def test_vampire(self): + raise NotImplementedError(self.test_vampire) + + def test_erase_partitions(self): + raise NotImplementedError(self.test_erase_partitions) + -- cgit From 595ec370da471116b35464dc65d2962f28380d74 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 19 Dec 2007 23:27:24 +0100 Subject: r26535: Get rid of all-knowing ProvisionSettings object. (This used to be commit 40bf88c8a70e8379a6081cb6050034bcd7ae56eb) --- source4/scripting/python/samba/provision.py | 522 ++++++++++++++-------------- 1 file changed, 258 insertions(+), 264 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 04f50e8359..c9cb457b4a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1,8 +1,10 @@ # # backend code for provisioning a Samba4 server -# Copyright Andrew Tridgell 2005 -# Copyright Jelmer Vernooij 2007 # Released under the GNU GPL v2 or later +# Copyright Jelmer Vernooij 2007 +# +# Based on the original in EJS: +# Copyright Andrew Tridgell 2005 # from base64 import b64encode @@ -22,67 +24,13 @@ from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring +DEFAULTSITE = "Default-First-Site-Name" + class InvalidNetbiosName(Exception): def __init__(self, name): super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name) -class ProvisionSettings(object): - def __init__(self, realm=None, domain=None, hostname=None, hostip=None): - self.realm = realm - self.domain = domain - self.hostname = hostname - self.hostip = hostip - self.domainsid = None - self.invocationid = None - self.krbtgtpass = None - self.machinepass = None - self.adminpass = None - self.defaultsite = "Default-First-Site-Name" - self.root = None - self.nobody = None - self.nogroup = None - self.wheel = None - self.backup = None - self.users = None - self.dnsdomain = None - self.dnsname = None - self.domaindn = None - self.rootdn = None - self.configdn = None - self.schemedn = None - self.schemedn_ldb = None - self.s4_ldapi_path = None - self.policyguid = None - - def fix(self, paths): - self.realm = self.realm.upper() - self.hostname = self.hostname.lower() - self.domain = self.domain.upper() - if not valid_netbios_name(self.domain): - raise InvalidNetbiosName(self.domain) - self.netbiosname = self.hostname.upper() - if not valid_netbios_name(self.netbiosname): - raise InvalidNetbiosName(self.netbiosname) - rdns = self.domaindn.split(",") - self.rdn_dc = rdns[0][len("DC="):] - - def validate(self, lp): - if not valid_netbios_name(self.domain): - raise InvalidNetbiosName(self.domain) - - if not valid_netbios_name(self.netbiosname): - raise InvalidNetbiosName(self.netbiosname) - - if lp.get("workgroup").upper() != self.domain.upper(): - raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", - lp.get("workgroup"), self.domain) - - if lp.get("realm").upper() != self.realm.upper(): - raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % - (lp.get("realm"), self.realm)) - - class ProvisionPaths: def __init__(self): self.smbconf = None @@ -125,11 +73,6 @@ def findnss(nssfn, *names): raise Exception("Unable to find user/group for %s" % arguments[1]) -def hostip(): - """return first host IP.""" - return gethostbyname(hostname()) - - def hostname(): """return first part of hostname.""" return gethostname().split(".")[0] @@ -210,11 +153,11 @@ def setup_file(setup_dir, template, fname, substvars): open(f, 'w').write(data) -def provision_default_paths(lp, subobj): +def provision_default_paths(lp, dnsdomain): """Set the default paths for provisioning. :param lp: Loadparm context. - :param subobj: Object + :param dnsdomain: DNS Domain name """ paths = ProvisionPaths() private_dir = lp.get("private dir") @@ -224,14 +167,14 @@ def provision_default_paths(lp, subobj): paths.templates = os.path.join(private_dir, "templates.ldb") paths.keytab = os.path.join(private_dir, "secrets.keytab") paths.dns_keytab = os.path.join(private_dir, "dns.keytab") - paths.dns = os.path.join(private_dir, subobj.dnsdomain + ".zone") + paths.dns = os.path.join(private_dir, dnsdomain + ".zone") paths.winsdb = os.path.join(private_dir, "wins.ldb") paths.ldap_basedn_ldif = os.path.join(private_dir, - subobj.dnsdomain + ".ldif") + dnsdomain + ".ldif") paths.ldap_config_basedn_ldif = os.path.join(private_dir, - subobj.dnsdomain + "-config.ldif") + dnsdomain + "-config.ldif") paths.ldap_schema_basedn_ldif = os.path.join(private_dir, - subobj.dnsdomain + "-schema.ldif") + dnsdomain + "-schema.ldif") paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php") @@ -247,41 +190,39 @@ def provision_default_paths(lp, subobj): return paths -def setup_name_mappings(subobj, ldb): +def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, + wheel, backup): """setup reasonable name mappings for sam names to unix names.""" - sid = str(subobj.domainsid) - # add some foreign sids if they are not present already - ldb.add_foreign(subobj.domaindn, "S-1-5-7", "Anonymous") - ldb.add_foreign(subobj.domaindn, "S-1-1-0", "World") - ldb.add_foreign(subobj.domaindn, "S-1-5-2", "Network") - ldb.add_foreign(subobj.domaindn, "S-1-5-18", "System") - ldb.add_foreign(subobj.domaindn, "S-1-5-11", "Authenticated Users") + ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous") + ldb.add_foreign(domaindn, "S-1-1-0", "World") + ldb.add_foreign(domaindn, "S-1-5-2", "Network") + ldb.add_foreign(domaindn, "S-1-5-18", "System") + ldb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users") # some well known sids - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-7", subobj.nobody) - ldb.setup_name_mapping(subobj.domaindn, "S-1-1-0", subobj.nogroup) - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-2", subobj.nogroup) - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-18", subobj.root) - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-11", subobj.users) - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-544", subobj.wheel) - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-545", subobj.users) - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-546", subobj.nogroup) - ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-551", subobj.backup) + ldb.setup_name_mapping(domaindn, "S-1-5-7", nobody) + ldb.setup_name_mapping(domaindn, "S-1-1-0", nogroup) + ldb.setup_name_mapping(domaindn, "S-1-5-2", nogroup) + ldb.setup_name_mapping(domaindn, "S-1-5-18", root) + ldb.setup_name_mapping(domaindn, "S-1-5-11", users) + ldb.setup_name_mapping(domaindn, "S-1-5-32-544", wheel) + ldb.setup_name_mapping(domaindn, "S-1-5-32-545", users) + ldb.setup_name_mapping(domaindn, "S-1-5-32-546", nogroup) + ldb.setup_name_mapping(domaindn, "S-1-5-32-551", backup) # and some well known domain rids - ldb.setup_name_mapping(subobj.domaindn, sid + "-500", subobj.root) - ldb.setup_name_mapping(subobj.domaindn, sid + "-518", subobj.wheel) - ldb.setup_name_mapping(subobj.domaindn, sid + "-519", subobj.wheel) - ldb.setup_name_mapping(subobj.domaindn, sid + "-512", subobj.wheel) - ldb.setup_name_mapping(subobj.domaindn, sid + "-513", subobj.users) - ldb.setup_name_mapping(subobj.domaindn, sid + "-520", subobj.wheel) + ldb.setup_name_mapping(domaindn, sid + "-500", root) + ldb.setup_name_mapping(domaindn, sid + "-518", wheel) + ldb.setup_name_mapping(domaindn, sid + "-519", wheel) + ldb.setup_name_mapping(domaindn, sid + "-512", wheel) + ldb.setup_name_mapping(domaindn, sid + "-513", users) + ldb.setup_name_mapping(domaindn, sid + "-520", wheel) -def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, +def provision_become_dc(setup_dir, message, paths, lp, session_info, credentials): assert session_info is not None - subobj.fix(paths) message("Setting up templates into %s" % paths.templates) setup_templatesdb(paths.templates, setup_dir, session_info, @@ -295,8 +236,8 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, samdb.erase() message("Setting up %s partitions" % paths.samdb) - setup_samdb_partitions(samdb, setup_dir, subobj.schemadn, - subobj.configdn, subobj.domaindn) + setup_samdb_partitions(samdb, setup_dir, schemadn, + configdn, domaindn) samdb = SamDB(paths.samdb, credentials=credentials, session_info=session_info, lp=lp) @@ -307,10 +248,12 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, setup_add_ldif(samdb, setup_dir, "provision_init.ldif") message("Setting up %s rootDSE" % paths.samdb) - setup_samdb_rootdse(samdb, setup_dir, subobj) + setup_samdb_rootdse(samdb, setup_dir, schemadn, domaindn, + hostname, dnsdomain, realm, rootdn, configdn, + netbiosname) message("Erasing data from partitions") - ldb_erase_partitions(subobj.domaindn, message, samdb, None) + ldb_erase_partitions(domaindn, message, samdb, None) message("Setting up %s indexes" % paths.samdb) setup_add_ldif(samdb, setup_dir, "provision_index.ldif") @@ -323,7 +266,7 @@ def provision_become_dc(setup_dir, subobj, message, paths, lp, session_info, message("Setting up %s" % paths.secrets) secrets_ldb = setup_secretsdb(paths.secrets, setup_dir, session_info, credentials, lp) setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", - { "MACHINEPASS_B64": b64encode(self.machinepass) }) + { "MACHINEPASS_B64": b64encode(machinepass) }) def setup_secretsdb(path, setup_dir, session_info, credentials, lp): @@ -351,17 +294,18 @@ def setup_registry(path, setup_dir, session_info, credentials, lp): reg.apply_patchfile(provision_reg) -def setup_samdb_rootdse(samdb, setup_dir, subobj): +def setup_samdb_rootdse(samdb, setup_dir, schemadn, domaindn, hostname, + dnsdomain, realm, rootdn, configdn, netbiosname): setup_add_ldif(samdb, setup_dir, "provision_rootdse_add.ldif", { - "SCHEMADN": subobj.schemadn, - "NETBIOSNAME": subobj.netbiosname, - "DNSDOMAIN": subobj.dnsdomain, - "DEFAULTSITE": subobj.defaultsite, - "REALM": subobj.realm, - "DNSNAME": subobj.dnsname, - "DOMAINDN": subobj.domaindn, - "ROOTDN": subobj.rootdn, - "CONFIGDN": subobj.configdn, + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "DNSDOMAIN": dnsdomain, + "DEFAULTSITE": DEFAULTSITE, + "REALM": realm, + "DNSNAME": "%s.%s" % (hostname, dnsdomain), + "DOMAINDN": domaindn, + "ROOTDN": rootdn, + "CONFIGDN": configdn, "VERSION": samba.version(), }) @@ -416,25 +360,103 @@ def setup_samdb_partitions(samdb, setup_dir, schemadn, configdn, domaindn): -def provision(lp, setup_dir, subobj, message, blank, paths, session_info, - credentials, ldapbackend): +def provision(lp, setup_dir, message, blank, paths, session_info, + credentials, ldapbackend, realm=None, domain=None, hostname=None, + hostip=None, domainsid=None, hostguid=None, adminpass=None, + krbtgtpass=None, domainguid=None, policyguid=None, + invocationid=None, machinepass=None, dnspass=None, root=None, + nobody=None, nogroup=None, users=None, wheel=None, backup=None, + aci=None, serverrole=None): """Provision samba4 :note: caution, this wipes all existing data! """ - subobj.fix(paths) + + if domainsid is None: + domainsid = security.random_sid() + if policyguid is None: + policyguid = uuid.random() + if invocationid is None: + invocationid = uuid.random() + if adminpass is None: + adminpass = misc.random_password(12) + if krbtgtpass is None: + krbtgtpass = misc.random_password(12) + if machinepass is None: + machinepass = misc.random_password(12) + if dnspass is None: + dnspass = misc.random_password(12) + if root is None: + root = findnss(pwd.getpwnam, "root")[4] + if nobody is None: + nobody = findnss(pwd.getpwnam, "nobody")[4] + if nogroup is None: + nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + if users is None: + users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", "usr")[2] + if wheel is None: + wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] + if backup is None: + backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] + if aci is None: + aci = "# no aci for local ldb" + if serverrole is None: + serverrole = lp.get("server role") + + if realm is None: + realm = lp.get("realm") + else: + if lp.get("realm").upper() != realm.upper(): + raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % + (lp.get("realm"), realm)) + + assert realm is not None + realm = realm.upper() + + if domain is None: + domain = lp.get("workgroup") + else: + if lp.get("workgroup").upper() != domain.upper(): + raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", + lp.get("workgroup"), domain) + + assert domain is not None + domain = domain.upper() + if not valid_netbios_name(domain): + raise InvalidNetbiosName(domain) + + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + if hostip is None: + hostip = gethostbyname(hostname) + + netbiosname = hostname.upper() + if not valid_netbios_name(netbiosname): + raise InvalidNetbiosName(netbiosname) + + dnsdomain = realm.lower() + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + rootdn = domaindn + configdn = "CN=Configuration," + rootdn + schemadn = "CN=Schema," + configdn + + rdn_dc = domaindn.split(",")[0][len("DC="):] + + message("Provisioning for %s in realm %s" % (domain, realm)) + message("Using administrator password: %s" % adminpass) assert paths.smbconf is not None # only install a new smb.conf if there isn't one there already if not os.path.exists(paths.smbconf): message("Setting up smb.conf") - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": smbconfsuffix = "dc" - elif lp.get("server role") == "member": + elif serverrole == "member": smbconfsuffix = "member" else: - assert "Invalid server role setting: %s" % lp.get("server role") + assert "Invalid server role setting: %s" % serverrole setup_file(setup_dir, "provision.smb.conf.%s" % smbconfsuffix, paths.smbconf) lp.reload() @@ -463,8 +485,7 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, samdb.erase() message("Setting up sam.ldb partitions") - setup_samdb_partitions(samdb, setup_dir, subobj.schemadn, - subobj.configdn, subobj.domaindn) + setup_samdb_partitions(samdb, setup_dir, schemadn, configdn, domaindn) samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) @@ -475,10 +496,12 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, setup_add_ldif(samdb, setup_dir, "provision_init.ldif") message("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, setup_dir, subobj) + setup_samdb_rootdse(samdb, setup_dir, schemadn, domaindn, + hostname, dnsdomain, realm, rootdn, configdn, + netbiosname) message("Erasing data from partitions") - ldb_erase_partitions(subobj.domaindn, message, samdb, ldapbackend) + ldb_erase_partitions(domaindn, message, samdb, ldapbackend) except: samdb.transaction_cancel() raise @@ -488,106 +511,104 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, message("Pre-loading the Samba 4 and AD schema") samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) - samdb.set_domain_sid(subobj.domainsid) - load_schema(setup_dir, samdb, subobj) + samdb.set_domain_sid(domainsid) + load_schema(setup_dir, samdb, schemadn, netbiosname, configdn) samdb.transaction_start() try: - message("Adding DomainDN: %s (permitted to fail)" % subobj.domaindn) + message("Adding DomainDN: %s (permitted to fail)" % domaindn) setup_add_ldif(samdb, setup_dir, "provision_basedn.ldif", { - "DOMAINDN": subobj.domaindn, - "ACI": "# no aci for local ldb", + "DOMAINDN": domaindn, + "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", - "RDN_DC": subobj.rdn_dc, + "RDN_DC": rdn_dc, }) - message("Modifying DomainDN: " + subobj.domaindn + "") - if subobj.domain_guid is not None: - domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % subobj.domain_guid + message("Modifying DomainDN: " + domaindn + "") + if domainguid is not None: + domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid else: domainguid_mod = "" setup_modify_ldif(samdb, setup_dir, "provision_basedn_modify.ldif", { - "RDN_DC": subobj.rdn_dc, + "RDN_DC": rdn_dc, "LDAPTIME": timestring(int(time.time())), - "DOMAINSID": str(subobj.domainsid), - "SCHEMADN": subobj.schemadn, - "NETBIOSNAME": subobj.netbiosname, - "DEFAULTSITE": subobj.defaultsite, - "CONFIGDN": subobj.configdn, - "POLICYGUID": subobj.policyguid, - "DOMAINDN": subobj.domaindn, + "DOMAINSID": str(domainsid), + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": configdn, + "POLICYGUID": policyguid, + "DOMAINDN": domaindn, "DOMAINGUID_MOD": domainguid_mod, }) message("Adding configuration container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_configuration_basedn.ldif", { - "CONFIGDN": subobj.configdn, - "ACI": "# no aci for local ldb", + "CONFIGDN": configdn, + "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", }) message("Modifying configuration container") setup_modify_ldif(samdb, setup_dir, "provision_configuration_basedn_modify.ldif", { - "CONFIGDN": subobj.configdn, - "SCHEMADN": subobj.schemadn, + "CONFIGDN": configdn, + "SCHEMADN": schemadn, }) message("Adding schema container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_schema_basedn.ldif", { - "SCHEMADN": subobj.schemadn, - "ACI": "# no aci for local ldb", + "SCHEMADN": schemadn, + "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") setup_modify_ldif(samdb, setup_dir, "provision_schema_basedn_modify.ldif", { - "SCHEMADN": subobj.schemadn, - "NETBIOSNAME": subobj.netbiosname, - "DEFAULTSITE": subobj.defaultsite, - "CONFIGDN": subobj.configdn, + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": configdn, }) message("Setting up sam.ldb Samba4 schema") - setup_add_ldif(samdb, setup_dir, "schema_samba4.ldif", { - "SCHEMADN": subobj.schemadn, - }) + setup_add_ldif(samdb, setup_dir, "schema_samba4.ldif", + {"SCHEMADN": schemadn }) message("Setting up sam.ldb AD schema") - setup_add_ldif(samdb, setup_dir, "schema.ldif", { - "SCHEMADN": subobj.schemadn, - }) + setup_add_ldif(samdb, setup_dir, "schema.ldif", + {"SCHEMADN": schemadn}) message("Setting up sam.ldb configuration data") setup_add_ldif(samdb, setup_dir, "provision_configuration.ldif", { - "CONFIGDN": subobj.configdn, - "NETBIOSNAME": subobj.netbiosname, - "DEFAULTSITE": subobj.defaultsite, - "DNSDOMAIN": subobj.dnsdomain, - "DOMAIN": subobj.domain, - "SCHEMADN": subobj.schemadn, - "DOMAINDN": subobj.domaindn, + "CONFIGDN": configdn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "DNSDOMAIN": dnsdomain, + "DOMAIN": domain, + "SCHEMADN": schemadn, + "DOMAINDN": domaindn, }) message("Setting up display specifiers") - setup_add_ldif(samdb, setup_dir, "display_specifiers.ldif", {"CONFIGDN": subobj.configdn}) + setup_add_ldif(samdb, setup_dir, "display_specifiers.ldif", {"CONFIGDN": configdn}) message("Adding users container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_users_add.ldif", { - "DOMAINDN": subobj.domaindn}) + "DOMAINDN": domaindn}) message("Modifying users container") setup_modify_ldif(samdb, setup_dir, "provision_users_modify.ldif", { - "DOMAINDN": subobj.domaindn}) + "DOMAINDN": domaindn}) message("Adding computers container (permitted to fail)") setup_add_ldif(samdb, setup_dir, "provision_computers_add.ldif", { - "DOMAINDN": subobj.domaindn}) + "DOMAINDN": domaindn}) message("Modifying computers container") setup_modify_ldif(samdb, setup_dir, "provision_computers_modify.ldif", { - "DOMAINDN": subobj.domaindn}) + "DOMAINDN": domaindn}) message("Setting up sam.ldb data") setup_add_ldif(samdb, setup_dir, "provision.ldif", { - "DOMAINDN": subobj.domaindn, - "NETBIOSNAME": subobj.netbiosname, - "DEFAULTSITE": subobj.defaultsite, - "CONFIGDN": subobj.configdn, + "DOMAINDN": domaindn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": configdn, }) if not blank: @@ -607,60 +628,63 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, # message("Setting up sam.ldb users and groups") setup_add_ldif(samdb, setup_dir, "provision_users.ldif", { - "DOMAINDN": subobj.domaindn, - "DOMAINSID": str(subobj.domainsid), - "CONFIGDN": subobj.configdn, - "ADMINPASS_B64": b64encode(subobj.adminpass), - "KRBTGTPASS_B64": b64encode(subobj.krbtgtpass), + "DOMAINDN": domaindn, + "DOMAINSID": str(domainsid), + "CONFIGDN": configdn, + "ADMINPASS_B64": b64encode(adminpass), + "KRBTGTPASS_B64": b64encode(krbtgtpass), }) if lp.get("server role") == "domain controller": message("Setting up self join") - if subobj.host_guid is not None: - hostguid_add = "objectGUID: %s" % subobj.host_guid + if hostguid is not None: + hostguid_add = "objectGUID: %s" % hostguid else: hostguid_add = "" setup_add_ldif(samdb, setup_dir, "provision_self_join.ldif", { - "CONFIGDN": subobj.configdn, - "SCHEMADN": subobj.schemadn, - "DOMAINDN": subobj.domaindn, - "INVOCATIONID": subobj.invocationid, - "NETBIOSNAME": subobj.netbiosname, - "DEFAULTSITE": subobj.defaultsite, - "DNSNAME": subobj.dnsname, - "MACHINEPASS_B64": b64encode(subobj.machinepass), - "DNSPASS_B64": b64encode(subobj.dnspass), - "REALM": subobj.realm, - "DOMAIN": subobj.domain, + "CONFIGDN": configdn, + "SCHEMADN": schemadn, + "DOMAINDN": domaindn, + "INVOCATIONID": invocationid, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "DNSNAME": "%s.%s" % (hostname, dnsdomain), + "MACHINEPASS_B64": b64encode(machinepass), + "DNSPASS_B64": b64encode(dnspass), + "REALM": realm, + "DOMAIN": domain, "HOSTGUID_ADD": hostguid_add, - "DNSDOMAIN": subobj.dnsdomain}) + "DNSDOMAIN": dnsdomain}) setup_add_ldif(samdb, setup_dir, "provision_group_policy.ldif", { - "POLICYGUID": subobj.policyguid, - "DNSDOMAIN": subobj.dnsdomain, - "DOMAINSID": str(subobj.domainsid), - "DOMAINDN": subobj.domaindn}) - - os.makedirs(os.path.join(paths.sysvol, subobj.dnsdomain, "Policies", "{" + subobj.policyguid + "}"), 0755) - os.makedirs(os.path.join(paths.sysvol, subobj.dnsdomain, "Policies", "{" + subobj.policyguid + "}", "Machine"), 0755) - os.makedirs(os.path.join(paths.sysvol, subobj.dnsdomain, "Policies", "{" + subobj.policyguid + "}", "User"), 0755) + "POLICYGUID": policyguid, + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), + "DOMAINDN": domaindn}) + + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}"), 0755) + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "Machine"), 0755) + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755) if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0755) setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", { - "MACHINEPASS_B64": b64encode(subobj.machinepass), - "DOMAIN": subobj.domain, - "REALM": subobj.realm, + "MACHINEPASS_B64": b64encode(machinepass), + "DOMAIN": domain, + "REALM": realm, "LDAPTIME": timestring(int(time.time())), - "DNSDOMAIN": subobj.dnsdomain, - "DOMAINSID": str(subobj.domainsid), + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), "SECRETS_KEYTAB": paths.keytab, - "NETBIOSNAME": subobj.netbiosname, + "NETBIOSNAME": netbiosname, "SAM_LDB": paths.samdb, "DNS_KEYTAB": paths.dns_keytab, - "DNSPASS_B64": b64encode(subobj.dnspass), + "DNSPASS_B64": b64encode(dnspass), }) - setup_name_mappings(subobj, samdb) + setup_name_mappings(samdb, str(domainsid), + domaindn, root=root, nobody=nobody, + nogroup=nogroup, wheel=wheel, users=users, + backup=backup) message("Setting up sam.ldb index") setup_add_ldif(samdb, setup_dir, "provision_index.ldif") @@ -678,113 +702,83 @@ def provision(lp, setup_dir, subobj, message, blank, paths, session_info, message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) + message("Setting up DNS zone: %s" % dnsdomain) + provision_dns(setup_dir, paths, session_info, credentials, lp, + hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, + domaindn=domaindn, dnspass=dnspass, realm=realm) + message("Please install the zone located in %s into your DNS server" % paths.dns) def create_phplpapdadmin_config(path, setup_dir, s4_ldapi_path): setup_file(setup_dir, "phpldapadmin-config.php", path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")}) -def provision_dns(setup_dir, subobj, message, paths, session_info, credentials, lp): +def provision_dns(setup_dir, paths, session_info, + credentials, lp, dnsdomain, domaindn, + hostip, hostname, dnspass, realm): """Write out a DNS zone file, from the info in the current database.""" - message("Setting up DNS zone: %s" % subobj.dnsdomain) + # connect to the sam ldb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) # These values may have changed, due to an incoming SamSync, # or may not have been specified, so fetch them from the database - domainguid = str(ldb.searchone(Dn(ldb, subobj.domaindn), "objectGUID")) + domainguid = str(ldb.searchone(Dn(ldb, domaindn), "objectGUID")) - hostguid = str(ldb.searchone(Dn(ldb, subobj.domaindn), "objectGUID" , - expression="(&(objectClass=computer)(cn=%s))" % subobj.netbiosname)) + hostguid = str(ldb.searchone(Dn(ldb, domaindn), "objectGUID" , + expression="(&(objectClass=computer)(cn=%s))" % hostname)) setup_file(setup_dir, "provision.zone", paths.dns, { - "DNSPASS_B64": b64encode(subobj.dnspass), - "HOSTNAME": hostname(), - "DNSDOMAIN": subobj.dnsdomain, - "REALM": subobj.realm, - "HOSTIP": hostip(), + "DNSPASS_B64": b64encode(dnspass), + "HOSTNAME": hostname, + "DNSDOMAIN": dnsdomain, + "REALM": realm, + "HOSTIP": hostip, "DOMAINGUID": domainguid, "DATESTRING": time.strftime("%Y%m%d%H"), - "DEFAULTSITE": subobj.defaultsite, + "DEFAULTSITE": DEFAULTSITE, "HOSTGUID": hostguid, }) - message("Please install the zone located in %s into your DNS server" % paths.dns) -def provision_ldapbase(setup_dir, subobj, message, paths): +def provision_ldapbase(setup_dir, message, paths): """Write out a DNS zone file, from the info in the current database.""" - message("Setting up LDAP base entry: %s" % subobj.domaindn) - rdns = subobj.domaindn.split(",") + message("Setting up LDAP base entry: %s" % domaindn) + rdns = domaindn.split(",") - subobj.rdn_dc = rdns[0][len("DC="):] + rdn_dc = rdns[0][len("DC="):] setup_file(setup_dir, "provision_basedn.ldif", - paths.ldap_basedn_ldif, - None) + paths.ldap_basedn_ldif) setup_file(setup_dir, "provision_configuration_basedn.ldif", - paths.ldap_config_basedn_ldif, None) + paths.ldap_config_basedn_ldif) setup_file(setup_dir, "provision_schema_basedn.ldif", paths.ldap_schema_basedn_ldif, { - "SCHEMADN": subobj.schemadn, + "SCHEMADN": schemadn, "ACI": "# no aci for local ldb", "EXTENSIBLEOBJECT": "objectClass: extensibleObject"}) message("Please install the LDIF located in " + paths.ldap_basedn_ldif + ", " + paths.ldap_config_basedn_ldif + " and " + paths.ldap_schema_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server") -def provision_guess(lp): - """guess reasonably default options for provisioning.""" - subobj = ProvisionSettings(realm=lp.get("realm").upper(), - domain=lp.get("workgroup"), - hostname=hostname(), - hostip=hostip()) - - assert subobj.realm is not None - assert subobj.domain is not None - assert subobj.hostname is not None - - subobj.domainsid = security.random_sid() - subobj.invocationid = uuid.random() - subobj.policyguid = uuid.random() - subobj.krbtgtpass = misc.random_password(12) - subobj.machinepass = misc.random_password(12) - subobj.adminpass = misc.random_password(12) - subobj.dnspass = misc.random_password(12) - subobj.root = findnss(pwd.getpwnam, "root")[4] - subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] - subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] - subobj.wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] - subobj.backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] - subobj.users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", "usr")[2] - - subobj.dnsdomain = subobj.realm.lower() - subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) - subobj.domaindn = "DC=" + subobj.dnsdomain.replace(".", ",DC=") - subobj.rootdn = subobj.domaindn - subobj.configdn = "CN=Configuration," + subobj.rootdn - subobj.schemadn = "CN=Schema," + subobj.configdn - - return subobj - - -def load_schema(setup_dir, samdb, subobj): +def load_schema(setup_dir, samdb, schemadn, netbiosname, configdn): """Load schema.""" src = os.path.join(setup_dir, "schema.ldif") schema_data = open(src, 'r').read() src = os.path.join(setup_dir, "schema_samba4.ldif") schema_data += open(src, 'r').read() - schema_data = substitute_var(schema_data, {"SCHEMADN": subobj.schemadn}) + schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) src = os.path.join(setup_dir, "provision_schema_basedn_modify.ldif") head_data = open(src, 'r').read() head_data = substitute_var(head_data, { - "SCHEMADN": subobj.schemadn, - "NETBIOSNAME": subobj.netbiosname, - "CONFIGDN": subobj.configdn, - "DEFAULTSITE": subobj.defaultsite}) + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "CONFIGDN": configdn, + "DEFAULTSITE": DEFAULTSITE}) samdb.attach_schema_from_ldif(head_data, schema_data) -- cgit From 86f91db7d5c84526b3fbd4369d7a56dc0f057b4c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 19 Dec 2007 23:27:31 +0100 Subject: r26536: More tests for provisioning code. (This used to be commit 43c8bfeedf06ce806c524a28fa72c643f6db60f4) --- source4/scripting/python/samba/__init__.py | 4 +++- source4/scripting/python/samba/provision.py | 6 ------ source4/scripting/python/samba/tests/__init__.py | 18 ++++++++++++++++++ source4/scripting/python/samba/tests/provision.py | 17 +++++++++++++---- source4/scripting/python/samba/upgrade.py | 18 +++++------------- 5 files changed, 39 insertions(+), 24 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 9ac283e660..d185464a58 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -92,7 +92,9 @@ class Ldb(ldb.Ldb): res = self.search(basedn, scope, expression, [attribute]) if len(res) != 1 or res[0][attribute] is None: return None - return res[0][attribute] + values = set(res[0][attribute]) + assert len(values) == 1 + return values.pop() def erase(self): """Erase an ldb, removing all records.""" diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index c9cb457b4a..f3fc138e6b 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -73,11 +73,6 @@ def findnss(nssfn, *names): raise Exception("Unable to find user/group for %s" % arguments[1]) -def hostname(): - """return first part of hostname.""" - return gethostname().split(".")[0] - - def open_ldb(session_info, credentials, lp, dbname): assert session_info is not None try: @@ -742,7 +737,6 @@ def provision_dns(setup_dir, paths, session_info, }) - def provision_ldapbase(setup_dir, message, paths): """Write out a DNS zone file, from the info in the current database.""" message("Setting up LDAP base entry: %s" % domaindn) diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index 0808469907..45588ecb5a 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -20,6 +20,7 @@ import os import ldb import samba +import tempfile import unittest class LdbTestCase(unittest.TestCase): @@ -35,6 +36,15 @@ class LdbTestCase(unittest.TestCase): self.ldb = samba.Ldb(self.filename) +class TestCaseInTempDir(unittest.TestCase): + def setUp(self): + super(TestCaseInTempDir, self).setUp() + self.tempdir = tempfile.mkdtemp() + + def tearDown(self): + super(TestCaseInTempDir, self).tearDown() + + class SubstituteVarTestCase(unittest.TestCase): def test_empty(self): self.assertEquals("", samba.substitute_var("", {})) @@ -52,3 +62,11 @@ class SubstituteVarTestCase(unittest.TestCase): def test_unknown_var(self): self.assertEquals("foo ${bla} gsff", samba.substitute_var("foo ${bla} gsff", {"bar": "bla"})) + + +class LdbExtensionTests(TestCaseInTempDir): + def test_searchone(self): + l = samba.Ldb(self.tempdir + "/searchone.ldb") + l.add({"dn": ldb.Dn(l, "foo=dc"), "bar": "bla"}) + self.assertEquals("bla", l.searchone(ldb.Dn(l, "foo=dc"), "bar")) + diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index 5edfe79084..c8bd99283b 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -17,13 +17,22 @@ # along with this program. If not, see . # -import unittest -import samba.provision +import os +from samba.provision import setup_secretsdb +import samba.tests +from ldb import Dn -class ProvisionTestCase(unittest.TestCase): +setup_dir = "setup" + +class ProvisionTestCase(samba.tests.TestCaseInTempDir): def test_setup_secretsdb(self): - raise NotImplementedError(self.test_setup_secretsdb) + ldb = setup_secretsdb(os.path.join(self.tempdir, "secrets.ldb"), + setup_dir, None, None, None) + self.assertEquals("LSA Secrets", + ldb.searchone(Dn(ldb, "CN=LSA Secrets"), "CN")) + +class Disabled: def test_setup_templatesdb(self): raise NotImplementedError(self.test_setup_templatesdb) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 783cc008d5..4521d4604d 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -14,7 +14,10 @@ import pwd import uuid def regkey_to_dn(name): - """Convert a registry key to a DN.""" + """Convert a registry key to a DN. + + :name: The registry key name. + :return: A matching DN.""" dn = "hive=NONE" if name == "": @@ -253,8 +256,6 @@ maxVersion: %llu return ldif def upgrade_provision(lp, samba3): - subobj = Object() - domainname = samba3.configuration.get("workgroup") if domainname is None: @@ -272,13 +273,7 @@ def upgrade_provision(lp, samba3): subobj.realm = realm subobj.domain = domainname - subobj.hostname = hostname() - assert subobj.realm is not None - assert subobj.domain is not None - assert subobj.hostname is not None - - subobj.HOSTIP = hostip() if domsec is not None: subobj.DOMAINGUID = domsec.guid subobj.DOMAINSID = domsec.sid @@ -288,10 +283,7 @@ def upgrade_provision(lp, samba3): subobj.DOMAINSID = randsid() if hostsec: - subobj.HOSTGUID = hostsec.guid - else: - subobj.HOSTGUID = uuid.random() - subobj.invocationid = uuid.random() + hostguid = hostsec.guid subobj.krbtgtpass = randpass(12) subobj.machinepass = randpass(12) subobj.adminpass = randpass(12) -- cgit From c2fffa8335ac68ff70de52f9fc80fb49e5d6d686 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 19 Dec 2007 23:27:38 +0100 Subject: r26538: Pass path generation function around rather than base directory. (This used to be commit 5f921af41e4dcd6844f6a662d56bd27c4e76ff88) --- source4/scripting/python/samba/__init__.py | 41 +++- source4/scripting/python/samba/provision.py | 256 ++++++++++------------ source4/scripting/python/samba/samdb.py | 4 +- source4/scripting/python/samba/tests/__init__.py | 2 +- source4/scripting/python/samba/tests/provision.py | 5 +- source4/scripting/python/samba/upgrade.py | 4 +- 6 files changed, 164 insertions(+), 148 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index d185464a58..2c46f72883 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -87,7 +87,8 @@ class Ldb(ldb.Ldb): set_session_info = misc.ldb_set_session_info set_loadparm = misc.ldb_set_loadparm - def searchone(self, basedn, attribute, expression=None, scope=ldb.SCOPE_BASE): + def searchone(self, basedn, attribute, expression=None, + scope=ldb.SCOPE_BASE): """Search for one attribute as a string.""" res = self.search(basedn, scope, expression, [attribute]) if len(res) != 1 or res[0][attribute] is None: @@ -112,11 +113,47 @@ class Ldb(ldb.Ldb): for msg in self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]): - self.delete(msg.dn) + try: + self.delete(msg.dn) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignor eno such object errors + pass res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) assert len(res) == 0 + def erase_partitions(self): + """Erase an ldb, removing all records.""" + res = self.search(ldb.Dn(self, ""), ldb.SCOPE_BASE, "(objectClass=*)", + ["namingContexts"]) + assert len(res) == 1 + if not "namingContexts" in res[0]: + return + for basedn in res[0]["namingContexts"]: + previous_remaining = 1 + current_remaining = 0 + + k = 0 + while ++k < 10 and (previous_remaining != current_remaining): + # and the rest + res2 = self.search(ldb.Dn(self, basedn), ldb.SCOPE_SUBTREE, "(|(objectclass=*)(dn=*))", ["dn"]) + previous_remaining = current_remaining + current_remaining = len(res2) + for msg in res2: + self.delete(msg.dn) + + def load_ldif_file_add(self, ldif_path): + """Load a LDIF file. + + :param ldif_path: Path to LDIF file. + """ + self.load_ldif_add(open(ldif_path, 'r').read()) + + def load_ldif_add(self, ldif): + for changetype, msg in self.parse_ldif(ldif): + assert changetype == ldb.CHANGETYPE_NONE + self.add(msg) + def substitute_var(text, values): """substitute strings of the form ${NAME} in str, replacing diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f3fc138e6b..90f7cd0697 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -21,7 +21,7 @@ from samba import Ldb, substitute_var, valid_netbios_name from samba.samdb import SamDB import security from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ - LDB_ERR_NO_SUCH_OBJECT, timestring + LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE DEFAULTSITE = "Default-First-Site-Name" @@ -58,7 +58,7 @@ def install_ok(lp, session_info, credentials): return False ldb = Ldb(lp.get("sam database"), session_info=session_info, credentials=credentials, lp=lp) - if len(ldb.search("(cn=Administrator)")) != 1: + if len(ldb.search(ldb.Dn("(cn=Administrator)"))) != 1: return False return True @@ -85,62 +85,56 @@ def open_ldb(session_info, credentials, lp, dbname): lp=lp) -def setup_add_ldif(ldb, setup_dir, ldif, subst_vars=None): +def setup_add_ldif(ldb, ldif_path, subst_vars=None): """Setup a ldb in the private dir.""" - assert isinstance(ldif, str) - assert isinstance(setup_dir, str) - src = os.path.join(setup_dir, ldif) + assert isinstance(ldif_path, str) - data = open(src, 'r').read() + data = open(ldif_path, 'r').read() if subst_vars is not None: data = substitute_var(data, subst_vars) assert "${" not in data - for msg in ldb.parse_ldif(data): - ldb.add(msg[1]) + ldb.load_ldif_add(data) -def setup_modify_ldif(ldb, setup_dir, ldif, substvars=None): +def setup_modify_ldif(ldb, ldif_path, substvars=None): """Modify a ldb in the private dir. :param ldb: LDB object. - :param setup_dir: Setup directory. - :param ldif: LDIF file path. + :param ldif_path: LDIF file path. :param substvars: Optional dictionary with substitution variables. """ - src = os.path.join(setup_dir, ldif) - - data = open(src, 'r').read() + data = open(ldif_path, 'r').read() if substvars is not None: data = substitute_var(data, substvars) assert "${" not in data for (changetype, msg) in ldb.parse_ldif(data): + assert changetype == CHANGETYPE_MODIFY ldb.modify(msg) -def setup_ldb(ldb, setup_dir, ldif, subst_vars=None): +def setup_ldb(ldb, ldif_path, subst_vars): assert ldb is not None ldb.transaction_start() try: - setup_add_ldif(ldb, setup_dir, ldif, subst_vars) + setup_add_ldif(ldb, ldif_path, subst_vars) except: ldb.transaction_cancel() raise ldb.transaction_commit() -def setup_file(setup_dir, template, fname, substvars): +def setup_file(template, fname, substvars): """Setup a file in the private dir.""" f = fname - src = os.path.join(setup_dir, template) if os.path.exists(f): os.unlink(f) - data = open(src, 'r').read() + data = open(template, 'r').read() if substvars: data = substitute_var(data, substvars) assert not "${" in data @@ -218,40 +212,44 @@ def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, def provision_become_dc(setup_dir, message, paths, lp, session_info, credentials): assert session_info is not None + erase = False + + def setup_path(file): + return os.path.join(setup_dir, file) + os.path.unlink(paths.samdb) - message("Setting up templates into %s" % paths.templates) - setup_templatesdb(paths.templates, setup_dir, session_info, + message("Setting up templates db") + setup_templatesdb(paths.templates, setup_path, session_info, credentials, lp) # Also wipes the database - message("Setting up samdb") - os.path.unlink(paths.samdb) + message("Setting up sam.ldb") samdb = SamDB(paths.samdb, credentials=credentials, session_info=session_info, lp=lp) - samdb.erase() - message("Setting up %s partitions" % paths.samdb) - setup_samdb_partitions(samdb, setup_dir, schemadn, - configdn, domaindn) + message("Setting up sam.ldb partitions") + setup_samdb_partitions(samdb, setup_path, schemadn, + configdn, domaindn) samdb = SamDB(paths.samdb, credentials=credentials, session_info=session_info, lp=lp) ldb.transaction_start() try: - message("Setting up %s attributes" % paths.samdb) - setup_add_ldif(samdb, setup_dir, "provision_init.ldif") + message("Setting up sam.ldb attributes") + samdb.load_ldif_file_add(setup_path("provision_init.ldif")) - message("Setting up %s rootDSE" % paths.samdb) - setup_samdb_rootdse(samdb, setup_dir, schemadn, domaindn, + message("Setting up sam.ldb rootDSE") + setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, dnsdomain, realm, rootdn, configdn, netbiosname) - message("Erasing data from partitions") - ldb_erase_partitions(domaindn, message, samdb, None) + if erase: + message("Erasing data from partitions") + samdb.erase_partitions() - message("Setting up %s indexes" % paths.samdb) - setup_add_ldif(samdb, setup_dir, "provision_index.ldif") + message("Setting up sam.ldb indexes") + samdb.load_ldif_file_add(setup_path("provision_index.ldif")) except: samdb.transaction_cancel() raise @@ -259,39 +257,39 @@ def provision_become_dc(setup_dir, message, paths, lp, session_info, samdb.transaction_commit() message("Setting up %s" % paths.secrets) - secrets_ldb = setup_secretsdb(paths.secrets, setup_dir, session_info, credentials, lp) - setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", + secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info, credentials, lp) + setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { "MACHINEPASS_B64": b64encode(machinepass) }) -def setup_secretsdb(path, setup_dir, session_info, credentials, lp): +def setup_secretsdb(path, setup_path, session_info, credentials, lp): secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp) secrets_ldb.erase() - setup_ldb(secrets_ldb, setup_dir, "secrets_init.ldif") - setup_ldb(secrets_ldb, setup_dir, "secrets.ldif") + secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif")) + secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) return secrets_ldb -def setup_templatesdb(path, setup_dir, session_info, credentials, lp): - templates_ldb = Ldb(path, session_info=session_info, +def setup_templatesdb(path, setup_path, session_info, credentials, lp): + templates_ldb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) templates_ldb.erase() - setup_ldb(templates_ldb, setup_dir, "provision_templates.ldif", None) + templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif")) -def setup_registry(path, setup_dir, session_info, credentials, lp): +def setup_registry(path, setup_path, session_info, credentials, lp): reg = registry.Registry() hive = registry.Hive(path, session_info=session_info, credentials=credentials, lp_ctx=lp) reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") - provision_reg = os.path.join(setup_dir, "provision.reg") + provision_reg = setup_path("provision.reg") assert os.path.exists(provision_reg) reg.apply_patchfile(provision_reg) -def setup_samdb_rootdse(samdb, setup_dir, schemadn, domaindn, hostname, +def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, dnsdomain, realm, rootdn, configdn, netbiosname): - setup_add_ldif(samdb, setup_dir, "provision_rootdse_add.ldif", { + setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), { "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "DNSDOMAIN": dnsdomain, @@ -305,7 +303,7 @@ def setup_samdb_rootdse(samdb, setup_dir, schemadn, domaindn, hostname, }) -def setup_samdb_partitions(samdb, setup_dir, schemadn, configdn, domaindn): +def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn): #Add modules to the list to activate them by default #beware often order is important # @@ -335,7 +333,7 @@ def setup_samdb_partitions(samdb, setup_dir, schemadn, configdn, domaindn): modules_list2 = ["show_deleted", "partition"] - setup_ldb(samdb, setup_dir, "provision_partitions.ldif", { + setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { "SCHEMADN": schemadn, "SCHEMADN_LDB": "schema.ldb", "SCHEMADN_MOD2": ",objectguid", @@ -367,6 +365,11 @@ def provision(lp, setup_dir, message, blank, paths, session_info, :note: caution, this wipes all existing data! """ + def setup_path(file): + return os.path.join(setup_dir, file) + + erase = False + if domainsid is None: domainsid = security.random_sid() if policyguid is None: @@ -438,6 +441,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, rdn_dc = domaindn.split(",")[0][len("DC="):] + message("set DOMAIN SID: %s" % str(domainsid)) message("Provisioning for %s in realm %s" % (domain, realm)) message("Using administrator password: %s" % adminpass) @@ -452,7 +456,14 @@ def provision(lp, setup_dir, message, blank, paths, session_info, smbconfsuffix = "member" else: assert "Invalid server role setting: %s" % serverrole - setup_file(setup_dir, "provision.smb.conf.%s" % smbconfsuffix, paths.smbconf) + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { + "HOSTNAME": hostname, + "DOMAIN_CONF": domain, + "REALM_CONF": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": paths.netlogon, + "SYSVOLPATH": paths.sysvol, + }) lp.reload() # only install a new shares config db if there is none @@ -460,27 +471,26 @@ def provision(lp, setup_dir, message, blank, paths, session_info, message("Setting up share.ldb") share_ldb = Ldb(paths.shareconf, session_info=session_info, credentials=credentials, lp=lp) - setup_ldb(share_ldb, setup_dir, "share.ldif") + share_ldb.load_ldif_file_add(setup_path("share.ldif")) - message("Setting up %s" % paths.secrets) - secrets_ldb = setup_secretsdb(paths.secrets, setup_dir, session_info=session_info, + message("Setting up secrets.ldb") + secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info=session_info, credentials=credentials, lp=lp) - message("Setting up registry") + message("Setting up the registry") # FIXME: Still fails for some reason - #setup_registry(paths.hklm, setup_dir, session_info, + #setup_registry(paths.hklm, setup_path, session_info, # credentials=credentials, lp=lp) - message("Setting up templates into %s" % paths.templates) - setup_templatesdb(paths.templates, setup_dir, session_info=session_info, + message("Setting up templates db") + setup_templatesdb(paths.templates, setup_path, session_info=session_info, credentials=credentials, lp=lp) samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) - samdb.erase() message("Setting up sam.ldb partitions") - setup_samdb_partitions(samdb, setup_dir, schemadn, configdn, domaindn) + setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn) samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) @@ -488,15 +498,16 @@ def provision(lp, setup_dir, message, blank, paths, session_info, samdb.transaction_start() try: message("Setting up sam.ldb attributes") - setup_add_ldif(samdb, setup_dir, "provision_init.ldif") + samdb.load_ldif_file_add(setup_path("provision_init.ldif")) message("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, setup_dir, schemadn, domaindn, + setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, dnsdomain, realm, rootdn, configdn, netbiosname) - message("Erasing data from partitions") - ldb_erase_partitions(domaindn, message, samdb, ldapbackend) + if erase: + message("Erasing data from partitions") + samdb.erase_partitions() except: samdb.transaction_cancel() raise @@ -507,13 +518,13 @@ def provision(lp, setup_dir, message, blank, paths, session_info, samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(domainsid) - load_schema(setup_dir, samdb, schemadn, netbiosname, configdn) + load_schema(setup_path, samdb, schemadn, netbiosname, configdn) samdb.transaction_start() try: message("Adding DomainDN: %s (permitted to fail)" % domaindn) - setup_add_ldif(samdb, setup_dir, "provision_basedn.ldif", { + setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { "DOMAINDN": domaindn, "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", @@ -526,7 +537,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, else: domainguid_mod = "" - setup_modify_ldif(samdb, setup_dir, "provision_basedn_modify.ldif", { + setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), { "RDN_DC": rdn_dc, "LDAPTIME": timestring(int(time.time())), "DOMAINSID": str(domainsid), @@ -540,25 +551,25 @@ def provision(lp, setup_dir, message, blank, paths, session_info, }) message("Adding configuration container (permitted to fail)") - setup_add_ldif(samdb, setup_dir, "provision_configuration_basedn.ldif", { + setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), { "CONFIGDN": configdn, "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", }) message("Modifying configuration container") - setup_modify_ldif(samdb, setup_dir, "provision_configuration_basedn_modify.ldif", { + setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), { "CONFIGDN": configdn, "SCHEMADN": schemadn, }) message("Adding schema container (permitted to fail)") - setup_add_ldif(samdb, setup_dir, "provision_schema_basedn.ldif", { + setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), { "SCHEMADN": schemadn, "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") - setup_modify_ldif(samdb, setup_dir, "provision_schema_basedn_modify.ldif", { + setup_modify_ldif(samdb, setup_path("provision_schema_basedn_modify.ldif"), { "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "DEFAULTSITE": DEFAULTSITE, @@ -566,14 +577,14 @@ def provision(lp, setup_dir, message, blank, paths, session_info, }) message("Setting up sam.ldb Samba4 schema") - setup_add_ldif(samdb, setup_dir, "schema_samba4.ldif", + setup_add_ldif(samdb, setup_path("schema_samba4.ldif"), {"SCHEMADN": schemadn }) message("Setting up sam.ldb AD schema") - setup_add_ldif(samdb, setup_dir, "schema.ldif", + setup_add_ldif(samdb, setup_path("schema.ldif"), {"SCHEMADN": schemadn}) message("Setting up sam.ldb configuration data") - setup_add_ldif(samdb, setup_dir, "provision_configuration.ldif", { + setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), { "CONFIGDN": configdn, "NETBIOSNAME": netbiosname, "DEFAULTSITE": DEFAULTSITE, @@ -584,22 +595,23 @@ def provision(lp, setup_dir, message, blank, paths, session_info, }) message("Setting up display specifiers") - setup_add_ldif(samdb, setup_dir, "display_specifiers.ldif", {"CONFIGDN": configdn}) + setup_add_ldif(samdb, setup_path("display_specifiers.ldif"), + {"CONFIGDN": configdn}) message("Adding users container (permitted to fail)") - setup_add_ldif(samdb, setup_dir, "provision_users_add.ldif", { + setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), { "DOMAINDN": domaindn}) message("Modifying users container") - setup_modify_ldif(samdb, setup_dir, "provision_users_modify.ldif", { + setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), { "DOMAINDN": domaindn}) message("Adding computers container (permitted to fail)") - setup_add_ldif(samdb, setup_dir, "provision_computers_add.ldif", { + setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), { "DOMAINDN": domaindn}) message("Modifying computers container") - setup_modify_ldif(samdb, setup_dir, "provision_computers_modify.ldif", { + setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), { "DOMAINDN": domaindn}) message("Setting up sam.ldb data") - setup_add_ldif(samdb, setup_dir, "provision.ldif", { + setup_add_ldif(samdb, setup_path("provision.ldif"), { "DOMAINDN": domaindn, "NETBIOSNAME": netbiosname, "DEFAULTSITE": DEFAULTSITE, @@ -622,7 +634,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, # samdb = open_ldb(info, paths.samdb, False) # message("Setting up sam.ldb users and groups") - setup_add_ldif(samdb, setup_dir, "provision_users.ldif", { + setup_add_ldif(samdb, setup_path("provision_users.ldif"), { "DOMAINDN": domaindn, "DOMAINSID": str(domainsid), "CONFIGDN": configdn, @@ -637,7 +649,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, else: hostguid_add = "" - setup_add_ldif(samdb, setup_dir, "provision_self_join.ldif", { + setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { "CONFIGDN": configdn, "SCHEMADN": schemadn, "DOMAINDN": domaindn, @@ -651,7 +663,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, "DOMAIN": domain, "HOSTGUID_ADD": hostguid_add, "DNSDOMAIN": dnsdomain}) - setup_add_ldif(samdb, setup_dir, "provision_group_policy.ldif", { + setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { "POLICYGUID": policyguid, "DNSDOMAIN": dnsdomain, "DOMAINSID": str(domainsid), @@ -662,7 +674,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755) if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0755) - setup_ldb(secrets_ldb, setup_dir, "secrets_dc.ldif", { + setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { "MACHINEPASS_B64": b64encode(machinepass), "DOMAIN": domain, "REALM": realm, @@ -682,10 +694,10 @@ def provision(lp, setup_dir, message, blank, paths, session_info, backup=backup) message("Setting up sam.ldb index") - setup_add_ldif(samdb, setup_dir, "provision_index.ldif") + samdb.load_ldif_file_add(setup_path("provision_index.ldif")) message("Setting up sam.ldb rootDSE marking as syncronized") - setup_modify_ldif(samdb, setup_dir, "provision_rootdse_modify.ldif") + setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) except: samdb.transaction_cancel() raise @@ -693,38 +705,33 @@ def provision(lp, setup_dir, message, blank, paths, session_info, samdb.transaction_commit() message("Setting up phpLDAPadmin configuration") - create_phplpapdadmin_config(paths.phpldapadminconfig, setup_dir, paths.s4_ldapi_path) + create_phplpapdadmin_config(paths.phpldapadminconfig, setup_path, paths.s4_ldapi_path) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) message("Setting up DNS zone: %s" % dnsdomain) - provision_dns(setup_dir, paths, session_info, credentials, lp, + create_zone_file(paths.dns, setup_path, samdb, hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, domaindn=domaindn, dnspass=dnspass, realm=realm) message("Please install the zone located in %s into your DNS server" % paths.dns) -def create_phplpapdadmin_config(path, setup_dir, s4_ldapi_path): - setup_file(setup_dir, "phpldapadmin-config.php", +def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path): + setup_file(setup_path("phpldapadmin-config.php"), path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")}) -def provision_dns(setup_dir, paths, session_info, - credentials, lp, dnsdomain, domaindn, +def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, hostip, hostname, dnspass, realm): """Write out a DNS zone file, from the info in the current database.""" # connect to the sam - ldb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, - lp=lp) - # These values may have changed, due to an incoming SamSync, # or may not have been specified, so fetch them from the database - domainguid = str(ldb.searchone(Dn(ldb, domaindn), "objectGUID")) + domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID") + hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID" , + expression="(&(objectClass=computer)(cn=%s))" % hostname) - hostguid = str(ldb.searchone(Dn(ldb, domaindn), "objectGUID" , - expression="(&(objectClass=computer)(cn=%s))" % hostname)) - - setup_file(setup_dir, "provision.zone", paths.dns, { + setup_file(setup_path("provision.zone"), path, { "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": hostname, "DNSDOMAIN": dnsdomain, @@ -744,13 +751,16 @@ def provision_ldapbase(setup_dir, message, paths): rdn_dc = rdns[0][len("DC="):] - setup_file(setup_dir, "provision_basedn.ldif", + def setup_path(file): + return os.path.join(setup_dir, file) + + setup_file(setup_path("provision_basedn.ldif"), paths.ldap_basedn_ldif) - setup_file(setup_dir, "provision_configuration_basedn.ldif", + setup_file(setup_path("provision_configuration_basedn.ldif"), paths.ldap_config_basedn_ldif) - setup_file(setup_dir, "provision_schema_basedn.ldif", + setup_file(setup_path("provision_schema_basedn.ldif"), paths.ldap_schema_basedn_ldif, { "SCHEMADN": schemadn, "ACI": "# no aci for local ldb", @@ -759,15 +769,12 @@ def provision_ldapbase(setup_dir, message, paths): message("Please install the LDIF located in " + paths.ldap_basedn_ldif + ", " + paths.ldap_config_basedn_ldif + " and " + paths.ldap_schema_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server") -def load_schema(setup_dir, samdb, schemadn, netbiosname, configdn): +def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): """Load schema.""" - src = os.path.join(setup_dir, "schema.ldif") - schema_data = open(src, 'r').read() - src = os.path.join(setup_dir, "schema_samba4.ldif") - schema_data += open(src, 'r').read() + schema_data = open(setup_path("schema.ldif"), 'r').read() + schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) - src = os.path.join(setup_dir, "provision_schema_basedn_modify.ldif") - head_data = open(src, 'r').read() + head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read() head_data = substitute_var(head_data, { "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, @@ -803,33 +810,4 @@ def vampire(domain, session_info, credentials, message): raise Exception("Migration of remote domain to Samba failed: %s " % vampire_ctx.error_string) -def ldb_erase_partitions(domaindn, message, ldb, ldapbackend): - """Erase an ldb, removing all records.""" - assert ldb is not None - res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)", - ["namingContexts"]) - assert len(res) == 1 - if not "namingContexts" in res[0]: - return - for basedn in res[0]["namingContexts"]: - anything = "(|(objectclass=*)(dn=*))" - previous_remaining = 1 - current_remaining = 0 - - if ldapbackend and (basedn == domaindn): - # Only delete objects that were created by provision - anything = "(objectcategory=*)" - - k = 0 - while ++k < 10 and (previous_remaining != current_remaining): - # and the rest - res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"]) - previous_remaining = current_remaining - current_remaining = len(res2) - for msg in res2: - try: - ldb.delete(msg.dn) - except LdbError, (_, text): - message("Unable to delete %s: %s" % (msg.dn, text)) - diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 7061e22ce4..84b604dbc4 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -29,8 +29,8 @@ class SamDB(samba.Ldb): modules_dir=None, lp=None): super(SamDB, self).__init__(session_info=session_info, credentials=credentials, modules_dir=modules_dir, lp=lp) - misc.dsdb_set_global_schema(self) - misc.ldb_register_samba_handlers(self) + assert misc.dsdb_set_global_schema(self) == 0 + assert misc.ldb_register_samba_handlers(self) == 0 if url: self.connect(url) diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index 45588ecb5a..e213c1cc1f 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -67,6 +67,6 @@ class SubstituteVarTestCase(unittest.TestCase): class LdbExtensionTests(TestCaseInTempDir): def test_searchone(self): l = samba.Ldb(self.tempdir + "/searchone.ldb") - l.add({"dn": ldb.Dn(l, "foo=dc"), "bar": "bla"}) + l.add({"dn": "foo=dc", "bar": "bla"}) self.assertEquals("bla", l.searchone(ldb.Dn(l, "foo=dc"), "bar")) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index c8bd99283b..bf7182dbd3 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -23,11 +23,14 @@ import samba.tests from ldb import Dn setup_dir = "setup" +def setup_path(file): + return os.path.join(setup_dir, file) + class ProvisionTestCase(samba.tests.TestCaseInTempDir): def test_setup_secretsdb(self): ldb = setup_secretsdb(os.path.join(self.tempdir, "secrets.ldb"), - setup_dir, None, None, None) + setup_path, None, None, None) self.assertEquals("LSA Secrets", ldb.searchone(Dn(ldb, "CN=LSA Secrets"), "CN")) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 4521d4604d..1c27f8ec25 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -537,9 +537,7 @@ replace: @LIST @LIST: samldb,operational,objectguid,rdn_name,samba3sam """) - samdb.add(""" -dn: @MAP=samba3sam -@MAP_URL: %s""" % ldapurl) + samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl}) return ret -- cgit From 109a903750e6bec865e402f02c5c457250594e55 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 20 Dec 2007 15:53:56 +0100 Subject: r26545: Sync output with ejs. (This used to be commit 48ceaa964327ed7094275780cc3c0767636bcb18) --- source4/scripting/python/samba/__init__.py | 2 + source4/scripting/python/samba/provision.py | 65 +++++++++++++---------------- source4/scripting/python/samba/samdb.py | 1 - 3 files changed, 32 insertions(+), 36 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 2c46f72883..c735361353 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -72,6 +72,8 @@ class Ldb(ldb.Ldb): if session_info is not None: self.set_session_info(self, session_info) + assert misc.ldb_register_samba_handlers(self) == 0 + if lp is not None: self.set_loadparm(self, lp) diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 90f7cd0697..a4a9e7ac46 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -219,20 +219,19 @@ def provision_become_dc(setup_dir, message, paths, lp, session_info, os.path.unlink(paths.samdb) message("Setting up templates db") - setup_templatesdb(paths.templates, setup_path, session_info, - credentials, lp) + setup_templatesdb(paths.templates, setup_path, session_info=session_info, + credentials=credentials, lp=lp) # Also wipes the database message("Setting up sam.ldb") - samdb = SamDB(paths.samdb, credentials=credentials, - session_info=session_info, lp=lp) + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) message("Setting up sam.ldb partitions") - setup_samdb_partitions(samdb, setup_path, schemadn, - configdn, domaindn) + setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn) - samdb = SamDB(paths.samdb, credentials=credentials, - session_info=session_info, lp=lp) + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) ldb.transaction_start() try: @@ -257,12 +256,15 @@ def provision_become_dc(setup_dir, message, paths, lp, session_info, samdb.transaction_commit() message("Setting up %s" % paths.secrets) - secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info, credentials, lp) + secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info, + credentials, lp) setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { "MACHINEPASS_B64": b64encode(machinepass) }) def setup_secretsdb(path, setup_path, session_info, credentials, lp): + if os.path.exists(path): + os.unlink(path) secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp) secrets_ldb.erase() secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif")) @@ -474,8 +476,9 @@ def provision(lp, setup_dir, message, blank, paths, session_info, share_ldb.load_ldif_file_add(setup_path("share.ldif")) message("Setting up secrets.ldb") - secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info=session_info, - credentials=credentials, lp=lp) + secrets_ldb = setup_secretsdb(paths.secrets, setup_path, + session_info=session_info, + credentials=credentials, lp=lp) message("Setting up the registry") # FIXME: Still fails for some reason @@ -486,6 +489,8 @@ def provision(lp, setup_dir, message, blank, paths, session_info, setup_templatesdb(paths.templates, setup_path, session_info=session_info, credentials=credentials, lp=lp) + # Also wipes the database + message("Setting up sam.ldb") samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) @@ -619,20 +624,6 @@ def provision(lp, setup_dir, message, blank, paths, session_info, }) if not blank: - - # message("Activate schema module") - # setup_modify_ldif("schema_activation.ldif", info, samdb, False) - # - # // (hack) Reload, now we have the schema loaded. - # commit_ok = samdb.transaction_commit() - # if (!commit_ok) { - # message("samdb commit failed: " + samdb.errstring() + "\n") - # assert(commit_ok) - # } - # samdb.close() - # - # samdb = open_ldb(info, paths.samdb, False) - # message("Setting up sam.ldb users and groups") setup_add_ldif(samdb, setup_path("provision_users.ldif"), { "DOMAINDN": domaindn, @@ -696,7 +687,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, message("Setting up sam.ldb index") samdb.load_ldif_file_add(setup_path("provision_index.ldif")) - message("Setting up sam.ldb rootDSE marking as syncronized") + message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) except: samdb.transaction_cancel() @@ -709,10 +700,21 @@ def provision(lp, setup_dir, message, blank, paths, session_info, message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + + domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID") + assert isinstance(domainguid, str) + hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID", + expression="(&(objectClass=computer)(cn=%s))" % hostname, + scope=SCOPE_SUBTREE) + assert isinstance(hostguid, str) + message("Setting up DNS zone: %s" % dnsdomain) create_zone_file(paths.dns, setup_path, samdb, hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, - domaindn=domaindn, dnspass=dnspass, realm=realm) + domaindn=domaindn, dnspass=dnspass, realm=realm, + domainguid=domainguid, hostguid=hostguid) message("Please install the zone located in %s into your DNS server" % paths.dns) def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path): @@ -721,16 +723,9 @@ def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path): def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, - hostip, hostname, dnspass, realm): + hostip, hostname, dnspass, realm, domainguid, hostguid): """Write out a DNS zone file, from the info in the current database.""" - # connect to the sam - # These values may have changed, due to an incoming SamSync, - # or may not have been specified, so fetch them from the database - domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID") - hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID" , - expression="(&(objectClass=computer)(cn=%s))" % hostname) - setup_file(setup_path("provision.zone"), path, { "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": hostname, diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 84b604dbc4..46707f060f 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -30,7 +30,6 @@ class SamDB(samba.Ldb): super(SamDB, self).__init__(session_info=session_info, credentials=credentials, modules_dir=modules_dir, lp=lp) assert misc.dsdb_set_global_schema(self) == 0 - assert misc.ldb_register_samba_handlers(self) == 0 if url: self.connect(url) -- cgit From 30ce895e0c75c50bbe510b6a3685c7e1f217b919 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 22 Dec 2007 00:47:36 -0600 Subject: r26559: Make the provision function a bit smaller. (This used to be commit a1175231a58c60f32574816643dafc78ff867161) --- source4/scripting/python/samba/provision.py | 346 +++++++++++++++------------- 1 file changed, 182 insertions(+), 164 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index a4a9e7ac46..f516e73893 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -354,150 +354,21 @@ def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn): }) - -def provision(lp, setup_dir, message, blank, paths, session_info, - credentials, ldapbackend, realm=None, domain=None, hostname=None, - hostip=None, domainsid=None, hostguid=None, adminpass=None, - krbtgtpass=None, domainguid=None, policyguid=None, - invocationid=None, machinepass=None, dnspass=None, root=None, - nobody=None, nogroup=None, users=None, wheel=None, backup=None, - aci=None, serverrole=None): - """Provision samba4 - - :note: caution, this wipes all existing data! - """ - - def setup_path(file): - return os.path.join(setup_dir, file) - - erase = False - - if domainsid is None: - domainsid = security.random_sid() - if policyguid is None: - policyguid = uuid.random() - if invocationid is None: - invocationid = uuid.random() - if adminpass is None: - adminpass = misc.random_password(12) - if krbtgtpass is None: - krbtgtpass = misc.random_password(12) - if machinepass is None: - machinepass = misc.random_password(12) - if dnspass is None: - dnspass = misc.random_password(12) - if root is None: - root = findnss(pwd.getpwnam, "root")[4] - if nobody is None: - nobody = findnss(pwd.getpwnam, "nobody")[4] - if nogroup is None: - nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] - if users is None: - users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", "usr")[2] - if wheel is None: - wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] - if backup is None: - backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] - if aci is None: - aci = "# no aci for local ldb" - if serverrole is None: - serverrole = lp.get("server role") - - if realm is None: - realm = lp.get("realm") - else: - if lp.get("realm").upper() != realm.upper(): - raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % - (lp.get("realm"), realm)) - - assert realm is not None - realm = realm.upper() - - if domain is None: - domain = lp.get("workgroup") - else: - if lp.get("workgroup").upper() != domain.upper(): - raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", - lp.get("workgroup"), domain) - - assert domain is not None - domain = domain.upper() - if not valid_netbios_name(domain): - raise InvalidNetbiosName(domain) - - if hostname is None: - hostname = gethostname().split(".")[0].lower() - - if hostip is None: - hostip = gethostbyname(hostname) - - netbiosname = hostname.upper() - if not valid_netbios_name(netbiosname): - raise InvalidNetbiosName(netbiosname) - - dnsdomain = realm.lower() - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") - rootdn = domaindn - configdn = "CN=Configuration," + rootdn - schemadn = "CN=Schema," + configdn - - rdn_dc = domaindn.split(",")[0][len("DC="):] - - message("set DOMAIN SID: %s" % str(domainsid)) - message("Provisioning for %s in realm %s" % (domain, realm)) - message("Using administrator password: %s" % adminpass) - - assert paths.smbconf is not None - - # only install a new smb.conf if there isn't one there already - if not os.path.exists(paths.smbconf): - message("Setting up smb.conf") - if serverrole == "domain controller": - smbconfsuffix = "dc" - elif serverrole == "member": - smbconfsuffix = "member" - else: - assert "Invalid server role setting: %s" % serverrole - setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { - "HOSTNAME": hostname, - "DOMAIN_CONF": domain, - "REALM_CONF": realm, - "SERVERROLE": serverrole, - "NETLOGONPATH": paths.netlogon, - "SYSVOLPATH": paths.sysvol, - }) - lp.reload() - - # only install a new shares config db if there is none - if not os.path.exists(paths.shareconf): - message("Setting up share.ldb") - share_ldb = Ldb(paths.shareconf, session_info=session_info, - credentials=credentials, lp=lp) - share_ldb.load_ldif_file_add(setup_path("share.ldif")) - - message("Setting up secrets.ldb") - secrets_ldb = setup_secretsdb(paths.secrets, setup_path, - session_info=session_info, - credentials=credentials, lp=lp) - - message("Setting up the registry") - # FIXME: Still fails for some reason - #setup_registry(paths.hklm, setup_path, session_info, - # credentials=credentials, lp=lp) - - message("Setting up templates db") - setup_templatesdb(paths.templates, setup_path, session_info=session_info, - credentials=credentials, lp=lp) - +def setup_samdb(path, setup_path, session_info, credentials, lp, + schemadn, configdn, domaindn, dnsdomain, realm, + netbiosname, message, hostname, rootdn, erase, + domainsid, aci, rdn_dc, domainguid, policyguid, + domainname, blank, adminpass, krbtgtpass, + machinepass, hostguid, invocationid, dnspass): # Also wipes the database message("Setting up sam.ldb") - samdb = SamDB(paths.samdb, session_info=session_info, + samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) message("Setting up sam.ldb partitions") setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn) - samdb = SamDB(paths.samdb, session_info=session_info, + samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) samdb.transaction_start() @@ -520,7 +391,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, samdb.transaction_commit() message("Pre-loading the Samba 4 and AD schema") - samdb = SamDB(paths.samdb, session_info=session_info, + samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(domainsid) load_schema(setup_path, samdb, schemadn, netbiosname, configdn) @@ -594,7 +465,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, "NETBIOSNAME": netbiosname, "DEFAULTSITE": DEFAULTSITE, "DNSDOMAIN": dnsdomain, - "DOMAIN": domain, + "DOMAIN": domainname, "SCHEMADN": schemadn, "DOMAINDN": domaindn, }) @@ -651,7 +522,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, "MACHINEPASS_B64": b64encode(machinepass), "DNSPASS_B64": b64encode(dnspass), "REALM": realm, - "DOMAIN": domain, + "DOMAIN": domainname, "HOSTGUID_ADD": hostguid_add, "DNSDOMAIN": dnsdomain}) setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { @@ -660,30 +531,6 @@ def provision(lp, setup_dir, message, blank, paths, session_info, "DOMAINSID": str(domainsid), "DOMAINDN": domaindn}) - os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}"), 0755) - os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "Machine"), 0755) - os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755) - if not os.path.isdir(paths.netlogon): - os.makedirs(paths.netlogon, 0755) - setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { - "MACHINEPASS_B64": b64encode(machinepass), - "DOMAIN": domain, - "REALM": realm, - "LDAPTIME": timestring(int(time.time())), - "DNSDOMAIN": dnsdomain, - "DOMAINSID": str(domainsid), - "SECRETS_KEYTAB": paths.keytab, - "NETBIOSNAME": netbiosname, - "SAM_LDB": paths.samdb, - "DNS_KEYTAB": paths.dns_keytab, - "DNSPASS_B64": b64encode(dnspass), - }) - - setup_name_mappings(samdb, str(domainsid), - domaindn, root=root, nobody=nobody, - nogroup=nogroup, wheel=wheel, users=users, - backup=backup) - message("Setting up sam.ldb index") samdb.load_ldif_file_add(setup_path("provision_index.ldif")) @@ -694,6 +541,177 @@ def provision(lp, setup_dir, message, blank, paths, session_info, raise samdb.transaction_commit() + return samdb + + +def provision(lp, setup_dir, message, blank, paths, session_info, + credentials, ldapbackend, realm=None, domain=None, hostname=None, + hostip=None, domainsid=None, hostguid=None, adminpass=None, + krbtgtpass=None, domainguid=None, policyguid=None, + invocationid=None, machinepass=None, dnspass=None, root=None, + nobody=None, nogroup=None, users=None, wheel=None, backup=None, + aci=None, serverrole=None): + """Provision samba4 + + :note: caution, this wipes all existing data! + """ + + def setup_path(file): + return os.path.join(setup_dir, file) + + erase = False + + if domainsid is None: + domainsid = security.random_sid() + if policyguid is None: + policyguid = uuid.random() + if invocationid is None: + invocationid = uuid.random() + if adminpass is None: + adminpass = misc.random_password(12) + if krbtgtpass is None: + krbtgtpass = misc.random_password(12) + if machinepass is None: + machinepass = misc.random_password(12) + if dnspass is None: + dnspass = misc.random_password(12) + if root is None: + root = findnss(pwd.getpwnam, "root")[4] + if nobody is None: + nobody = findnss(pwd.getpwnam, "nobody")[4] + if nogroup is None: + nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + if users is None: + users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", "usr")[2] + if wheel is None: + wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] + if backup is None: + backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] + if aci is None: + aci = "# no aci for local ldb" + if serverrole is None: + serverrole = lp.get("server role") + + if realm is None: + realm = lp.get("realm") + else: + if lp.get("realm").upper() != realm.upper(): + raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % + (lp.get("realm"), realm)) + + assert realm is not None + realm = realm.upper() + + if domain is None: + domain = lp.get("workgroup") + else: + if lp.get("workgroup").upper() != domain.upper(): + raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", + lp.get("workgroup"), domain) + + assert domain is not None + domain = domain.upper() + if not valid_netbios_name(domain): + raise InvalidNetbiosName(domain) + + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + if hostip is None: + hostip = gethostbyname(hostname) + + netbiosname = hostname.upper() + if not valid_netbios_name(netbiosname): + raise InvalidNetbiosName(netbiosname) + + dnsdomain = realm.lower() + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + rootdn = domaindn + configdn = "CN=Configuration," + rootdn + schemadn = "CN=Schema," + configdn + + rdn_dc = domaindn.split(",")[0][len("DC="):] + + message("set DOMAIN SID: %s" % str(domainsid)) + message("Provisioning for %s in realm %s" % (domain, realm)) + message("Using administrator password: %s" % adminpass) + + assert paths.smbconf is not None + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(paths.smbconf): + message("Setting up smb.conf") + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member": + smbconfsuffix = "member" + else: + assert "Invalid server role setting: %s" % serverrole + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { + "HOSTNAME": hostname, + "DOMAIN_CONF": domain, + "REALM_CONF": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": paths.netlogon, + "SYSVOLPATH": paths.sysvol, + }) + lp.reload() + + # only install a new shares config db if there is none + if not os.path.exists(paths.shareconf): + message("Setting up share.ldb") + share_ldb = Ldb(paths.shareconf, session_info=session_info, + credentials=credentials, lp=lp) + share_ldb.load_ldif_file_add(setup_path("share.ldif")) + + message("Setting up secrets.ldb") + secrets_ldb = setup_secretsdb(paths.secrets, setup_path, + session_info=session_info, + credentials=credentials, lp=lp) + + message("Setting up the registry") + # FIXME: Still fails for some reason + #setup_registry(paths.hklm, setup_path, session_info, + # credentials=credentials, lp=lp) + + message("Setting up templates db") + setup_templatesdb(paths.templates, setup_path, session_info=session_info, + credentials=credentials, lp=lp) + + samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials, + lp=lp, schemadn=schemadn, configdn=configdn, domaindn=domaindn, + dnsdomain=dnsdomain, netbiosname=netbiosname, realm=realm, message=message, + hostname=hostname, rootdn=rootdn, erase=erase, domainsid=domainsid, aci=aci, + rdn_dc=rdn_dc, domainguid=domainguid, policyguid=policyguid, + domainname=domain, blank=blank, adminpass=adminpass, krbtgtpass=krbtgtpass, + hostguid=hostguid, invocationid=invocationid, machinepass=machinepass, + dnspass=dnspass) + + if lp.get("server role") == "domain controller": + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}"), 0755) + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "Machine"), 0755) + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755) + if not os.path.isdir(paths.netlogon): + os.makedirs(paths.netlogon, 0755) + setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { + "MACHINEPASS_B64": b64encode(machinepass), + "DOMAIN": domain, + "REALM": realm, + "LDAPTIME": timestring(int(time.time())), + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), + "SECRETS_KEYTAB": paths.keytab, + "NETBIOSNAME": netbiosname, + "SAM_LDB": paths.samdb, + "DNS_KEYTAB": paths.dns_keytab, + "DNSPASS_B64": b64encode(dnspass), + }) + + if not blank: + setup_name_mappings(samdb, str(domainsid), + domaindn, root=root, nobody=nobody, + nogroup=nogroup, wheel=wheel, users=users, + backup=backup) message("Setting up phpLDAPadmin configuration") create_phplpapdadmin_config(paths.phpldapadminconfig, setup_path, paths.s4_ldapi_path) -- cgit From b7ffc3b404fbe3cf759e743c23e7bdbf75e71286 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 22 Dec 2007 02:26:38 -0600 Subject: r26562: Fix provisioning using Python. (This used to be commit b07ca944ba62a3f3de58c06b66533c0953a32de9) --- source4/scripting/python/samba/provision.py | 73 +++++++++++++++++------------ 1 file changed, 43 insertions(+), 30 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f516e73893..65094ecfac 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -354,6 +354,36 @@ def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn): }) +def setup_self_join(samdb, configdn, schemadn, domaindn, + netbiosname, hostname, dnsdomain, machinepass, dnspass, + realm, domainname, domainsid, invocationid, setup_path, + policyguid, hostguid=None): + if hostguid is not None: + hostguid_add = "objectGUID: %s" % hostguid + else: + hostguid_add = "" + + setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { + "CONFIGDN": configdn, + "SCHEMADN": schemadn, + "DOMAINDN": domaindn, + "INVOCATIONID": invocationid, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "DNSNAME": "%s.%s" % (hostname, dnsdomain), + "MACHINEPASS_B64": b64encode(machinepass), + "DNSPASS_B64": b64encode(dnspass), + "REALM": realm, + "DOMAIN": domainname, + "HOSTGUID_ADD": hostguid_add, + "DNSDOMAIN": dnsdomain}) + setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { + "POLICYGUID": policyguid, + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), + "DOMAINDN": domaindn}) + + def setup_samdb(path, setup_path, session_info, credentials, lp, schemadn, configdn, domaindn, dnsdomain, realm, netbiosname, message, hostname, rootdn, erase, @@ -506,30 +536,11 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, if lp.get("server role") == "domain controller": message("Setting up self join") - if hostguid is not None: - hostguid_add = "objectGUID: %s" % hostguid - else: - hostguid_add = "" - - setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { - "CONFIGDN": configdn, - "SCHEMADN": schemadn, - "DOMAINDN": domaindn, - "INVOCATIONID": invocationid, - "NETBIOSNAME": netbiosname, - "DEFAULTSITE": DEFAULTSITE, - "DNSNAME": "%s.%s" % (hostname, dnsdomain), - "MACHINEPASS_B64": b64encode(machinepass), - "DNSPASS_B64": b64encode(dnspass), - "REALM": realm, - "DOMAIN": domainname, - "HOSTGUID_ADD": hostguid_add, - "DNSDOMAIN": dnsdomain}) - setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { - "POLICYGUID": policyguid, - "DNSDOMAIN": dnsdomain, - "DOMAINSID": str(domainsid), - "DOMAINDN": domaindn}) + setup_self_join(samdb, configdn=configdn, schemadn=schemadn, domaindn=domaindn, + invocationid=invocationid, dnspass=dnspass, netbiosname=netbiosname, + dnsdomain=dnsdomain, realm=realm, machinepass=machinepass, + domainname=domainname, domainsid=domainsid, policyguid=policyguid, + hostname=hostname, hostguid=hostguid, setup_path=setup_path) message("Setting up sam.ldb index") samdb.load_ldif_file_add(setup_path("provision_index.ldif")) @@ -693,6 +704,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755) if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0755) + secrets_ldb = Ldb(paths.secrets, session_info=session_info, credentials=credentials, lp=lp) setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { "MACHINEPASS_B64": b64encode(machinepass), "DOMAIN": domain, @@ -728,12 +740,13 @@ def provision(lp, setup_dir, message, blank, paths, session_info, scope=SCOPE_SUBTREE) assert isinstance(hostguid, str) - message("Setting up DNS zone: %s" % dnsdomain) - create_zone_file(paths.dns, setup_path, samdb, - hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, - domaindn=domaindn, dnspass=dnspass, realm=realm, - domainguid=domainguid, hostguid=hostguid) - message("Please install the zone located in %s into your DNS server" % paths.dns) + if lp.get("server role") == "domain controller": + message("Setting up DNS zone: %s" % dnsdomain) + create_zone_file(paths.dns, setup_path, samdb, + hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, + domaindn=domaindn, dnspass=dnspass, realm=realm, + domainguid=domainguid, hostguid=hostguid) + message("Please install the zone located in %s into your DNS server" % paths.dns) def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path): setup_file(setup_path("phpldapadmin-config.php"), -- cgit From 09f820f0bd1a9fc7ffd171418ceb0e19df8e2e43 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 22 Dec 2007 05:02:57 -0600 Subject: r26564: More python bindings for registry code. (This used to be commit f40fad9827d0e9567224bc1e64ea91e610a07a3f) --- source4/scripting/python/samba/provision.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 65094ecfac..1d606d80e5 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -681,9 +681,8 @@ def provision(lp, setup_dir, message, blank, paths, session_info, credentials=credentials, lp=lp) message("Setting up the registry") - # FIXME: Still fails for some reason - #setup_registry(paths.hklm, setup_path, session_info, - # credentials=credentials, lp=lp) + setup_registry(paths.hklm, setup_path, session_info, + credentials=credentials, lp=lp) message("Setting up templates db") setup_templatesdb(paths.templates, setup_path, session_info=session_info, -- cgit From 249cc734cebfef31320ec10b05dbfaaaa39682ca Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 22 Dec 2007 05:03:02 -0600 Subject: r26565: Fix python registry bindings. 'PROVISION_PYTHON=yes make test' works now. (This used to be commit 485d1fa3d17fe6cc7a0ecd80e8bac42d173bbb19) --- source4/scripting/python/samba/provision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 1d606d80e5..b5fe3eba9e 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -281,12 +281,12 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp): def setup_registry(path, setup_path, session_info, credentials, lp): reg = registry.Registry() - hive = registry.Hive(path, session_info=session_info, + hive = registry.open_ldb(path, session_info=session_info, credentials=credentials, lp_ctx=lp) reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") provision_reg = setup_path("provision.reg") assert os.path.exists(provision_reg) - reg.apply_patchfile(provision_reg) + reg.diff_apply(provision_reg) def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, -- cgit From f053e385ff796914392d0eafa1e8756ff5ffdb18 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 22 Dec 2007 05:11:21 -0600 Subject: r26566: Fix member provision when using python. (This used to be commit e5573283df9e98bccc8eae227cf0f11367ecf084) --- source4/scripting/python/samba/provision.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index b5fe3eba9e..dcf567954a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -729,17 +729,17 @@ def provision(lp, setup_dir, message, blank, paths, session_info, message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) - samdb = SamDB(paths.samdb, session_info=session_info, - credentials=credentials, lp=lp) + if lp.get("server role") == "domain controller": + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) - domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID") - assert isinstance(domainguid, str) - hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID", - expression="(&(objectClass=computer)(cn=%s))" % hostname, - scope=SCOPE_SUBTREE) - assert isinstance(hostguid, str) + domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID") + assert isinstance(domainguid, str) + hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID", + expression="(&(objectClass=computer)(cn=%s))" % hostname, + scope=SCOPE_SUBTREE) + assert isinstance(hostguid, str) - if lp.get("server role") == "domain controller": message("Setting up DNS zone: %s" % dnsdomain) create_zone_file(paths.dns, setup_path, samdb, hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, -- cgit 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/__init__.py | 20 +- source4/scripting/python/samba/provision.py | 4 +- source4/scripting/python/samba/samba3.py | 224 +++++++++++++++++++++++ source4/scripting/python/samba/tests/__init__.py | 1 + source4/scripting/python/samba/tests/samba3.py | 57 ++++++ source4/scripting/python/samba/upgrade.py | 16 +- 6 files changed, 307 insertions(+), 15 deletions(-) create mode 100644 source4/scripting/python/samba/samba3.py create mode 100644 source4/scripting/python/samba/tests/samba3.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index c735361353..5b34534133 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -91,7 +91,14 @@ class Ldb(ldb.Ldb): def searchone(self, basedn, attribute, expression=None, scope=ldb.SCOPE_BASE): - """Search for one attribute as a string.""" + """Search for one attribute as a string. + + :param basedn: BaseDN for the search. + :param attribute: Name of the attribute + :param expression: Optional search expression. + :param scope: Search scope (defaults to base). + :return: Value of attribute as a string or None if it wasn't found. + """ res = self.search(basedn, scope, expression, [attribute]) if len(res) != 1 or res[0][attribute] is None: return None @@ -100,7 +107,7 @@ class Ldb(ldb.Ldb): return values.pop() def erase(self): - """Erase an ldb, removing all records.""" + """Erase this ldb, removing all records.""" # delete the specials for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: @@ -149,13 +156,18 @@ class Ldb(ldb.Ldb): :param ldif_path: Path to LDIF file. """ - self.load_ldif_add(open(ldif_path, 'r').read()) + self.add_ldif(open(ldif_path, 'r').read()) - def load_ldif_add(self, ldif): + def add_ldif(self, ldif): for changetype, msg in self.parse_ldif(ldif): assert changetype == ldb.CHANGETYPE_NONE self.add(msg) + def modify_ldif(self, ldif): + for (changetype, msg) in ldb.parse_ldif(data): + assert changetype == CHANGETYPE_MODIFY + ldb.modify(msg) + def substitute_var(text, values): """substitute strings of the form ${NAME} in str, replacing diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index dcf567954a..a4e6c6a214 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -111,9 +111,7 @@ def setup_modify_ldif(ldb, ldif_path, substvars=None): assert "${" not in data - for (changetype, msg) in ldb.parse_ldif(data): - assert changetype == CHANGETYPE_MODIFY - ldb.modify(msg) + ldb.modify_ldif(data) def setup_ldb(ldb, ldif_path, subst_vars): 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")) diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index e213c1cc1f..b01807c02f 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -43,6 +43,7 @@ class TestCaseInTempDir(unittest.TestCase): def tearDown(self): super(TestCaseInTempDir, self).tearDown() + # FIXME: Remove all files in self.tempdir class SubstituteVarTestCase(unittest.TestCase): diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py new file mode 100644 index 0000000000..c6b6281c60 --- /dev/null +++ b/source4/scripting/python/samba/tests/samba3.py @@ -0,0 +1,57 @@ +#!/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 . +# + +import unittest +from samba.samba3 import GroupMappingDatabase, Registry, PolicyDatabase +import os + +DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3") + +class RegistryTestCase(unittest.TestCase): + def setUp(self): + self.registry = Registry(os.path.join(DATADIR, "registry.tdb")) + + def test_length(self): + self.assertEquals(28, len(self.registry)) + + def test_keys(self): + self.assertEquals([], self.registry.keys()) + + +class PolicyTestCase(unittest.TestCase): + def setUp(self): + self.policy = PolicyDatabase(os.path.join(DATADIR, "account_policy.tdb")) + + def test_policy(self): + self.assertEquals(self.policy.min_password_length, 5) + self.assertEquals(self.policy.minimum_password_age, 0) + self.assertEquals(self.policy.maximum_password_age, 999999999) + self.assertEquals(self.policy.refuse_machine_password_change, 0) + self.assertEquals(self.policy.reset_count_minutes, 0) + self.assertEquals(self.policy.disconnect_time, -1) + self.assertEquals(self.policy.user_must_logon_to_change_password, 0) + self.assertEquals(self.policy.password_history, 0) + self.assertEquals(self.policy.lockout_duration, 0) + self.assertEquals(self.policy.bad_lockout_minutes, 0) + + +class GroupsTestCase(unittest.TestCase): + def setUp(self): + self.groupdb = GroupMappingDatabase(os.path.join(DATADIR, "group_mapping.tdb")) + diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 1c27f8ec25..3168fedf2d 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -7,7 +7,7 @@ """Support code for upgrading from Samba 3 to Samba 4.""" -from provision import findnss +from provision import findnss, provision import provision import grp import pwd @@ -69,7 +69,7 @@ data:: %s""" % (keydn, rv.name, rv.name, rv.type, ldb.encode(rv.data)) return ldif -def upgrade_sam_policy(samba3,dn): +def upgrade_sam_policy(policy,dn): ldif = """ dn: %s changetype: modify @@ -84,11 +84,11 @@ samba3UserMustLogonToChangePassword: %d samba3BadLockoutMinutes: %d samba3DisconnectTime: %d -""" % (dn, samba3.policy.min_password_length, - samba3.policy.password_history, samba3.policy.minimum_password_age, - samba3.policy.maximum_password_age, samba3.policy.lockout_duration, - samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password, - samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time) +""" % (dn, policy.min_password_length, + policy.password_history, policy.minimum_password_age, + policy.maximum_password_age, policy.lockout_duration, + policy.reset_count_minutes, policy.user_must_logon_to_change_password, + policy.bad_lockout_minutes, policy.disconnect_time) return ldif @@ -465,7 +465,7 @@ replace: type type: 4 replace: data data: %d -""" % samba3.policy.refuse_machine_password_change) +""" % policy.refuse_machine_password_change) message("Importing users") for account in samba3.samaccounts: -- 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 ++++++++++++++------------ source4/scripting/python/samba/tests/samba3.py | 10 ++++-- 2 files changed, 30 insertions(+), 22 deletions(-) (limited to 'source4/scripting/python/samba') 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: diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py index c6b6281c60..0d56ca9117 100644 --- a/source4/scripting/python/samba/tests/samba3.py +++ b/source4/scripting/python/samba/tests/samba3.py @@ -22,16 +22,20 @@ from samba.samba3 import GroupMappingDatabase, Registry, PolicyDatabase import os DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3") +print "Samba 3 data dir: %s" % DATADIR class RegistryTestCase(unittest.TestCase): def setUp(self): self.registry = Registry(os.path.join(DATADIR, "registry.tdb")) + def tearDown(self): + self.registry.close() + def test_length(self): self.assertEquals(28, len(self.registry)) def test_keys(self): - self.assertEquals([], self.registry.keys()) + self.assertTrue("HKLM" in self.registry.keys()) class PolicyTestCase(unittest.TestCase): @@ -45,10 +49,10 @@ class PolicyTestCase(unittest.TestCase): self.assertEquals(self.policy.refuse_machine_password_change, 0) self.assertEquals(self.policy.reset_count_minutes, 0) self.assertEquals(self.policy.disconnect_time, -1) - self.assertEquals(self.policy.user_must_logon_to_change_password, 0) + self.assertEquals(self.policy.user_must_logon_to_change_password, None) self.assertEquals(self.policy.password_history, 0) self.assertEquals(self.policy.lockout_duration, 0) - self.assertEquals(self.policy.bad_lockout_minutes, 0) + self.assertEquals(self.policy.bad_lockout_minutes, None) class GroupsTestCase(unittest.TestCase): -- 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 ++++++++++++++++++++----- source4/scripting/python/samba/tests/samba3.py | 55 ++++++++- source4/scripting/python/samba/upgrade.py | 21 ++-- 3 files changed, 196 insertions(+), 40 deletions(-) (limited to 'source4/scripting/python/samba') 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): diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py index 0d56ca9117..92d11d11d4 100644 --- a/source4/scripting/python/samba/tests/samba3.py +++ b/source4/scripting/python/samba/tests/samba3.py @@ -18,7 +18,8 @@ # import unittest -from samba.samba3 import GroupMappingDatabase, Registry, PolicyDatabase +from samba.samba3 import (GroupMappingDatabase, Registry, PolicyDatabase, SecretsDatabase, TdbSam, + WinsDatabase) import os DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3") @@ -59,3 +60,55 @@ class GroupsTestCase(unittest.TestCase): def setUp(self): self.groupdb = GroupMappingDatabase(os.path.join(DATADIR, "group_mapping.tdb")) + def tearDown(self): + self.groupdb.close() + + def test_group_length(self): + self.assertEquals(13, len(list(self.groupdb.groupsids()))) + + def test_groupsids(self): + sids = list(self.groupdb.groupsids()) + self.assertTrue("S-1-5-32-544" in sids) + + def test_alias_length(self): + self.assertEquals(0, len(list(self.groupdb.aliases()))) + + +class SecretsDbTestCase(unittest.TestCase): + def setUp(self): + self.secretsdb = SecretsDatabase(os.path.join(DATADIR, "secrets.tdb")) + + def tearDown(self): + self.secretsdb.close() + + def test_get_sid(self): + self.assertTrue(self.secretsdb.get_sid("BEDWYR") is not None) + + +class TdbSamTestCase(unittest.TestCase): + def setUp(self): + self.samdb = TdbSam(os.path.join(DATADIR, "passdb.tdb")) + + def tearDown(self): + self.samdb.close() + + def test_usernames(self): + self.assertEquals(3, len(list(self.samdb.usernames()))) + + +class WinsDatabaseTestCase(unittest.TestCase): + def setUp(self): + self.winsdb = WinsDatabase(os.path.join(DATADIR, "wins.dat")) + + def test_length(self): + self.assertEquals(22, len(self.winsdb)) + + def test_first_entry(self): + self.assertEqual((1124185120, ["192.168.1.5"], "64R"), self.winsdb["ADMINISTRATOR#03"]) + + def tearDown(self): + self.winsdb.close() + +# FIXME: smbpasswd +# FIXME: idmapdb +# FIXME: Shares diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 3168fedf2d..4f2ab46ef0 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -530,14 +530,7 @@ data: %d if ldapurl is not None: message("Enabling Samba3 LDAP mappings for SAM database") - samdb.modify(""" -dn: @MODULES -changetype: modify -replace: @LIST -@LIST: samldb,operational,objectguid,rdn_name,samba3sam -""") - - samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl}) + enable_samba3sam(samdb) return ret @@ -551,3 +544,15 @@ def upgrade_verify(subobj, samba3, paths, message): assert(len(msg) >= 1) # FIXME + + + +def enable_samba3sam(samdb): + samdb.modify(""" +dn: @MODULES +changetype: modify +replace: @LIST +@LIST: samldb,operational,objectguid,rdn_name,samba3sam +""") + + samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl}) -- 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 ++++++++++++++++++++++++-- source4/scripting/python/samba/tests/samba3.py | 53 ++++++++++++-- 2 files changed, 140 insertions(+), 9 deletions(-) (limited to 'source4/scripting/python/samba') 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" diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py index 92d11d11d4..580bcfa3c2 100644 --- a/source4/scripting/python/samba/tests/samba3.py +++ b/source4/scripting/python/samba/tests/samba3.py @@ -19,7 +19,7 @@ import unittest from samba.samba3 import (GroupMappingDatabase, Registry, PolicyDatabase, SecretsDatabase, TdbSam, - WinsDatabase) + WinsDatabase, SmbpasswdFile, ACB_NORMAL, IdmapDatabase) import os DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3") @@ -109,6 +109,51 @@ class WinsDatabaseTestCase(unittest.TestCase): def tearDown(self): self.winsdb.close() -# FIXME: smbpasswd -# FIXME: idmapdb -# FIXME: Shares +class SmbpasswdTestCase(unittest.TestCase): + def setUp(self): + self.samdb = SmbpasswdFile(os.path.join(DATADIR, "smbpasswd")) + + def test_length(self): + self.assertEquals(3, len(self.samdb)) + + def test_get_user(self): + self.assertEquals((0, "552902031BEDE9EFAAD3B435B51404EE", "878D8014606CDA29677A44EFA1353FC7", ACB_NORMAL, int(1125418267)), self.samdb["rootpw"]) + + def tearDown(self): + self.samdb.close() + + +class IdmapDbTestCase(unittest.TestCase): + def setUp(self): + self.idmapdb = IdmapDatabase(os.path.join(DATADIR, "winbindd_idmap.tdb")) + + def test_user_hwm(self): + self.assertEquals(10000, self.idmapdb.get_user_hwm()) + + def test_group_hwm(self): + self.assertEquals(10002, self.idmapdb.get_group_hwm()) + + def test_uids(self): + self.assertEquals(1, len(list(self.idmapdb.uids()))) + + def test_gids(self): + self.assertEquals(3, len(list(self.idmapdb.gids()))) + + def test_get_user_sid(self): + self.assertEquals("S-1-5-21-58189338-3053988021-627566699-501", self.idmapdb.get_user_sid(65534)) + + def test_get_group_sid(self): + self.assertEquals("S-1-5-21-2447931902-1787058256-3961074038-3007", self.idmapdb.get_group_sid(10001)) + + def tearDown(self): + self.idmapdb.close() + + +class ShareInfoTestCase(unittest.TestCase): + def setUp(self): + self.shareinfodb = ShareInfoDatabase(os.path.join(DATADIR, "share_info.tdb")) + + # FIXME: needs proper data so it can be tested + + def tearDown(self): + self.shareinfodb.close() -- 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 +++++++++++++++++++++++-------- source4/scripting/python/samba/upgrade.py | 4 +-- 2 files changed, 32 insertions(+), 14 deletions(-) (limited to 'source4/scripting/python/samba') 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")) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 4f2ab46ef0..375c39eb5a 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -447,7 +447,6 @@ def upgrade_smbconf(oldconf,mark): def upgrade(subobj, samba3, message, paths, session_info, credentials): ret = 0 - lp = loadparm_init() samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) message("Writing configuration") @@ -455,8 +454,7 @@ def upgrade(subobj, samba3, message, paths, session_info, credentials): newconf.save(paths.smbconf) message("Importing account policies") - ldif = upgrade_sam_policy(samba3,subobj.BASEDN) - samdb.modify(ldif) + samdb.modify_ldif(upgrade_sam_policy(samba3,subobj.BASEDN)) regdb = Ldb(paths.hklm) regdb.modify(""" -- 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') 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 +- source4/scripting/python/samba/tests/__init__.py | 2 +- source4/scripting/python/samba/upgrade.py | 94 ++++++++---------------- 3 files changed, 33 insertions(+), 65 deletions(-) (limited to 'source4/scripting/python/samba') 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): diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index b01807c02f..5885a3b507 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -43,7 +43,7 @@ class TestCaseInTempDir(unittest.TestCase): def tearDown(self): super(TestCaseInTempDir, self).tearDown() - # FIXME: Remove all files in self.tempdir + os.rmdir(self.tempdir) class SubstituteVarTestCase(unittest.TestCase): diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 375c39eb5a..c13351bc63 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -255,68 +255,44 @@ maxVersion: %llu return ldif -def upgrade_provision(lp, samba3): - domainname = samba3.configuration.get("workgroup") +def upgrade_provision(samba3, setup_dir, message, credentials, session_info, paths): + oldconf = samba3.get_conf() + + if oldconf.get("domain logons") == "True": + serverrole = "domain controller" + else: + if oldconf.get("security") == "user": + serverrole = "standalone" + else: + serverrole = "member server" + + domainname = oldconf.get("workgroup") + realm = oldconf.get("realm") + netbiosname = oldconf.get("netbios name") + + secrets_db = samba3.get_secrets_db() if domainname is None: - domainname = samba3.secrets.domains[0].name - print "No domain specified in smb.conf file, assuming '%s'\n" % domainname + domainname = secrets_db.domains()[0] + message("No domain specified in smb.conf file, assuming '%s'" % domainname) - domsec = samba3.find_domainsecrets(domainname) - hostsec = samba3.find_domainsecrets(hostname()) - realm = samba3.configuration.get("realm") - if realm is None: - realm = domainname - print "No realm specified in smb.conf file, assuming '%s'\n" % realm - random_init(local) + realm = domainname.lower() + message("No realm specified in smb.conf file, assuming '%s'\n" % realm) - subobj.realm = realm - subobj.domain = domainname - - if domsec is not None: - subobj.DOMAINGUID = domsec.guid - subobj.DOMAINSID = domsec.sid + domainguid = secrets_db.get_domain_guid(domainname) + domainsid = secrets_db.get_sid(domainsid) + if domainsid is None: + message("Can't find domain secrets for '%s'; using random SID\n" % domainname) + + if netbiosname is not None: + machinepass = secrets_db.get_machine_password(netbiosname) else: - print "Can't find domain secrets for '%s'; using random SID and GUID\n" % domainname - subobj.DOMAINGUID = uuid.random() - subobj.DOMAINSID = randsid() + netbiosname = None - if hostsec: - hostguid = hostsec.guid - subobj.krbtgtpass = randpass(12) - subobj.machinepass = randpass(12) - subobj.adminpass = randpass(12) - subobj.datestring = datestring() - subobj.root = findnss(pwd.getpwnam, "root")[4] - subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] - subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] - subobj.wheel = findnss(grp.getgrnam, "wheel", "root")[2] - subobj.users = findnss(grp.getgrnam, "users", "guest", "other")[2] - subobj.dnsdomain = subobj.realm.lower() - subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) - subobj.basedn = "DC=" + ",DC=".join(subobj.realm.split(".")) - rdn_list = subobj.dnsdomain.split(".") - subobj.domaindn = "DC=" + ",DC=".join(rdn_list) - subobj.domaindn_ldb = "users.ldb" - subobj.rootdn = subobj.domaindn - - modules_list = ["rootdse", - "kludge_acl", - "paged_results", - "server_sort", - "extended_dn", - "asq", - "samldb", - "password_hash", - "operational", - "objectclass", - "rdn_name", - "show_deleted", - "partition"] - subobj.modules_list = ",".join(modules_list) - - return subobj + provision(lp, setup_dir, message, blank=True, paths=path, session_info=session_info, + credentials=credentials, realm=realm, domain=domainname, + domainsid=domainsid, domainguid=domainguid, machinepass=machinepass, serverrole=serverrole) smbconf_keep = [ "dos charset", @@ -435,14 +411,6 @@ def upgrade_smbconf(oldconf,mark): elif mark: newconf.set(s, "samba3:"+p, oldconf.get(s,p)) - if oldconf.get("domain logons") == "True": - newconf.set("server role", "domain controller") - else: - if oldconf.get("security") == "user": - newconf.set("server role", "standalone") - else: - newconf.set("server role", "member server") - return newconf def upgrade(subobj, samba3, message, paths, session_info, credentials): -- cgit From 533cc583ed20efdfd6bee60f86d16fef3942898b Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 25 Dec 2007 16:36:44 -0600 Subject: r26596: Fixed upgrade.py. Added blackbox tests for provision and upgrade Python scripts. Clean up temporary files created by the Python tests. (This used to be commit 2227fb6df62240cae64d27a1920d878316f819fc) --- source4/scripting/python/samba/__init__.py | 6 +++--- source4/scripting/python/samba/provision.py | 6 +++--- source4/scripting/python/samba/tests/__init__.py | 11 +++++++--- source4/scripting/python/samba/tests/provision.py | 10 ++++++--- source4/scripting/python/samba/upgrade.py | 26 ++++++++--------------- 5 files changed, 30 insertions(+), 29 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 5b34534133..359457d815 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -164,9 +164,9 @@ class Ldb(ldb.Ldb): self.add(msg) def modify_ldif(self, ldif): - for (changetype, msg) in ldb.parse_ldif(data): - assert changetype == CHANGETYPE_MODIFY - ldb.modify(msg) + for (changetype, msg) in self.parse_ldif(ldif): + assert changetype == ldb.CHANGETYPE_MODIFY + self.modify(msg) def substitute_var(text, values): diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index a4e6c6a214..c4a3bb7fd6 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -95,7 +95,7 @@ def setup_add_ldif(ldb, ldif_path, subst_vars=None): assert "${" not in data - ldb.load_ldif_add(data) + ldb.add_ldif(data) def setup_modify_ldif(ldb, ldif_path, substvars=None): @@ -140,7 +140,7 @@ def setup_file(template, fname, substvars): open(f, 'w').write(data) -def provision_default_paths(lp, dnsdomain): +def provision_paths_from_lp(lp, dnsdomain): """Set the default paths for provisioning. :param lp: Loadparm context. @@ -605,7 +605,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, realm = lp.get("realm") else: if lp.get("realm").upper() != realm.upper(): - raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % + raise Exception("realm '%s' in smb.conf must match chosen realm '%s'\n" % (lp.get("realm"), realm)) assert realm is not None diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index 5885a3b507..5e1ff87c2b 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -67,7 +67,12 @@ class SubstituteVarTestCase(unittest.TestCase): class LdbExtensionTests(TestCaseInTempDir): def test_searchone(self): - l = samba.Ldb(self.tempdir + "/searchone.ldb") - l.add({"dn": "foo=dc", "bar": "bla"}) - self.assertEquals("bla", l.searchone(ldb.Dn(l, "foo=dc"), "bar")) + path = self.tempdir + "/searchone.ldb" + l = samba.Ldb(path) + try: + l.add({"dn": "foo=dc", "bar": "bla"}) + self.assertEquals("bla", l.searchone(ldb.Dn(l, "foo=dc"), "bar")) + finally: + del l + os.unlink(path) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index bf7182dbd3..f5a0339c1f 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -29,10 +29,14 @@ def setup_path(file): class ProvisionTestCase(samba.tests.TestCaseInTempDir): def test_setup_secretsdb(self): - ldb = setup_secretsdb(os.path.join(self.tempdir, "secrets.ldb"), - setup_path, None, None, None) - self.assertEquals("LSA Secrets", + path = os.path.join(self.tempdir, "secrets.ldb") + ldb = setup_secretsdb(path, setup_path, None, None, None) + try: + self.assertEquals("LSA Secrets", ldb.searchone(Dn(ldb, "CN=LSA Secrets"), "CN")) + finally: + del ldb + os.unlink(path) class Disabled: diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index c13351bc63..05a63d9326 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -8,7 +8,6 @@ """Support code for upgrading from Samba 3 to Samba 4.""" from provision import findnss, provision -import provision import grp import pwd import uuid @@ -255,7 +254,7 @@ maxVersion: %llu return ldif -def upgrade_provision(samba3, setup_dir, message, credentials, session_info, paths): +def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, paths): oldconf = samba3.get_conf() if oldconf.get("domain logons") == "True": @@ -266,7 +265,11 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, pat else: serverrole = "member server" + lp.set("server role", serverrole) domainname = oldconf.get("workgroup") + if domainname: + domainname = str(domainname) + lp.set("workgroup", domainname) realm = oldconf.get("realm") netbiosname = oldconf.get("netbios name") @@ -279,18 +282,19 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, pat if realm is None: realm = domainname.lower() message("No realm specified in smb.conf file, assuming '%s'\n" % realm) + lp.set("realm", realm) domainguid = secrets_db.get_domain_guid(domainname) - domainsid = secrets_db.get_sid(domainsid) + domainsid = secrets_db.get_sid(domainname) if domainsid is None: message("Can't find domain secrets for '%s'; using random SID\n" % domainname) if netbiosname is not None: machinepass = secrets_db.get_machine_password(netbiosname) else: - netbiosname = None + machinepass = None - provision(lp, setup_dir, message, blank=True, paths=path, session_info=session_info, + provision(lp=lp, setup_dir=setup_dir, message=message, blank=True, ldapbackend=None, paths=paths, session_info=session_info, credentials=credentials, realm=realm, domain=domainname, domainsid=domainsid, domainguid=domainguid, machinepass=machinepass, serverrole=serverrole) @@ -500,18 +504,6 @@ data: %d return ret -def upgrade_verify(subobj, samba3, paths, message): - message("Verifying account policies") - - samldb = Ldb(paths.samdb) - - for account in samba3.samaccounts: - msg = samldb.search("(&(sAMAccountName=" + account.nt_username + ")(objectclass=user))") - assert(len(msg) >= 1) - - # FIXME - - def enable_samba3sam(samdb): samdb.modify(""" -- 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 +++- source4/scripting/python/samba/tests/samba3.py | 8 ++ source4/scripting/python/samba/upgrade.py | 188 +++++++++---------------- 3 files changed, 102 insertions(+), 122 deletions(-) (limited to 'source4/scripting/python/samba') 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(" 1: + elif type & 0x80: + if len(ips) > 1: rType = 0x2 else: rType = 0x1 else: - if numIPs > 1: + if len(ips) > 1: rType = 0x3 else: rType = 0x0 - if ttl > now: + if ttl > time.time(): rState = 0x0 # active else: rState = 0x1 # released - nType = ((e.nb_flags & 0x60)>>5) - - ldif += """ -dn: name=%s,type=0x%02X -type: 0x%02X -name: %s -objectClass: winsRecord -recordType: %u -recordState: %u -nodeType: %u -isStatic: 0 -expireTime: %s -versionID: %llu -""" % (e.name, e.type, e.type, e.name, - rType, rState, nType, - ldaptime(ttl), version_id) - - for ip in e.ips: - ldif += "address: %s\n" % ip - - ldif += """ -dn: CN=VERSION -objectClass: winsMaxVersion -maxVersion: %llu -""" % version_id + nType = ((nb_flags & 0x60)>>5) - return ldif + samba4_winsdb.add({"dn": "name=%s,type=0x%s" % name.split("#"), + "type": name.split("#")[1], + "name": name.split("#")[0], + "objectClass": "winsRecord", + "recordType": str(rType), + "recordState": str(rState), + "nodeType": str(nType), + "expireTime": ldb.ldaptime(ttl), + "isStatic": "0", + "versionID": str(version_id), + "address": ips}) + + samba4_winsdb.add({"dn": "CN=VERSION", + "objectClass": "winsMaxVersion", + "maxVersion": str(version_id)}) def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, paths): oldconf = samba3.get_conf() @@ -417,6 +360,30 @@ def upgrade_smbconf(oldconf,mark): return newconf +SAMBA3_PREDEF_NAMES = { + 'HKLM': registry.HKEY_LOCAL_MACHINE, +} + +def import_registry(samba4_registry, samba3_regdb): + """Import a Samba 3 registry database into the Samba 4 registry. + + :param samba4_registry: Samba 4 registry handle. + :param samba3_regdb: Samba 3 registry database handle. + """ + def ensure_key_exists(keypath): + (predef_name, keypath) = keypath.split("/", 1) + predef_id = SAMBA3_PREDEF_NAMES[predef_name] + keypath = keypath.replace("/", "\\") + return samba4_registry.create_key(predef_id, keypath) + + for key in samba3_regdb.keys(): + key_handle = ensure_key_exists(key) + for subkey in samba3_regdb.subkeys(key): + ensure_key_exists(subkey) + for (value_name, (value_type, value_data)) in samba3_regdb.values(key).items(): + key_handle.set_value(value_name, value_type, value_data) + + def upgrade(subobj, samba3, message, paths, session_info, credentials): ret = 0 samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) @@ -462,21 +429,6 @@ data: %d ret += 1 message(msg) - message("Importing registry data") - for hive in ["hkcr","hkcu","hklm","hkpd","hku","hkpt"]: - message("... " + hive) - regdb = Ldb(paths[hive]) - ldif = upgrade_registry(samba3.registry, hive, regdb) - for j in ldif: - msg = "... ... " + j - try: - regdb.add(ldif[j]) - except LdbError, e: - # FIXME: Ignore 'Record exists' errors - msg += "... error: " + str(e) - ret += 1 - message(msg) - message("Importing WINS data") winsdb = Ldb(paths.winsdb) ldb_erase(winsdb) -- cgit From 222262b54e74a01a66b3cbbea5502d4ce488905d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij 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/provision.py | 2 + source4/scripting/python/samba/samba3.py | 165 +++++++++++++-- source4/scripting/python/samba/tests/samba3.py | 20 +- source4/scripting/python/samba/tests/upgrade.py | 8 +- source4/scripting/python/samba/upgrade.py | 260 +++++++++++++----------- 5 files changed, 307 insertions(+), 148 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index c4a3bb7fd6..53eb1d618f 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -745,6 +745,8 @@ def provision(lp, setup_dir, message, blank, paths, session_info, domainguid=domainguid, hostguid=hostguid) message("Please install the zone located in %s into your DNS server" % paths.dns) + return domaindn + def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path): setup_file(setup_path("phpldapadmin-config.php"), path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")}) 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]) diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py index e25562929a..22b21ba1b4 100644 --- a/source4/scripting/python/samba/tests/samba3.py +++ b/source4/scripting/python/samba/tests/samba3.py @@ -19,7 +19,7 @@ import unittest from samba.samba3 import (GroupMappingDatabase, Registry, PolicyDatabase, SecretsDatabase, TdbSam, - WinsDatabase, SmbpasswdFile, ACB_NORMAL, IdmapDatabase) + WinsDatabase, SmbpasswdFile, ACB_NORMAL, IdmapDatabase, SAMUser) import os DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3") @@ -74,6 +74,9 @@ class GroupsTestCase(unittest.TestCase): def test_group_length(self): self.assertEquals(13, len(list(self.groupdb.groupsids()))) + def test_get_group(self): + self.assertEquals((-1, 5L, 'Administrators', ''), self.groupdb.get_group("S-1-5-32-544")) + def test_groupsids(self): sids = list(self.groupdb.groupsids()) self.assertTrue("S-1-5-32-544" in sids) @@ -103,6 +106,11 @@ class TdbSamTestCase(unittest.TestCase): def test_usernames(self): self.assertEquals(3, len(list(self.samdb.usernames()))) + def test_getuser(self): + return + user = SAMUser("root") + self.assertEquals(user, self.samdb["root"]) + class WinsDatabaseTestCase(unittest.TestCase): def setUp(self): @@ -112,7 +120,7 @@ class WinsDatabaseTestCase(unittest.TestCase): self.assertEquals(22, len(self.winsdb)) def test_first_entry(self): - self.assertEqual((1124185120, ["192.168.1.5"], "64R"), self.winsdb["ADMINISTRATOR#03"]) + self.assertEqual((1124185120, ["192.168.1.5"], 0x64), self.winsdb["ADMINISTRATOR#03"]) def tearDown(self): self.winsdb.close() @@ -125,7 +133,13 @@ class SmbpasswdTestCase(unittest.TestCase): self.assertEquals(3, len(self.samdb)) def test_get_user(self): - self.assertEquals((0, "552902031BEDE9EFAAD3B435B51404EE", "878D8014606CDA29677A44EFA1353FC7", ACB_NORMAL, int(1125418267)), self.samdb["rootpw"]) + user = SAMUser("rootpw") + user.lm_password = "552902031BEDE9EFAAD3B435B51404EE" + user.nt_password = "878D8014606CDA29677A44EFA1353FC7" + user.acct_ctrl = ACB_NORMAL + user.pass_last_set_time = int(1125418267) + user.uid = 0 + self.assertEquals(user, self.samdb["rootpw"]) def tearDown(self): self.samdb.close() diff --git a/source4/scripting/python/samba/tests/upgrade.py b/source4/scripting/python/samba/tests/upgrade.py index a25743425b..ddafa00691 100644 --- a/source4/scripting/python/samba/tests/upgrade.py +++ b/source4/scripting/python/samba/tests/upgrade.py @@ -17,12 +17,6 @@ # along with this program. If not, see . # -from samba.upgrade import regkey_to_dn +import samba.upgrade from unittest import TestCase -class RegkeyDnTests(TestCase): - def test_empty(self): - self.assertEquals("hive=NONE", regkey_to_dn("")) - - def test_nested(self): - self.assertEquals("key=bar,key=foo,hive=NONE", regkey_to_dn("foo/bar")) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index a6bd07df58..3ecfe872f9 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -9,20 +9,15 @@ from provision import findnss, provision import grp +import ldb import pwd import uuid import registry +from samba import Ldb +from samba.samdb import SamDB -# Where prefix is any of: -# - HKLM -# HKU -# HKCR -# HKPD -# HKPT -# - -def upgrade_sam_policy(policy,dn): - ldif = """ +def import_sam_policy(samldb, samba3_policy, domaindn): + samldb.modify_ldif(""" dn: %s changetype: modify replace: minPwdLength @@ -40,19 +35,24 @@ samba3DisconnectTime: %d policy.password_history, policy.minimum_password_age, policy.maximum_password_age, policy.lockout_duration, policy.reset_count_minutes, policy.user_must_logon_to_change_password, - policy.bad_lockout_minutes, policy.disconnect_time) - - return ldif + policy.bad_lockout_minutes, policy.disconnect_time)) + -def upgrade_sam_account(ldb,acc,domaindn,domainsid): - """Upgrade a SAM account.""" +def import_sam_account(samldb,acc,domaindn,domainsid): + """Import a Samba 3 SAM account. + + :param samldb: Samba 4 SAM Database handle + :param acc: Samba 3 account + :param domaindn: Domain DN + :param domainsid: Domain SID.""" if acc.nt_username is None or acc.nt_username == "": acc.nt_username = acc.username if acc.fullname is None: - acc.fullname = pwd.getpwnam(acc.fullname)[4] - - acc.fullname = acc.fullname.split(",")[0] + try: + acc.fullname = pwd.getpwnam(acc.username)[4].split(",")[0] + except KeyError: + pass if acc.fullname is None: acc.fullname = acc.username @@ -60,105 +60,113 @@ def upgrade_sam_account(ldb,acc,domaindn,domainsid): assert acc.fullname is not None assert acc.nt_username is not None - ldif = """dn: cn=%s,%s -objectClass: top -objectClass: user -lastLogon: %d -lastLogoff: %d -unixName: %s -sAMAccountName: %s -cn: %s -description: %s -primaryGroupID: %d -badPwdcount: %d -logonCount: %d -samba3Domain: %s -samba3DirDrive: %s -samba3MungedDial: %s -samba3Homedir: %s -samba3LogonScript: %s -samba3ProfilePath: %s -samba3Workstations: %s -samba3KickOffTime: %d -samba3BadPwdTime: %d -samba3PassLastSetTime: %d -samba3PassCanChangeTime: %d -samba3PassMustChangeTime: %d -objectSid: %s-%d -lmPwdHash:: %s -ntPwdHash:: %s - -""" % (ldb.dn_escape(acc.fullname), domaindn, acc.logon_time, acc.logoff_time, acc.username, acc.nt_username, acc.nt_username, -acc.acct_desc, acc.group_rid, acc.bad_password_count, acc.logon_count, -acc.domain, acc.dir_drive, acc.munged_dial, acc.homedir, acc.logon_script, -acc.profile_path, acc.workstations, acc.kickoff_time, acc.bad_password_time, -acc.pass_last_set_time, acc.pass_can_change_time, acc.pass_must_change_time, domainsid, acc.user_rid, - ldb.encode(acc.lm_pw), ldb.encode(acc.nt_pw)) - - return ldif - -def upgrade_sam_group(group,domaindn): - """Upgrade a SAM group.""" - if group.sid_name_use == 5: # Well-known group + samldb.add({ + "dn": "cn=%s,%s" % (acc.fullname, domaindn), + "objectClass": ["top", "user"], + "lastLogon": str(acc.logon_time), + "lastLogoff": str(acc.logoff_time), + "unixName": acc.username, + "sAMAccountName": acc.nt_username, + "cn": acc.nt_username, + "description": acc.acct_desc, + "primaryGroupID": str(acc.group_rid), + "badPwdcount": str(acc.bad_password_count), + "logonCount": str(acc.logon_count), + "samba3Domain": acc.domain, + "samba3DirDrive": acc.dir_drive, + "samba3MungedDial": acc.munged_dial, + "samba3Homedir": acc.homedir, + "samba3LogonScript": acc.logon_script, + "samba3ProfilePath": acc.profile_path, + "samba3Workstations": acc.workstations, + "samba3KickOffTime": str(acc.kickoff_time), + "samba3BadPwdTime": str(acc.bad_password_time), + "samba3PassLastSetTime": str(acc.pass_last_set_time), + "samba3PassCanChangeTime": str(acc.pass_can_change_time), + "samba3PassMustChangeTime": str(acc.pass_must_change_time), + "objectSid": "%s-%d" % (domainsid, acc.user_rid), + "lmPwdHash:": acc.lm_password, + "ntPwdHash:": acc.nt_password, + }) + + +def import_sam_group(samldb, sid, gid, sid_name_use, nt_name, comment, domaindn): + """Upgrade a SAM group. + + :param samldb: SAM database. + :param gid: Group GID + :param sid_name_use: SID name use + :param nt_name: NT Group Name + :param comment: NT Group Comment + :param domaindn: Domain DN + """ + + if sid_name_use == 5: # Well-known group return None - if group.nt_name in ("Domain Guests", "Domain Users", "Domain Admins"): + if nt_name in ("Domain Guests", "Domain Users", "Domain Admins"): return None - if group.gid == -1: - gr = grp.getgrnam(grp.nt_name) + if gid == -1: + gr = grp.getgrnam(nt_name) else: - gr = grp.getgrgid(grp.gid) + gr = grp.getgrgid(gid) if gr is None: - group.unixname = "UNKNOWN" + unixname = "UNKNOWN" else: - group.unixname = gr.gr_name + unixname = gr.gr_name - assert group.unixname is not None + assert unixname is not None - ldif = """dn: cn=%s,%s -objectClass: top -objectClass: group -description: %s -cn: %s -objectSid: %s -unixName: %s -samba3SidNameUse: %d -""" % (group.nt_name, domaindn, -group.comment, group.nt_name, group.sid, group.unixname, group.sid_name_use) - - return ldif - -def import_idmap(samba4_idmap,samba3_idmap,domaindn): - samba4_idmap.add({ + samldb.add({ + "dn": "cn=%s,%s" % (nt_name, domaindn), + "objectClass": ["top", "group"], + "description": comment, + "cn": nt_name, + "objectSid": sid, + "unixName": unixname, + "samba3SidNameUse": str(sid_name_use) + }) + + +def import_idmap(samdb,samba3_idmap,domaindn): + """Import idmap data. + + :param samdb: SamDB handle. + :param samba3_idmap: Samba 3 IDMAP database to import from + :param domaindn: Domain DN. + """ + samdb.add({ "dn": domaindn, "userHwm": str(samba3_idmap.get_user_hwm()), "groupHwm": str(samba3_idmap.get_group_hwm())}) for uid in samba3_idmap.uids(): - samba4_idmap.add({"dn": "SID=%s,%s" % (samba3_idmap.get_user_sid(uid), domaindn), + samdb.add({"dn": "SID=%s,%s" % (samba3_idmap.get_user_sid(uid), domaindn), "SID": samba3_idmap.get_user_sid(uid), "type": "user", "unixID": str(uid)}) for gid in samba3_idmap.uids(): - samba4_idmap.add({"dn": "SID=%s,%s" % (samba3_idmap.get_group_sid(gid), domaindn), + samdb.add({"dn": "SID=%s,%s" % (samba3_idmap.get_group_sid(gid), domaindn), "SID": samba3_idmap.get_group_sid(gid), "type": "group", "unixID": str(gid)}) def import_wins(samba4_winsdb, samba3_winsdb): - """Import settings from a Samba3 WINS database.""" + """Import settings from a Samba3 WINS database. + + :param samba4_winsdb: WINS database to import to + :param samba3_winsdb: WINS database to import from + """ version_id = 0 import time for (name, (ttl, ips, nb_flags)) in samba3_winsdb.items(): version_id+=1 - numIPs = len(e.ips) - type = int(name.split("#", 1)[1], 16) if type == 0x1C: @@ -181,14 +189,14 @@ def import_wins(samba4_winsdb, samba3_winsdb): nType = ((nb_flags & 0x60)>>5) - samba4_winsdb.add({"dn": "name=%s,type=0x%s" % name.split("#"), + samba4_winsdb.add({"dn": "name=%s,type=0x%s" % tuple(name.split("#")), "type": name.split("#")[1], "name": name.split("#")[0], "objectClass": "winsRecord", "recordType": str(rType), "recordState": str(rState), "nodeType": str(nType), - "expireTime": ldb.ldaptime(ttl), + "expireTime": ldb.timestring(ttl), "isStatic": "0", "versionID": str(version_id), "address": ips}) @@ -237,9 +245,52 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: machinepass = None - provision(lp=lp, setup_dir=setup_dir, message=message, blank=True, ldapbackend=None, paths=paths, session_info=session_info, - credentials=credentials, realm=realm, domain=domainname, - domainsid=domainsid, domainguid=domainguid, machinepass=machinepass, serverrole=serverrole) + domaindn = provision(lp=lp, setup_dir=setup_dir, message=message, blank=True, ldapbackend=None, + paths=paths, session_info=session_info, credentials=credentials, realm=realm, + domain=domainname, domainsid=domainsid, domainguid=domainguid, + machinepass=machinepass, serverrole=serverrole) + + samdb = SamDB(paths.samdb, credentials=credentials, lp=lp, session_info=session_info) + + import_wins(Ldb(paths.winsdb), samba3.get_wins_db()) + + # FIXME: import_registry(registry.Registry(), samba3.get_registry()) + + # FIXME: import_idmap(samdb,samba3.get_idmap_db(),domaindn) + + groupdb = samba3.get_groupmapping_db() + for sid in groupdb.groupsids(): + (gid, sid_name_use, nt_name, comment) = groupdb.get_group(sid) + # FIXME: import_sam_group(samdb, sid, gid, sid_name_use, nt_name, comment, domaindn) + + # FIXME: Aliases + + passdb = samba3.get_sam_db() + for name in passdb: + user = passdb[name] + #FIXME: import_sam_account(samdb, user, domaindn, domainsid) + + if hasattr(passdb, 'ldap_url'): + message("Enabling Samba3 LDAP mappings for SAM database") + + enable_samba3sam(samdb, passdb.ldap_url) + + +def enable_samba3sam(samdb, ldapurl): + """Enable Samba 3 LDAP URL database. + + :param samdb: SAM Database. + :param ldapurl: Samba 3 LDAP URL + """ + samdb.modify_ldif(""" +dn: @MODULES +changetype: modify +replace: @LIST +@LIST: samldb,operational,objectguid,rdn_name,samba3sam +""") + + samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl}) + smbconf_keep = [ "dos charset", @@ -436,33 +487,4 @@ data: %d ldif = upgrade_wins(samba3) winsdb.add(ldif) - # figure out ldapurl, if applicable - ldapurl = None - pdb = samba3.configuration.get_list("passdb backend") - if pdb is not None: - for backend in pdb: - if len(backend) >= 7 and backend[0:7] == "ldapsam": - ldapurl = backend[7:] - - # URL was not specified in passdb backend but ldap /is/ used - if ldapurl == "": - ldapurl = "ldap://%s" % samba3.configuration.get("ldap server") - # Enable samba3sam module if original passdb backend was ldap - if ldapurl is not None: - message("Enabling Samba3 LDAP mappings for SAM database") - - enable_samba3sam(samdb) - - return ret - - -def enable_samba3sam(samdb): - samdb.modify(""" -dn: @MODULES -changetype: modify -replace: @LIST -@LIST: samldb,operational,objectguid,rdn_name,samba3sam -""") - - samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl}) -- cgit From 094f364fe172a117fd1cf8ae1855fd72fca8e5b4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 27 Dec 2007 23:31:42 -0600 Subject: r26614: Fix options parsing for credentials in Python. (This used to be commit 9ef3b7de6baadeb2240ef9d24c55be9dc4cccf1e) --- source4/scripting/python/samba/getopt.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 8143dcafdb..3335c55bc6 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -35,12 +35,24 @@ class VersionOptions(optparse.OptionGroup): class CredentialsOptions(optparse.OptionGroup): def __init__(self, parser): optparse.OptionGroup.__init__(self, parser, "Credentials Options") - self.add_option("--simple-bind-dn", type="string", metavar="DN", + self.add_option("--simple-bind-dn", metavar="DN", action="callback", + callback=self.set_simple_bind_dn, type=str, help="DN to use for a simple bind") - self.add_option("--password", type="string", metavar="PASSWORD", - help="Password") + self.add_option("--password", metavar="PASSWORD", action="callback", + help="Password", type=str, callback=self.set_password) + self.add_option("-U", "--username", metavar="USERNAME", + action="callback", type=str, + help="username", callback=self.parse_username) + self.creds = Credentials() + + def parse_username(self, option, opt_str, arg, parser): + self.creds.parse_string(arg) + + def set_password(self, option, opt_str, arg, parser): + self.creds.set_password(arg) + + def set_simple_bind_dn(self, option, opt_str, arg, parser): + self.creds.set_simple_bind_dn(arg) def get_credentials(self): - creds = Credentials() - # FIXME: Update - return creds + return self.creds -- 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/getopt.py | 2 +- source4/scripting/python/samba/samba3.py | 139 ++++++++++++++----------- source4/scripting/python/samba/tests/samba3.py | 32 +++++- source4/scripting/python/samba/upgrade.py | 53 ---------- 4 files changed, 111 insertions(+), 115 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 3335c55bc6..014dd336d8 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -23,7 +23,7 @@ from credentials import Credentials class SambaOptions(optparse.OptionGroup): def __init__(self, parser): optparse.OptionGroup.__init__(self, parser, "Samba Common Options") - self.add_option("--configfile", type="string", metavar="FILE", + self.add_option("-s", "--configfile", type="string", metavar="FILE", help="Configuration file") 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): diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py index 22b21ba1b4..175aa90497 100644 --- a/source4/scripting/python/samba/tests/samba3.py +++ b/source4/scripting/python/samba/tests/samba3.py @@ -107,9 +107,37 @@ class TdbSamTestCase(unittest.TestCase): self.assertEquals(3, len(list(self.samdb.usernames()))) def test_getuser(self): - return user = SAMUser("root") - self.assertEquals(user, self.samdb["root"]) + user.logoff_time = 2147483647 + user.kickoff_time = 2147483647 + user.pass_can_change_time = 1125418267 + user.username = "root" + user.uid = None + user.lm_password = 'U)\x02\x03\x1b\xed\xe9\xef\xaa\xd3\xb45\xb5\x14\x04\xee' + user.nt_password = '\x87\x8d\x80\x14`l\xda)gzD\xef\xa15?\xc7' + user.acct_ctrl = 16 + user.pass_last_set_time = 1125418267 + user.fullname = "root" + user.nt_username = "" + user.logoff_time = 2147483647 + user.acct_desc = "" + user.group_rid = 1001 + user.logon_count = 0 + user.bad_password_count = 0 + user.domain = "BEDWYR" + user.munged_dial = "" + user.workstations = "" + user.user_rid = 1000 + user.kickoff_time = 2147483647 + user.logoff_time = 2147483647 + user.unknown_6 = 1260L + user.logon_divs = 0 + user.hours = [True for i in range(168)] + other = self.samdb["root"] + for name in other.__dict__: + if other.__dict__[name] != user.__dict__[name]: + print "%s: %r != %r" % (name, other.__dict__[name], user.__dict__[name]) + self.assertEquals(user, other) class WinsDatabaseTestCase(unittest.TestCase): diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 3ecfe872f9..abf1127c36 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -435,56 +435,3 @@ def import_registry(samba4_registry, samba3_regdb): key_handle.set_value(value_name, value_type, value_data) -def upgrade(subobj, samba3, message, paths, session_info, credentials): - ret = 0 - samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) - - message("Writing configuration") - newconf = upgrade_smbconf(samba3.configuration,True) - newconf.save(paths.smbconf) - - message("Importing account policies") - samdb.modify_ldif(upgrade_sam_policy(samba3,subobj.BASEDN)) - regdb = Ldb(paths.hklm) - - regdb.modify(""" -dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE -replace: type -type: 4 -replace: data -data: %d -""" % policy.refuse_machine_password_change) - - message("Importing users") - for account in samba3.samaccounts: - msg = "... " + account.username - ldif = upgrade_sam_account(samdb, accounts,subobj.BASEDN,subobj.DOMAINSID) - try: - samdb.add(ldif) - except LdbError, e: - # FIXME: Ignore 'Record exists' errors - msg += "... error: " + str(e) - ret += 1; - message(msg) - - message("Importing groups") - for mapping in samba3.groupmappings: - msg = "... " + mapping.nt_name - ldif = upgrade_sam_group(mapping, subobj.BASEDN) - if ldif is not None: - try: - samdb.add(ldif) - except LdbError, e: - # FIXME: Ignore 'Record exists' errors - msg += "... error: " + str(e) - ret += 1 - message(msg) - - message("Importing WINS data") - winsdb = Ldb(paths.winsdb) - ldb_erase(winsdb) - - ldif = upgrade_wins(samba3) - winsdb.add(ldif) - - -- cgit From 77c825f08b516e3e5acf40d0b744a01ce68635fe Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 28 Dec 2007 15:36:55 -0600 Subject: r26618: Implement -W option support. (This used to be commit e48026b17d682c01eb3343ef35f6e847b18fa297) --- source4/scripting/python/samba/getopt.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 014dd336d8..87cf171ca2 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -42,12 +42,18 @@ class CredentialsOptions(optparse.OptionGroup): help="Password", type=str, callback=self.set_password) self.add_option("-U", "--username", metavar="USERNAME", action="callback", type=str, - help="username", callback=self.parse_username) + help="Username", callback=self.parse_username) + self.add_option("-W", "--workgroup", metavar="WORKGROUP", + action="callback", type=str, + help="Workgroup", callback=self.parse_workgroup) self.creds = Credentials() def parse_username(self, option, opt_str, arg, parser): self.creds.parse_string(arg) + def parse_workgroup(self, option, opt_str, arg, parser): + self.creds.set_domain(arg) + def set_password(self, option, opt_str, arg, parser): self.creds.set_password(arg) -- cgit From a61e25f17492bf78eb5d5ec962f0d174f94d8f84 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 28 Dec 2007 16:25:17 -0600 Subject: r26622: python: Update license version, clarify copyright. (This used to be commit 3ee62094074d74b6c69948730f2892f0a430f40b) --- source4/scripting/python/samba/provision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 53eb1d618f..fa45f7a79d 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1,6 +1,6 @@ # # backend code for provisioning a Samba4 server -# Released under the GNU GPL v2 or later +# Released under the GNU GPL v3 or later # Copyright Jelmer Vernooij 2007 # # Based on the original in EJS: -- 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/__init__.py | 8 ++ source4/scripting/python/samba/getopt.py | 2 +- source4/scripting/python/samba/provision.py | 96 ++++++++++++++-------- source4/scripting/python/samba/samba3.py | 100 +++++++++++++++-------- source4/scripting/python/samba/samdb.py | 50 ++++++++---- source4/scripting/python/samba/tests/__init__.py | 4 + 6 files changed, 174 insertions(+), 86 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 359457d815..01fdea6665 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -159,11 +159,19 @@ class Ldb(ldb.Ldb): self.add_ldif(open(ldif_path, 'r').read()) def add_ldif(self, ldif): + """Add data based on a LDIF string. + + :param ldif: LDIF text. + """ for changetype, msg in self.parse_ldif(ldif): assert changetype == ldb.CHANGETYPE_NONE self.add(msg) def modify_ldif(self, ldif): + """Modify database based on a LDIF string. + + :param ldif: LDIF text. + """ for (changetype, msg) in self.parse_ldif(ldif): assert changetype == ldb.CHANGETYPE_MODIFY self.modify(msg) diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 87cf171ca2..c0e7053062 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -58,7 +58,7 @@ class CredentialsOptions(optparse.OptionGroup): self.creds.set_password(arg) 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): return self.creds diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index fa45f7a79d..bdfe035c41 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -74,6 +74,14 @@ def findnss(nssfn, *names): 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 try: 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): - """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) data = open(ldif_path, 'r').read() @@ -126,7 +139,12 @@ def setup_ldb(ldb, ldif_path, subst_vars): 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 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, 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 ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous") 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: nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] 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: wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] if backup is None: @@ -748,13 +777,32 @@ def provision(lp, setup_dir, message, blank, paths, session_info, return domaindn 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"), path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")}) def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, 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, { "DNSPASS_B64": b64encode(dnspass), @@ -795,7 +843,14 @@ def provision_ldapbase(setup_dir, message, paths): 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_samba4.ldif"), 'r').read() schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) @@ -807,32 +862,3 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): "DEFAULTSITE": DEFAULTSITE}) 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) - - - 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): diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 46707f060f..2af56d8d8e 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -20,13 +20,20 @@ # along with this program. If not, see . # +"""Convenience functions for using the SAM.""" + import samba import misc import ldb class SamDB(samba.Ldb): + """The SAM database.""" def __init__(self, url=None, session_info=None, credentials=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, modules_dir=modules_dir, lp=lp) assert misc.dsdb_set_global_schema(self) == 0 @@ -47,7 +54,12 @@ description: %s self.add(msg[1]) 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, "objectSid=%s" % sid, ["dn"]) 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]) def enable_account(self, user_dn): - """enable the account. + """Enable an account. :param user_dn: Dn of the account to enable. """ @@ -75,10 +87,15 @@ changetype: modify replace: userAccountControl userAccountControl: %u """ % (user_dn, userAccountControl) - self.modify(mod) + self.modify_ldif(mod) - def newuser(self, username, unixname, password, message): - """add a new user record""" + def newuser(self, username, unixname, password): + """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 self.transaction_start() @@ -97,13 +114,13 @@ userAccountControl: %u # the new user record. note the reliance on the samdb module to fill # in a sid, guid etc # - ldif = """ -dn: %s -sAMAccountName: %s -unixName: %s -sambaPassword: %s -objectClass: user - """ % (user_dn, username, unixname, password) + # now the real work + self.add({"dn": user_dn, + "sAMAccountName": username, + "unixName": unixname, + "sambaPassword": password, + "objectClass": "user"}) + # add the user to the users group as well modgroup = """ dn: %s @@ -113,11 +130,6 @@ member: %s """ % (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) # modify the userAccountControl to remove the disabled bit @@ -125,6 +137,10 @@ member: %s self.transaction_commit() 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) def attach_schema_from_ldif(self, pf, df): diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index 5e1ff87c2b..ad8a2524b5 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -17,6 +17,8 @@ # along with this program. If not, see . # +"""Samba Python tests.""" + import os import ldb import samba @@ -24,11 +26,13 @@ import tempfile import unittest class LdbTestCase(unittest.TestCase): + """Trivial test case for running tests against a LDB.""" def setUp(self): self.filename = os.tempnam() self.ldb = samba.Ldb(self.filename) def set_modules(self, modules=[]): + """Change the modules for this Ldb.""" m = ldb.Message() m.dn = ldb.Dn(self.ldb, "@MODULES") m["@LIST"] = ",".join(modules) -- 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/getopt.py | 16 +++++------ source4/scripting/python/samba/provision.py | 8 +++++- source4/scripting/python/samba/samba3.py | 43 +++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 17 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index c0e7053062..a087974a69 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -36,28 +36,28 @@ class CredentialsOptions(optparse.OptionGroup): def __init__(self, parser): optparse.OptionGroup.__init__(self, parser, "Credentials Options") self.add_option("--simple-bind-dn", metavar="DN", action="callback", - callback=self.set_simple_bind_dn, type=str, + callback=self._set_simple_bind_dn, type=str, help="DN to use for a simple bind") self.add_option("--password", metavar="PASSWORD", action="callback", - help="Password", type=str, callback=self.set_password) + help="Password", type=str, callback=self._set_password) self.add_option("-U", "--username", metavar="USERNAME", action="callback", type=str, - help="Username", callback=self.parse_username) + help="Username", callback=self._parse_username) self.add_option("-W", "--workgroup", metavar="WORKGROUP", action="callback", type=str, - help="Workgroup", callback=self.parse_workgroup) + help="Workgroup", callback=self._parse_workgroup) self.creds = Credentials() - def parse_username(self, option, opt_str, arg, parser): + def _parse_username(self, option, opt_str, arg, parser): self.creds.parse_string(arg) - def parse_workgroup(self, option, opt_str, arg, parser): + def _parse_workgroup(self, option, opt_str, arg, parser): self.creds.set_domain(arg) - def set_password(self, option, opt_str, arg, parser): + def _set_password(self, option, opt_str, arg, parser): 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_bind_dn(arg) def get_credentials(self): diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index bdfe035c41..db3749f721 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -23,6 +23,7 @@ import security from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE +"""Functions for setting up a Samba configuration.""" DEFAULTSITE = "Default-First-Site-Name" @@ -53,7 +54,12 @@ class ProvisionPaths: def install_ok(lp, session_info, credentials): - """Check whether the current install seems ok.""" + """Check whether the current install seems ok. + + :param lp: Loadparm context + :param session_info: Session information + :param credentials: Credentials + """ if lp.get("realm") == "": return False ldb = Ldb(lp.get("sam database"), session_info=session_info, 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 5e03b921825ffe177bf9d00ed1e12de02728da75 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 2 Jan 2008 01:52:31 -0600 Subject: r26642: samba3sam.py: Remove more EJS-specific code. (This used to be commit 7d14b657b3d59924b15f4f84bbd5745cd7f759ef) --- source4/scripting/python/samba/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 01fdea6665..e0b9e1d410 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -172,8 +172,7 @@ class Ldb(ldb.Ldb): :param ldif: LDIF text. """ - for (changetype, msg) in self.parse_ldif(ldif): - assert changetype == ldb.CHANGETYPE_MODIFY + for changetype, msg in self.parse_ldif(ldif): self.modify(msg) -- cgit From 7c3e8c838f0ada9ebae9dbb2bc5d84320c8431f2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 11 Jan 2008 16:13:46 +0100 Subject: Python: Simplify code in a couple of places. Copy Andrew's changes from g53b5166. (This used to be commit f056f624958af79204c972eba3f85e36e93daed7) --- source4/scripting/python/samba/__init__.py | 12 ++++++------ source4/scripting/python/samba/provision.py | 8 ++++---- source4/scripting/python/samba/samdb.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index e0b9e1d410..e858180169 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -112,15 +112,15 @@ class Ldb(ldb.Ldb): for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: try: - self.delete(ldb.Dn(self, attr)) + self.delete(attr) except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): # Ignore missing dn errors pass - basedn = ldb.Dn(self, "") + basedn = "" # and the rest for msg in self.search(basedn, ldb.SCOPE_SUBTREE, - "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", + "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", ["dn"]): try: self.delete(msg.dn) @@ -128,12 +128,12 @@ class Ldb(ldb.Ldb): # Ignor eno such object errors pass - res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) + res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguisedName=@BASEINFO)))", ["dn"]) assert len(res) == 0 def erase_partitions(self): """Erase an ldb, removing all records.""" - res = self.search(ldb.Dn(self, ""), ldb.SCOPE_BASE, "(objectClass=*)", + res = self.search("", ldb.SCOPE_BASE, "(objectClass=*)", ["namingContexts"]) assert len(res) == 1 if not "namingContexts" in res[0]: @@ -145,7 +145,7 @@ class Ldb(ldb.Ldb): k = 0 while ++k < 10 and (previous_remaining != current_remaining): # and the rest - res2 = self.search(ldb.Dn(self, basedn), ldb.SCOPE_SUBTREE, "(|(objectclass=*)(dn=*))", ["dn"]) + res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) previous_remaining = current_remaining current_remaining = len(res2) for msg in res2: diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index db3749f721..1607cb343b 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -20,7 +20,7 @@ import samba from samba import Ldb, substitute_var, valid_netbios_name from samba.samdb import SamDB import security -from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ +from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE """Functions for setting up a Samba configuration.""" @@ -64,7 +64,7 @@ def install_ok(lp, session_info, credentials): return False ldb = Ldb(lp.get("sam database"), session_info=session_info, credentials=credentials, lp=lp) - if len(ldb.search(ldb.Dn("(cn=Administrator)"))) != 1: + if len(ldb.search("(cn=Administrator)")) != 1: return False return True @@ -766,9 +766,9 @@ def provision(lp, setup_dir, message, blank, paths, session_info, samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) - domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID") + domainguid = samdb.searchone(domaindn, "objectGUID") assert isinstance(domainguid, str) - hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID", + hostguid = samdb.searchone(domaindn, "objectGUID", expression="(&(objectClass=computer)(cn=%s))" % hostname, scope=SCOPE_SUBTREE) assert isinstance(hostguid, str) diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 2af56d8d8e..353eaee198 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -60,7 +60,7 @@ description: %s :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(domaindn, ldb.SCOPE_SUBTREE, "objectSid=%s" % sid, ["dn"]) assert len(res) == 1, "Failed to find record for objectSid %s" % sid @@ -103,7 +103,7 @@ userAccountControl: %u res = self.search("", SCOPE_BASE, "defaultNamingContext=*", ["defaultNamingContext"]) assert(len(res) == 1 and res[0].defaultNamingContext is not None) - domain_dn = res[0].defaultNamingContext + domain_dn = res[0]["defaultNamingContext"][0] assert(domain_dn is not None) dom_users = self.searchone(domain_dn, "dn", "name=Domain Users") assert(dom_users is not None) -- cgit From 378dff1365801b2dd23677a38f2fb20828cbbf39 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 11 Jan 2008 16:28:17 +0100 Subject: python: Fix typo. (This used to be commit d6b06fc03e37781f5f59b15cff8fe3ee8df63444) --- source4/scripting/python/samba/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index e858180169..483929661d 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -121,14 +121,14 @@ class Ldb(ldb.Ldb): # and the rest for msg in self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", - ["dn"]): + ["distinguishedName"]): try: self.delete(msg.dn) except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): # Ignor eno such object errors pass - res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguisedName=@BASEINFO)))", ["dn"]) + res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", ["distinguishedName"]) assert len(res) == 0 def erase_partitions(self): -- cgit From db4ee4cce5f1fd84f3f0a331e769a70394126ca5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Jan 2008 03:59:36 +0100 Subject: python: Fix rpcecho tests. (This used to be commit ebb78ea4232c1614755844849580e3697b0a53fa) --- .../python/samba/tests/dcerpc/__init__.py | 0 .../scripting/python/samba/tests/dcerpc/rpcecho.py | 39 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 source4/scripting/python/samba/tests/dcerpc/__init__.py create mode 100644 source4/scripting/python/samba/tests/dcerpc/rpcecho.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/__init__.py b/source4/scripting/python/samba/tests/dcerpc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py new file mode 100644 index 0000000000..cedd0cc2fe --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2008 +# +# 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 . +# + +import echo +import unittest + +class RpcEchoTests(unittest.TestCase): + def setUp(self): + self.conn = echo.rpcecho("ncalrpc:") + + def test_addone(self): + self.assertEquals(2, conn.AddOne(1)) + + def test_echodata(self): + self.assertEquals("bla", conn.EchoData(3, "bla")) + + def test_call(self): + self.assertEquals("foobar", conn.TestCall("foobar")) + + def test_surrounding(self): + somearray = [1,2,3,4] + (y,) = conn.TestSurrounding(echo.Surrounding(4, somearray)) + self.assertEquals(8 * [0], y.surrounding) -- cgit From 3b16c532f21202696d54ef87f8fa74d066812898 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Jan 2008 05:16:51 +0100 Subject: pidl/python: Pass credentials and loadparm context when connecting using DCE/RPC. (This used to be commit 4c87af95310e4aaee3f2e2da02d0ea70ed1ec25b) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index cedd0cc2fe..52a4f49bb4 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -18,22 +18,25 @@ # import echo +from param import LoadParm import unittest class RpcEchoTests(unittest.TestCase): def setUp(self): - self.conn = echo.rpcecho("ncalrpc:") + lp_ctx = LoadParm() + lp_ctx.load("st/client/client.conf") + self.conn = echo.rpcecho("ncalrpc:", lp_ctx) def test_addone(self): - self.assertEquals(2, conn.AddOne(1)) + self.assertEquals(2, self.conn.AddOne(1)) def test_echodata(self): - self.assertEquals("bla", conn.EchoData(3, "bla")) + self.assertEquals("bla", self.conn.EchoData(3, "bla")) def test_call(self): - self.assertEquals("foobar", conn.TestCall("foobar")) + self.assertEquals("foobar", self.conn.TestCall("foobar")) def test_surrounding(self): somearray = [1,2,3,4] - (y,) = conn.TestSurrounding(echo.Surrounding(4, somearray)) + (y,) = self.conn.TestSurrounding(echo.Surrounding(4, somearray)) self.assertEquals(8 * [0], y.surrounding) -- cgit From 271f5f18f2c871cfba256f7088839e4eb195e289 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Jan 2008 06:05:28 +0100 Subject: python: Fix last bugs in rpcecho test. It passes now! (This used to be commit 25a0cd091bb24e579ceb34472d9c213aae157ba9) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 52a4f49bb4..52c2bb8c72 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -31,12 +31,14 @@ class RpcEchoTests(unittest.TestCase): self.assertEquals(2, self.conn.AddOne(1)) def test_echodata(self): - self.assertEquals("bla", self.conn.EchoData(3, "bla")) + self.assertEquals([1,2,3], self.conn.EchoData(3, [1, 2, 3])) def test_call(self): - self.assertEquals("foobar", self.conn.TestCall("foobar")) + self.assertEquals(u"foobar", self.conn.TestCall(u"foobar")) def test_surrounding(self): - somearray = [1,2,3,4] - (y,) = self.conn.TestSurrounding(echo.Surrounding(4, somearray)) + surrounding_struct = echo.Surrounding() + surrounding_struct.x = 4 + surrounding_struct.surrounding = [1,2,3,4] + y = self.conn.TestSurrounding(surrounding_struct) self.assertEquals(8 * [0], y.surrounding) -- cgit From 7dd468ff2e5a4c4ce503e1b8e024bf91dcf7a412 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Jan 2008 14:48:59 +0100 Subject: python: Fix python code for winreg, add test. (This used to be commit bd3e6c41c42738fcfcc5cef4e65f0e219d358260) --- .../python/samba/tests/dcerpc/registry.py | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 source4/scripting/python/samba/tests/dcerpc/registry.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py new file mode 100644 index 0000000000..7979592a40 --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2008 +# +# 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 . +# + + +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2008 +# +# 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 . +# + +import winreg +from param import LoadParm +import unittest + +class WinregTests(unittest.TestCase): + def setUp(self): + lp_ctx = LoadParm() + lp_ctx.load("st/client/client.conf") + self.conn = winreg.winreg("ncalrpc:", lp_ctx) + + def test_hklm(self): + (handle, _) = self.conn.OpenHKLM(None, + winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + self.conn.CloseKey(handle) -- cgit From 035599fa651409502a6894179d5cd8a026110ba1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Jan 2008 15:25:09 +0100 Subject: python: Be more pythonic - turn WERROR and NTSTATUS return codes into exceptions. (This used to be commit 16fc69b843e92ae62b15caf927335cc117156499) --- .../python/samba/tests/dcerpc/registry.py | 39 ++++++++++------------ 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index 7979592a40..f3f0b0fb1a 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -17,26 +17,6 @@ # along with this program. If not, see . # - -#!/usr/bin/python - -# Unix SMB/CIFS implementation. -# Copyright (C) Jelmer Vernooij 2008 -# -# 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 . -# - import winreg from param import LoadParm import unittest @@ -47,7 +27,24 @@ class WinregTests(unittest.TestCase): lp_ctx.load("st/client/client.conf") self.conn = winreg.winreg("ncalrpc:", lp_ctx) + def get_hklm(self): + return self.conn.OpenHKLM(None, + winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + def test_hklm(self): - (handle, _) = self.conn.OpenHKLM(None, + handle = self.conn.OpenHKLM(None, + winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + self.conn.CloseKey(handle) + + def test_getversion(self): + handle = self.get_hklm() + version = self.conn.GetVersion(handle) + self.assertEquals(int, version.__class__) + self.conn.CloseKey(handle) + + def test_getkeyinfo(self): + handle = self.conn.OpenHKLM(None, winreg.KEY_QUERY_VALUE | winreg.KEY_ENUMERATE_SUB_KEYS) + x = self.conn.QueryInfoKey(handle, winreg.String()) + self.assertEquals(9, len(x)) # should return a 9-tuple self.conn.CloseKey(handle) -- cgit From 001b2435f0a47f75f82a32f2ccead2759596a09d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Jan 2008 19:05:08 +0100 Subject: python: Add simple test for samr python code. (This used to be commit 0a039fabcba9510ab600b2e4becbf75a58d2134d) --- source4/scripting/python/samba/tests/dcerpc/sam.py | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 source4/scripting/python/samba/tests/dcerpc/sam.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py new file mode 100644 index 0000000000..50caaf2348 --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2008 +# +# 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 . +# + +import samr +import unittest + +class SamrTests(unittest.TestCase): + def setUp(self): + self.conn = samr.samr("ncalrpc:", "st/client/client.conf") + + def test_connect5(self): + (level, info, handle) = self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) -- cgit From 064eb82870596e72373c290dfaf0e6b8289303de Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jan 2008 13:25:01 +1100 Subject: Remove --ldap-base from the python provision script (This is a merge from the ejs script) Andrew Bartlett (This used to be commit d822dfa017b84895222ace8c44935fb872930548) --- source4/scripting/python/samba/provision.py | 32 ----------------------------- 1 file changed, 32 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 1607cb343b..d59cea121e 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -180,12 +180,6 @@ def provision_paths_from_lp(lp, dnsdomain): paths.dns_keytab = os.path.join(private_dir, "dns.keytab") paths.dns = os.path.join(private_dir, dnsdomain + ".zone") paths.winsdb = os.path.join(private_dir, "wins.ldb") - paths.ldap_basedn_ldif = os.path.join(private_dir, - dnsdomain + ".ldif") - paths.ldap_config_basedn_ldif = os.path.join(private_dir, - dnsdomain + "-config.ldif") - paths.ldap_schema_basedn_ldif = os.path.join(private_dir, - dnsdomain + "-schema.ldif") paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php") @@ -465,7 +459,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { "DOMAINDN": domaindn, "ACI": aci, - "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", "RDN_DC": rdn_dc, }) @@ -823,31 +816,6 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, }) -def provision_ldapbase(setup_dir, message, paths): - """Write out a DNS zone file, from the info in the current database.""" - message("Setting up LDAP base entry: %s" % domaindn) - rdns = domaindn.split(",") - - rdn_dc = rdns[0][len("DC="):] - - def setup_path(file): - return os.path.join(setup_dir, file) - - setup_file(setup_path("provision_basedn.ldif"), - paths.ldap_basedn_ldif) - - setup_file(setup_path("provision_configuration_basedn.ldif"), - paths.ldap_config_basedn_ldif) - - setup_file(setup_path("provision_schema_basedn.ldif"), - paths.ldap_schema_basedn_ldif, { - "SCHEMADN": schemadn, - "ACI": "# no aci for local ldb", - "EXTENSIBLEOBJECT": "objectClass: extensibleObject"}) - - message("Please install the LDIF located in " + paths.ldap_basedn_ldif + ", " + paths.ldap_config_basedn_ldif + " and " + paths.ldap_schema_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server") - - def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): """Load schema. -- cgit From decdf5954d5e1ae84318d6767317965f544a897f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 23 Jan 2008 23:33:36 +0100 Subject: python: Add convenience function for getting command line loadparm context and default to using system smb.conf. (This used to be commit b3afde0f00ab5093b577b139a062c233d4db2524) --- source4/scripting/python/samba/getopt.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index a087974a69..dfcf2c457e 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -23,9 +23,25 @@ from credentials import Credentials class SambaOptions(optparse.OptionGroup): def __init__(self, parser): optparse.OptionGroup.__init__(self, parser, "Samba Common Options") - self.add_option("-s", "--configfile", type="string", metavar="FILE", - help="Configuration file") + self.add_option("-s", "--configfile", action="callback", + type=str, metavar="FILE", help="Configuration file", + callback=self._load_configfile) + self._configfile = None + def get_loadparm_path(self): + return self._configfile + + def _load_configfile(self, option, opt_str, arg, parser): + self._configfile = arg + + def get_loadparm(self): + import param + lp = param.LoadParm() + if self._configfile is None: + lp.load_default() + else: + lp.load(self._configfile) + return lp class VersionOptions(optparse.OptionGroup): def __init__(self, parser): -- cgit From 42771814530639940b3349a6b5091f9a7d19f8f7 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 24 Jan 2008 01:05:57 +0100 Subject: python: Support --no-pass. (This used to be commit a90f3e8c420bec7fd7a39e0d5e2df6b32aedcdd5) --- source4/scripting/python/samba/getopt.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index dfcf2c457e..088a5acf6f 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -50,6 +50,7 @@ class VersionOptions(optparse.OptionGroup): class CredentialsOptions(optparse.OptionGroup): def __init__(self, parser): + self.no_pass = False optparse.OptionGroup.__init__(self, parser, "Credentials Options") self.add_option("--simple-bind-dn", metavar="DN", action="callback", callback=self._set_simple_bind_dn, type=str, @@ -62,6 +63,8 @@ class CredentialsOptions(optparse.OptionGroup): self.add_option("-W", "--workgroup", metavar="WORKGROUP", action="callback", type=str, help="Workgroup", callback=self._parse_workgroup) + self.add_option("-N", "--no-pass", action="store_true", + help="Don't ask for a password") self.creds = Credentials() def _parse_username(self, option, opt_str, arg, parser): @@ -77,4 +80,7 @@ class CredentialsOptions(optparse.OptionGroup): self.creds.set_bind_dn(arg) def get_credentials(self): + self.creds.guess() + if not self.no_pass: + self.creds.set_cmdline_callbacks() return self.creds -- cgit From a2dcf7bd22b5f206ef3c3816d0c93b140260da67 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 24 Jan 2008 01:06:19 +0100 Subject: Python: add some docstrings. (This used to be commit 1de69a772e1cc007220add1f51bffe83784c3344) --- source4/scripting/python/samba/provision.py | 51 ++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d59cea121e..11dd819ad3 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -289,6 +289,14 @@ def provision_become_dc(setup_dir, message, paths, lp, session_info, def setup_secretsdb(path, setup_path, session_info, credentials, lp): + """Setup the secrets database. + + :param path: Path to the secrets database. + :param setup_path: Get the path to a setup file. + :param session_info: Session info. + :param credentials: Credentials + :param lp: Loadparm context + """ if os.path.exists(path): os.unlink(path) secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp) @@ -299,6 +307,14 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): def setup_templatesdb(path, setup_path, session_info, credentials, lp): + """Setup the templates database. + + :param path: Path to the database. + :param setup_path: Function for obtaining the path to setup files. + :param session_info: Session info + :param credentials: Credentials + :param lp: Loadparm context + """ templates_ldb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) templates_ldb.erase() @@ -306,6 +322,14 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp): def setup_registry(path, setup_path, session_info, credentials, lp): + """Setup the registry. + + :param path: Path to the registry database + :param setup_path: Function that returns the path to a setup. + :param session_info: Session information + :param credentials: Credentials + :param lp: Loadparm context + """ reg = registry.Registry() hive = registry.open_ldb(path, session_info=session_info, credentials=credentials, lp_ctx=lp) @@ -317,6 +341,12 @@ def setup_registry(path, setup_path, session_info, credentials, lp): def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, dnsdomain, realm, rootdn, configdn, netbiosname): + """Setup the SamDB rootdse. + + :param samdb: Sam Database handle + :param setup_path: Obtain setup path + ... + """ setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), { "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, @@ -332,6 +362,14 @@ def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn): + """Setup SAM database partitions. + + :param samdb: Sam Database handle + :param setup_path: Setup path function + :param schemadn: Schema DN. + :param configdn: Configuration DN. + :param domaindn: Domain DN. + """ #Add modules to the list to activate them by default #beware often order is important # @@ -561,11 +599,14 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, if lp.get("server role") == "domain controller": message("Setting up self join") - setup_self_join(samdb, configdn=configdn, schemadn=schemadn, domaindn=domaindn, - invocationid=invocationid, dnspass=dnspass, netbiosname=netbiosname, - dnsdomain=dnsdomain, realm=realm, machinepass=machinepass, - domainname=domainname, domainsid=domainsid, policyguid=policyguid, - hostname=hostname, hostguid=hostguid, setup_path=setup_path) + setup_self_join(samdb, configdn=configdn, schemadn=schemadn, + domaindn=domaindn, invocationid=invocationid, + dnspass=dnspass, netbiosname=netbiosname, + dnsdomain=dnsdomain, realm=realm, + machinepass=machinepass, domainname=domainname, + domainsid=domainsid, policyguid=policyguid, + hostname=hostname, hostguid=hostguid, + setup_path=setup_path) message("Setting up sam.ldb index") samdb.load_ldif_file_add(setup_path("provision_index.ldif")) -- cgit From 859b847a68cf10526b9f356ebcb328e7334a8cb1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 24 Jan 2008 22:08:39 +0100 Subject: python: Add bindings for SamDB.set_invocation_id(). (This used to be commit c09efa7b778f9cb29032a6abfd914fcaae8df163) --- source4/scripting/python/samba/samdb.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 353eaee198..e92a4bbb90 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -145,3 +145,10 @@ member: %s def attach_schema_from_ldif(self, pf, df): misc.dsdb_attach_schema_from_ldif_file(self, pf, df) + + def set_invocation_id(self, invocation_id): + """Set the invocation id for this SamDB handle. + + :param invocation_id: GUID of the invocation id. + """ + misc.samdb_set_ntds_invocation_id(self, invocation_id) \ No newline at end of file -- cgit From d958f4b3912dc298037c112ad724b85a7a46ecdb Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 24 Jan 2008 22:18:27 +0100 Subject: python: Add function to look for unsubsituted variables. (This used to be commit e726ce5bc515ae8d10b472396e228cfd35737476) --- source4/scripting/python/samba/__init__.py | 15 +++++++++++++++ source4/scripting/python/samba/tests/__init__.py | 4 ++++ 2 files changed, 19 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 483929661d..b5d7f2ebc7 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -192,6 +192,21 @@ def substitute_var(text, values): return text +def check_all_substituted(text): + """Make sure that all substitution variables in a string have been replaced. + If not, raise an exception. + + :param text: The text to search for substitution variables + """ + if not "${" in text: + return + + var_start = text.find("${") + var_end = text.find("}", var_start) + + raise Exception("Not all variables substituted: %s" % text[var_start:var_end]) + + def valid_netbios_name(name): """Check whether a name is valid as a NetBIOS name. """ # FIXME: There are probably more constraints here. diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index ad8a2524b5..6fbf420339 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -67,6 +67,10 @@ class SubstituteVarTestCase(unittest.TestCase): def test_unknown_var(self): self.assertEquals("foo ${bla} gsff", samba.substitute_var("foo ${bla} gsff", {"bar": "bla"})) + + def test_check_all_substituted(self): + check_all_substituted("nothing to see here") + self.assertRaises(Exception, check_all_substituted, "Not subsituted: ${FOOBAR}") class LdbExtensionTests(TestCaseInTempDir): -- cgit From 37f35d2a03409e0d52232d4c4f956ec8637d4884 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 25 Jan 2008 01:02:13 +0100 Subject: python/provision: Reconcile code partitions-only provisioning and generic provisioning, some other minor refactoring of the provisioning. Pair-programmed by Andrew and me using obby :-) (This used to be commit 688adcbb635af87fcfedb869b7f1857a947fd2f9) --- source4/scripting/python/samba/__init__.py | 6 +- source4/scripting/python/samba/provision.py | 469 +++++++++++++---------- source4/scripting/python/samba/samdb.py | 6 +- source4/scripting/python/samba/tests/__init__.py | 2 +- source4/scripting/python/samba/upgrade.py | 5 +- 5 files changed, 276 insertions(+), 212 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index b5d7f2ebc7..5c14edd357 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -1,8 +1,10 @@ #!/usr/bin/python # Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2007-2008 +# +# Based on the original in EJS: # Copyright (C) Andrew Tridgell 2005 -# 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 @@ -204,7 +206,7 @@ def check_all_substituted(text): var_start = text.find("${") var_end = text.find("}", var_start) - raise Exception("Not all variables substituted: %s" % text[var_start:var_end]) + raise Exception("Not all variables substituted: %s" % text[var_start:var_end+1]) def valid_netbios_name(name): diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 11dd819ad3..918d983782 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1,10 +1,25 @@ # -# backend code for provisioning a Samba4 server -# Released under the GNU GPL v3 or later -# Copyright Jelmer Vernooij 2007 +# Unix SMB/CIFS implementation. +# backend code for provisioning a Samba4 server + +# Copyright (C) Jelmer Vernooij 2007-2008 +# Copyright (C) Andrew Bartlett 2008 # # Based on the original in EJS: -# Copyright Andrew Tridgell 2005 +# Copyright (C) Andrew Tridgell 2005 +# +# 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 . # from base64 import b64encode @@ -17,9 +32,10 @@ from socket import gethostname, gethostbyname import param import registry import samba -from samba import Ldb, substitute_var, valid_netbios_name +from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted from samba.samdb import SamDB import security +import urllib from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE @@ -53,7 +69,7 @@ class ProvisionPaths: self.ldap_schema_basedn_ldif = None -def install_ok(lp, session_info, credentials): +def check_install(lp, session_info, credentials): """Check whether the current install seems ok. :param lp: Loadparm context @@ -61,12 +77,11 @@ def install_ok(lp, session_info, credentials): :param credentials: Credentials """ if lp.get("realm") == "": - return False + raise Error("Realm empty") ldb = Ldb(lp.get("sam database"), session_info=session_info, credentials=credentials, lp=lp) if len(ldb.search("(cn=Administrator)")) != 1: - return False - return True + raise "No administrator account found" def findnss(nssfn, *names): @@ -112,7 +127,7 @@ def setup_add_ldif(ldb, ldif_path, subst_vars=None): if subst_vars is not None: data = substitute_var(data, subst_vars) - assert "${" not in data + check_all_substituted(data) ldb.add_ldif(data) @@ -128,7 +143,7 @@ def setup_modify_ldif(ldb, ldif_path, substvars=None): if substvars is not None: data = substitute_var(data, substvars) - assert "${" not in data + check_all_substituted(data) ldb.modify_ldif(data) @@ -159,19 +174,20 @@ def setup_file(template, fname, substvars): data = open(template, 'r').read() if substvars: data = substitute_var(data, substvars) - assert not "${" in data + check_all_substituted(data) open(f, 'w').write(data) -def provision_paths_from_lp(lp, dnsdomain): +def provision_paths_from_lp(lp, dnsdomain, private_dir=None): """Set the default paths for provisioning. :param lp: Loadparm context. :param dnsdomain: DNS Domain name """ paths = ProvisionPaths() - private_dir = lp.get("private dir") + if private_dir is None: + private_dir = lp.get("private dir") paths.shareconf = os.path.join(private_dir, "share.ldb") paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") @@ -235,57 +251,144 @@ def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, ldb.setup_name_mapping(domaindn, sid + "-520", wheel) -def provision_become_dc(setup_dir, message, paths, lp, session_info, - credentials): +def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, + credentials, configdn, schemadn, domaindn, + hostname, netbiosname, dnsdomain, realm, + rootdn, serverrole, ldap_backend=None, + ldap_backend_type=None, erase=False): + """Setup the partitions for the SAM database. + + Alternatively, provision() may call this, and then populate the database. + + :param erase: Remove the existing data present in the database. + :param + + :note: This will wipe the Sam Database! + + :note: This function always removes the local SAM LDB file. The erase + parameter controls whether to erase the existing data, which + may not be stored locally but in LDAP. + """ assert session_info is not None - erase = False - def setup_path(file): - return os.path.join(setup_dir, file) - os.path.unlink(paths.samdb) - - message("Setting up templates db") - setup_templatesdb(paths.templates, setup_path, session_info=session_info, - credentials=credentials, lp=lp) + if os.path.exists(samdb_path): + os.unlink(samdb_path) # Also wipes the database - message("Setting up sam.ldb") - samdb = SamDB(paths.samdb, session_info=session_info, + samdb = SamDB(samdb_path, session_info=session_info, credentials=credentials, lp=lp) - message("Setting up sam.ldb partitions") - setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn) + #Add modules to the list to activate them by default + #beware often order is important + # + # Some Known ordering constraints: + # - rootdse must be first, as it makes redirects from "" -> cn=rootdse + # - objectclass must be before password_hash, because password_hash checks + # that the objectclass is of type person (filled in by objectclass + # module when expanding the objectclass list) + # - partition must be last + # - each partition has its own module list then + modules_list = ["rootdse", + "paged_results", + "ranged_results", + "anr", + "server_sort", + "extended_dn", + "asq", + "samldb", + "rdn_name", + "objectclass", + "kludge_acl", + "operational"] + tdb_modules_list = [ + "subtree_rename", + "subtree_delete", + "linked_attributes"] + modules_list2 = ["show_deleted", + "partition"] + + domaindn_ldb = "users.ldb" + if ldap_backend is not None: + domaindn_ldb = ldap_backend + configdn_ldb = "configuration.ldb" + if ldap_backend is not None: + configdn_ldb = ldap_backend + schema_ldb = "schema.ldb" + if ldap_backend is not None: + schema_ldb = ldap_backend + + if ldap_backend_type == "fedora-ds": + backend_modules = ["nsuniqueid","paged_searches"] + elif ldap_backend_type == "openldap": + backend_modules = ["normalise","entryuuid","paged_searches"] + elif serverrole == "domain controller": + backend_modules = ["repl_meta_data"] + else: + backend_modules = ["objectguid"] + + setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { + "SCHEMADN": schemadn, + "SCHEMADN_LDB": "schema.ldb", + "SCHEMADN_MOD2": ",objectguid", + "CONFIGDN": configdn, + "CONFIGDN_LDB": "configuration.ldb", + "DOMAINDN": domaindn, + "DOMAINDN_LDB": "users.ldb", + "SCHEMADN_MOD": "schema_fsmo,instancetype", + "CONFIGDN_MOD": "naming_fsmo,instancetype", + "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype", + "MODULES_LIST": ",".join(modules_list), + "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), + "MODULES_LIST2": ",".join(modules_list2), + "BACKEND_MOD": ",".join(backend_modules), + }) - samdb = SamDB(paths.samdb, session_info=session_info, + samdb = SamDB(samdb_path, session_info=session_info, credentials=credentials, lp=lp) - ldb.transaction_start() + samdb.transaction_start() try: message("Setting up sam.ldb attributes") samdb.load_ldif_file_add(setup_path("provision_init.ldif")) message("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, - hostname, dnsdomain, realm, rootdn, configdn, - netbiosname) + setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, + dnsdomain, realm, rootdn, configdn, netbiosname) if erase: message("Erasing data from partitions") samdb.erase_partitions() - message("Setting up sam.ldb indexes") - samdb.load_ldif_file_add(setup_path("provision_index.ldif")) except: samdb.transaction_cancel() raise samdb.transaction_commit() + + return samdb + - message("Setting up %s" % paths.secrets) - secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info, - credentials, lp) - setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), - { "MACHINEPASS_B64": b64encode(machinepass) }) +def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain, + netbiosname, domainsid, keytab_path, samdb_url, + dns_keytab_path, dnspass, machinepass): + """Add DC-specific bits to a secrets database. + + :param secretsdb: Ldb Handle to the secrets database + :param setup_path: Setup path function + :param machinepass: Machine password + """ + setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), { + "MACHINEPASS_B64": b64encode(machinepass), + "DOMAIN": domain, + "REALM": realm, + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), + "SECRETS_KEYTAB": keytab_path, + "NETBIOSNAME": netbiosname, + "SAM_LDB": samdb_url, + "DNS_KEYTAB": dns_keytab_path, + "DNSPASS_B64": b64encode(dnspass), + }) def setup_secretsdb(path, setup_path, session_info, credentials, lp): @@ -296,10 +399,12 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): :param session_info: Session info. :param credentials: Credentials :param lp: Loadparm context + :return: LDB handle for the created secrets database """ if os.path.exists(path): os.unlink(path) - secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp) + secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, + lp=lp) secrets_ldb.erase() secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif")) secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) @@ -316,7 +421,7 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp): :param lp: Loadparm context """ templates_ldb = SamDB(path, session_info=session_info, - credentials=credentials, lp=lp) + credentials=credentials, lp=lp) templates_ldb.erase() templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif")) @@ -359,69 +464,13 @@ def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, "CONFIGDN": configdn, "VERSION": samba.version(), }) - - -def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn): - """Setup SAM database partitions. - - :param samdb: Sam Database handle - :param setup_path: Setup path function - :param schemadn: Schema DN. - :param configdn: Configuration DN. - :param domaindn: Domain DN. - """ - #Add modules to the list to activate them by default - #beware often order is important - # - # Some Known ordering constraints: - # - rootdse must be first, as it makes redirects from "" -> cn=rootdse - # - objectclass must be before password_hash, because password_hash checks - # that the objectclass is of type person (filled in by objectclass - # module when expanding the objectclass list) - # - partition must be last - # - each partition has its own module list then - modules_list = ["rootdse", - "paged_results", - "ranged_results", - "anr", - "server_sort", - "extended_dn", - "asq", - "samldb", - "rdn_name", - "objectclass", - "kludge_acl", - "operational"] - tdb_modules_list = [ - "subtree_rename", - "subtree_delete", - "linked_attributes"] - modules_list2 = ["show_deleted", - "partition"] - - setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { - "SCHEMADN": schemadn, - "SCHEMADN_LDB": "schema.ldb", - "SCHEMADN_MOD2": ",objectguid", - "CONFIGDN": configdn, - "CONFIGDN_LDB": "configuration.ldb", - "DOMAINDN": domaindn, - "DOMAINDN_LDB": "users.ldb", - "SCHEMADN_MOD": "schema_fsmo", - "CONFIGDN_MOD": "naming_fsmo", - "CONFIGDN_MOD2": ",objectguid", - "DOMAINDN_MOD": "pdc_fsmo,password_hash", - "DOMAINDN_MOD2": ",objectguid", - "MODULES_LIST": ",".join(modules_list), - "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), - "MODULES_LIST2": ",".join(modules_list2), - }) - + def setup_self_join(samdb, configdn, schemadn, domaindn, netbiosname, hostname, dnsdomain, machinepass, dnspass, realm, domainname, domainsid, invocationid, setup_path, policyguid, hostguid=None): + """Join a host to its own domain.""" if hostguid is not None: hostguid_add = "objectGUID: %s" % hostguid else: @@ -451,43 +500,39 @@ def setup_self_join(samdb, configdn, schemadn, domaindn, def setup_samdb(path, setup_path, session_info, credentials, lp, schemadn, configdn, domaindn, dnsdomain, realm, netbiosname, message, hostname, rootdn, erase, - domainsid, aci, rdn_dc, domainguid, policyguid, - domainname, blank, adminpass, krbtgtpass, - machinepass, hostguid, invocationid, dnspass): - # Also wipes the database - message("Setting up sam.ldb") - samdb = SamDB(path, session_info=session_info, - credentials=credentials, lp=lp) + domainsid, aci, domainguid, policyguid, + domainname, fill, adminpass, krbtgtpass, + machinepass, hostguid, invocationid, dnspass, + serverrole, ldap_backend=None, ldap_backend_type=None): + """Setup a complete SAM Database. + + """ - message("Setting up sam.ldb partitions") - setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn) + # Also wipes the database + setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, + domaindn=domaindn, message=message, lp=lp, + credentials=credentials, session_info=session_info, + hostname=hostname, netbiosname=netbiosname, + dnsdomain=dnsdomain, realm=realm, rootdn=rootdn, + ldap_backend=ldap_backend, serverrole=serverrole, + ldap_backend_type=ldap_backend_type, erase=erase) samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) - samdb.transaction_start() - try: - message("Setting up sam.ldb attributes") - samdb.load_ldif_file_add(setup_path("provision_init.ldif")) - - message("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, - hostname, dnsdomain, realm, rootdn, configdn, - netbiosname) - - if erase: - message("Erasing data from partitions") - samdb.erase_partitions() - except: - samdb.transaction_cancel() - raise - - samdb.transaction_commit() + if fill == FILL_DRS: + # We want to finish here, but setup the index before we do so + message("Setting up sam.ldb index") + samdb.load_ldif_file_add(setup_path("provision_index.ldif")) + return samdb message("Pre-loading the Samba 4 and AD schema") samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(domainsid) + if lp.get("server role") == "domain controller": + samdb.set_invocation_id(invocationid) + load_schema(setup_path, samdb, schemadn, netbiosname, configdn) samdb.transaction_start() @@ -497,7 +542,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { "DOMAINDN": domaindn, "ACI": aci, - "RDN_DC": rdn_dc, }) message("Modifying DomainDN: " + domaindn + "") @@ -507,7 +551,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, domainguid_mod = "" setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), { - "RDN_DC": rdn_dc, "LDAPTIME": timestring(int(time.time())), "DOMAINSID": str(domainsid), "SCHEMADN": schemadn, @@ -538,7 +581,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") - setup_modify_ldif(samdb, setup_path("provision_schema_basedn_modify.ldif"), { + setup_modify_ldif(samdb, + setup_path("provision_schema_basedn_modify.ldif"), { "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "DEFAULTSITE": DEFAULTSITE, @@ -587,7 +631,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "CONFIGDN": configdn, }) - if not blank: + if fill == FILL_FULL: message("Setting up sam.ldb users and groups") setup_add_ldif(samdb, setup_path("provision_users.ldif"), { "DOMAINDN": domaindn, @@ -608,11 +652,9 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, hostname=hostname, hostguid=hostguid, setup_path=setup_path) + #We want to setup the index last, as adds are faster unindexed message("Setting up sam.ldb index") samdb.load_ldif_file_add(setup_path("provision_index.ldif")) - - message("Setting up sam.ldb rootDSE marking as synchronized") - setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) except: samdb.transaction_cancel() raise @@ -620,14 +662,18 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb.transaction_commit() return samdb - -def provision(lp, setup_dir, message, blank, paths, session_info, - credentials, ldapbackend, realm=None, domain=None, hostname=None, - hostip=None, domainsid=None, hostguid=None, adminpass=None, - krbtgtpass=None, domainguid=None, policyguid=None, - invocationid=None, machinepass=None, dnspass=None, root=None, - nobody=None, nogroup=None, users=None, wheel=None, backup=None, - aci=None, serverrole=None): +FILL_FULL = "FULL" +FILL_NT4SYNC = "NT4SYNC" +FILL_DRS = "DRS" + +def provision(lp, setup_dir, message, paths, session_info, + credentials, ldapbackend, samdb_fill=FILL_FULL, realm=None, rootdn=None, + domain=None, hostname=None, hostip=None, domainsid=None, + hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, + policyguid=None, invocationid=None, machinepass=None, + dnspass=None, root=None, nobody=None, nogroup=None, users=None, + wheel=None, backup=None, aci=None, serverrole=None, erase=False, + ldap_backend=None, ldap_backend_type=None): """Provision samba4 :note: caution, this wipes all existing data! @@ -636,14 +682,10 @@ def provision(lp, setup_dir, message, blank, paths, session_info, def setup_path(file): return os.path.join(setup_dir, file) - erase = False - if domainsid is None: domainsid = security.random_sid() if policyguid is None: policyguid = uuid.random() - if invocationid is None: - invocationid = uuid.random() if adminpass is None: adminpass = misc.random_password(12) if krbtgtpass is None: @@ -669,29 +711,25 @@ def provision(lp, setup_dir, message, blank, paths, session_info, aci = "# no aci for local ldb" if serverrole is None: serverrole = lp.get("server role") + if invocationid is None and serverrole == "domain controller": + invocationid = uuid.random() if realm is None: realm = lp.get("realm") - else: - if lp.get("realm").upper() != realm.upper(): - raise Exception("realm '%s' in smb.conf must match chosen realm '%s'\n" % + + if lp.get("realm").upper() != realm.upper(): + raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % (lp.get("realm"), realm)) + ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path) + + if ldap_backend == "ldapi": + # provision-backend will set this path suggested slapd command line / fedorads.inf + ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi")) + assert realm is not None realm = realm.upper() - if domain is None: - domain = lp.get("workgroup") - else: - if lp.get("workgroup").upper() != domain.upper(): - raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", - lp.get("workgroup"), domain) - - assert domain is not None - domain = domain.upper() - if not valid_netbios_name(domain): - raise InvalidNetbiosName(domain) - if hostname is None: hostname = gethostname().split(".")[0].lower() @@ -703,13 +741,30 @@ def provision(lp, setup_dir, message, blank, paths, session_info, raise InvalidNetbiosName(netbiosname) dnsdomain = realm.lower() - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") - rootdn = domaindn + if serverrole == "domain controller": + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + if domain is None: + domain = lp.get("workgroup") + + if lp.get("workgroup").upper() != domain.upper(): + raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'", + lp.get("workgroup"), domain) + + assert domain is not None + domain = domain.upper() + if not valid_netbios_name(domain): + raise InvalidNetbiosName(domain) + + else: + domaindn = "CN=" + netbiosname + domain = netbiosname + + if rootdn is None: + rootdn = domaindn + configdn = "CN=Configuration," + rootdn schemadn = "CN=Schema," + configdn - rdn_dc = domaindn.split(",")[0][len("DC="):] - message("set DOMAIN SID: %s" % str(domainsid)) message("Provisioning for %s in realm %s" % (domain, realm)) message("Using administrator password: %s" % adminpass) @@ -725,7 +780,8 @@ def provision(lp, setup_dir, message, blank, paths, session_info, smbconfsuffix = "member" else: assert "Invalid server role setting: %s" % serverrole - setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), + paths.smbconf, { "HOSTNAME": hostname, "DOMAIN_CONF": domain, "REALM_CONF": realm, @@ -742,6 +798,7 @@ def provision(lp, setup_dir, message, blank, paths, session_info, credentials=credentials, lp=lp) share_ldb.load_ldif_file_add(setup_path("share.ldif")) + message("Setting up secrets.ldb") secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info=session_info, @@ -755,44 +812,47 @@ def provision(lp, setup_dir, message, blank, paths, session_info, setup_templatesdb(paths.templates, setup_path, session_info=session_info, credentials=credentials, lp=lp) - samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials, - lp=lp, schemadn=schemadn, configdn=configdn, domaindn=domaindn, - dnsdomain=dnsdomain, netbiosname=netbiosname, realm=realm, message=message, - hostname=hostname, rootdn=rootdn, erase=erase, domainsid=domainsid, aci=aci, - rdn_dc=rdn_dc, domainguid=domainguid, policyguid=policyguid, - domainname=domain, blank=blank, adminpass=adminpass, krbtgtpass=krbtgtpass, - hostguid=hostguid, invocationid=invocationid, machinepass=machinepass, - dnspass=dnspass) + samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, + credentials=credentials, lp=lp, schemadn=schemadn, + configdn=configdn, domaindn=domaindn, + dnsdomain=dnsdomain, netbiosname=netbiosname, + realm=realm, message=message, hostname=hostname, + rootdn=rootdn, erase=erase, domainsid=domainsid, + aci=aci, domainguid=domainguid, policyguid=policyguid, + domainname=domain, fill=samdb_fill, + adminpass=adminpass, krbtgtpass=krbtgtpass, + hostguid=hostguid, invocationid=invocationid, + machinepass=machinepass, dnspass=dnspass, + serverrole=serverrole, ldap_backend=ldap_backend, + ldap_backend_type=ldap_backend_type) if lp.get("server role") == "domain controller": - os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}"), 0755) - os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "Machine"), 0755) - os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755) - if not os.path.isdir(paths.netlogon): + policy_path = os.path.join(paths.sysvol, dnsdomain, "Policies", + "{" + policyguid + "}") + os.makedirs(policy_path, 0755) + os.makedirs(os.path.join(policy_path, "Machine"), 0755) + os.makedirs(os.path.join(policy_path, "User"), 0755) + if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0755) - secrets_ldb = Ldb(paths.secrets, session_info=session_info, credentials=credentials, lp=lp) - setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { - "MACHINEPASS_B64": b64encode(machinepass), - "DOMAIN": domain, - "REALM": realm, - "LDAPTIME": timestring(int(time.time())), - "DNSDOMAIN": dnsdomain, - "DOMAINSID": str(domainsid), - "SECRETS_KEYTAB": paths.keytab, - "NETBIOSNAME": netbiosname, - "SAM_LDB": paths.samdb, - "DNS_KEYTAB": paths.dns_keytab, - "DNSPASS_B64": b64encode(dnspass), - }) - - if not blank: - setup_name_mappings(samdb, str(domainsid), - domaindn, root=root, nobody=nobody, - nogroup=nogroup, wheel=wheel, users=users, - backup=backup) + secrets_ldb = Ldb(paths.secrets, session_info=session_info, + credentials=credentials, lp=lp) + secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=realm, + netbiosname=netbiosname, domainsid=domainsid, + keytab_path=paths.keytab, samdb_url=paths.samdb, + dns_keytab_path=paths.dns_keytab, dnspass=dnspass, + machinepass=machinepass, dnsdomain=dnsdomain) + + if samdb_fill == FILL_FULL: + setup_name_mappings(samdb, str(domainsid), domaindn, root=root, + nobody=nobody, nogroup=nogroup, wheel=wheel, + users=users, backup=backup) + + message("Setting up sam.ldb rootDSE marking as synchronized") + setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) message("Setting up phpLDAPadmin configuration") - create_phplpapdadmin_config(paths.phpldapadminconfig, setup_path, paths.s4_ldapi_path) + create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, + ldapi_url) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) @@ -816,15 +876,15 @@ def provision(lp, setup_dir, message, blank, paths, session_info, return domaindn -def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path): + +def create_phpldapadmin_config(path, setup_path, ldap_backend): """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"), - path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")}) + setup_file(setup_path("phpldapadmin-config.php"), path, + {"S4_LDAPI_URI": ldap_backend}) def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, @@ -874,6 +934,7 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "CONFIGDN": configdn, - "DEFAULTSITE": DEFAULTSITE}) + "DEFAULTSITE": DEFAULTSITE + }) samdb.attach_schema_from_ldif(head_data, schema_data) diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index e92a4bbb90..b757330ecb 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -1,10 +1,10 @@ #!/usr/bin/python # Unix SMB/CIFS implementation. -# Copyright (C) Jelmer Vernooij 2007 +# Copyright (C) Jelmer Vernooij 2007-2008 # # Based on the original in EJS: -# Copyright (C) Andrew Tridgell 2005 +# Copyright (C) Andrew Tridgell 2005 # # 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 @@ -151,4 +151,4 @@ member: %s :param invocation_id: GUID of the invocation id. """ - misc.samdb_set_ntds_invocation_id(self, invocation_id) \ No newline at end of file + misc.dsdb_set_ntds_invocation_id(self, invocation_id) diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index 6fbf420339..9839811470 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/python # Unix SMB/CIFS implementation. -# Copyright (C) Jelmer Vernooij 2007 +# Copyright (C) Jelmer Vernooij 2007-2008 # # 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 diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index abf1127c36..a118af2526 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -7,7 +7,7 @@ """Support code for upgrading from Samba 3 to Samba 4.""" -from provision import findnss, provision +from provision import findnss, provision, FILL_DRS import grp import ldb import pwd @@ -245,7 +245,8 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: machinepass = None - domaindn = provision(lp=lp, setup_dir=setup_dir, message=message, blank=True, ldapbackend=None, + domaindn = provision(lp=lp, setup_dir=setup_dir, message=message, + samdb_fill=FILL_DRS, ldapbackend=None, paths=paths, session_info=session_info, credentials=credentials, realm=realm, domain=domainname, domainsid=domainsid, domainguid=domainguid, machinepass=machinepass, serverrole=serverrole) -- cgit From 76eb7ddd75719eb516a0dc10a88e23fd6463a718 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 25 Jan 2008 01:30:43 +0100 Subject: python: fix tests for check_all_substituted. (This used to be commit 859cffed9d3a62f9f7610d74472aa3c0d1979a35) --- source4/scripting/python/samba/tests/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index 9839811470..e557dd95be 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -69,8 +69,8 @@ class SubstituteVarTestCase(unittest.TestCase): samba.substitute_var("foo ${bla} gsff", {"bar": "bla"})) def test_check_all_substituted(self): - check_all_substituted("nothing to see here") - self.assertRaises(Exception, check_all_substituted, "Not subsituted: ${FOOBAR}") + samba.check_all_substituted("nothing to see here") + self.assertRaises(Exception, samba.check_all_substituted, "Not subsituted: ${FOOBAR}") class LdbExtensionTests(TestCaseInTempDir): -- cgit From c91791bbc489d90eca5f6b8d6dc369d7e2129c29 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 25 Jan 2008 01:37:47 +0100 Subject: python: Add test for secretsdb_become_dc (This used to be commit 9173c678efb6f74dbec64298bcb00952feff2ed7) --- source4/scripting/python/samba/tests/provision.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index f5a0339c1f..83952df9fe 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -1,7 +1,7 @@ #!/usr/bin/python # Unix SMB/CIFS implementation. -# Copyright (C) Jelmer Vernooij 2007 +# Copyright (C) Jelmer Vernooij 2007-2008 # # 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 @@ -18,7 +18,7 @@ # import os -from samba.provision import setup_secretsdb +from samba.provision import setup_secretsdb, secretsdb_become_dc import samba.tests from ldb import Dn @@ -37,7 +37,22 @@ class ProvisionTestCase(samba.tests.TestCaseInTempDir): finally: del ldb os.unlink(path) - + + def test_become_dc(self): + path = os.path.join(self.tempdir, "secrets.ldb") + secrets_ldb = setup_secretsdb(path, setup_path, None, None, None) + try: + secretsdb_become_dc(secrets_ldb, setup_path, domain="EXAMPLE", + realm="example", netbiosname="myhost", + domainsid="S-5-22", keytab_path="keytab.path", + samdb_url="ldap://url/", + dns_keytab_path="dns.keytab", dnspass="bla", + machinepass="machinepass", dnsdomain="example.com") + self.assertEquals(1, + len(secrets_ldb.search("samAccountName=krbtgt,flatname=EXAMPLE,CN=Principals"))) + finally: + del secrets_ldb + os.unlink(path) class Disabled: def test_setup_templatesdb(self): -- cgit From dcb04065cda7fc7f23c494ec138af6b882651f20 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 25 Jan 2008 03:54:33 +0100 Subject: python: Fix representation of UUIDs as strings in zone files rather than binary blobs, fix escaping of LDAP URL's in PHP LDAP admin configuration. Pair-programmed with Andrew, but git doesn't appear to support multiple --author arguments. :-( (This used to be commit dff54ff043563f93b86361039c46e662045f62cc) --- source4/scripting/python/samba/__init__.py | 4 ++-- source4/scripting/python/samba/provision.py | 11 ++++++----- source4/scripting/python/samba/samdb.py | 2 +- source4/scripting/python/samba/tests/__init__.py | 2 +- source4/scripting/python/samba/tests/provision.py | 10 +++++++++- 5 files changed, 19 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 5c14edd357..b041165800 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -91,7 +91,7 @@ class Ldb(ldb.Ldb): set_session_info = misc.ldb_set_session_info set_loadparm = misc.ldb_set_loadparm - def searchone(self, basedn, attribute, expression=None, + def searchone(self, attribute, basedn=None, expression=None, scope=ldb.SCOPE_BASE): """Search for one attribute as a string. @@ -106,7 +106,7 @@ class Ldb(ldb.Ldb): return None values = set(res[0][attribute]) assert len(values) == 1 - return values.pop() + return self.schema_format_value(attribute, values.pop()) def erase(self): """Erase this ldb, removing all records.""" diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 918d983782..0e498f65e5 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -725,7 +725,7 @@ def provision(lp, setup_dir, message, paths, session_info, if ldap_backend == "ldapi": # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi")) + ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), "") assert realm is not None realm = realm.upper() @@ -860,9 +860,9 @@ def provision(lp, setup_dir, message, paths, session_info, samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) - domainguid = samdb.searchone(domaindn, "objectGUID") + domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") assert isinstance(domainguid, str) - hostguid = samdb.searchone(domaindn, "objectGUID", + hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", expression="(&(objectClass=computer)(cn=%s))" % hostname, scope=SCOPE_SUBTREE) assert isinstance(hostguid, str) @@ -877,14 +877,14 @@ def provision(lp, setup_dir, message, paths, session_info, return domaindn -def create_phpldapadmin_config(path, setup_path, ldap_backend): +def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. :param path: Path to write the configuration to. :param setup_path: Function to generate setup paths. """ setup_file(setup_path("phpldapadmin-config.php"), path, - {"S4_LDAPI_URI": ldap_backend}) + {"S4_LDAPI_URI": ldapi_uri}) def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, @@ -903,6 +903,7 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, :param domainguid: GUID of the domain. :param hostguid: GUID of the host. """ + assert isinstance(domainguid, str) setup_file(setup_path("provision.zone"), path, { "DNSPASS_B64": b64encode(dnspass), diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index b757330ecb..c11fabf553 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -105,7 +105,7 @@ userAccountControl: %u assert(len(res) == 1 and res[0].defaultNamingContext is not None) domain_dn = res[0]["defaultNamingContext"][0] assert(domain_dn is not None) - dom_users = self.searchone(domain_dn, "dn", "name=Domain Users") + dom_users = self.searchone(basedn=domain_dn, attribute="dn", expression="name=Domain Users") assert(dom_users is not None) user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index e557dd95be..9402002674 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -79,7 +79,7 @@ class LdbExtensionTests(TestCaseInTempDir): l = samba.Ldb(path) try: l.add({"dn": "foo=dc", "bar": "bla"}) - self.assertEquals("bla", l.searchone(ldb.Dn(l, "foo=dc"), "bar")) + self.assertEquals("bla", l.searchone(basedn=ldb.Dn(l, "foo=dc"), attribute="bar")) finally: del l os.unlink(path) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index 83952df9fe..1456b6751c 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -33,7 +33,7 @@ class ProvisionTestCase(samba.tests.TestCaseInTempDir): ldb = setup_secretsdb(path, setup_path, None, None, None) try: self.assertEquals("LSA Secrets", - ldb.searchone(Dn(ldb, "CN=LSA Secrets"), "CN")) + ldb.searchone(basedn="CN=LSA Secrets", attribute="CN")) finally: del ldb os.unlink(path) @@ -50,6 +50,14 @@ class ProvisionTestCase(samba.tests.TestCaseInTempDir): machinepass="machinepass", dnsdomain="example.com") self.assertEquals(1, len(secrets_ldb.search("samAccountName=krbtgt,flatname=EXAMPLE,CN=Principals"))) + self.assertEquals("keytab.path", + secrets_ldb.searchone(basedn="flatname=EXAMPLE,CN=primary domains", + expression="(privateKeytab=*)", + attribute="privateKeytab")) + self.assertEquals("S-5-22", + secrets_ldb.searchone(basedn="flatname=EXAMPLE,CN=primary domains", + expression="objectSid=*", attribute="objectSid")) + finally: del secrets_ldb os.unlink(path) -- cgit From 1b18de131c556280004dea6393e22547c9681fd9 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 25 Jan 2008 17:11:20 +1100 Subject: Tidy up the last regresesions on the python smbscript, from my work with Jelmer today. The only remaining issue is that for the build farm, we will need to manually specify the users and groups from the NSS_WRAPPPER, as python isn't compiled with this. Andrew Bartlett (This used to be commit 5370484d25b8c7a5bde730d9be36ecbbb0aaf315) --- source4/scripting/python/samba/provision.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0e498f65e5..26c4afe3c8 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -188,12 +188,17 @@ def provision_paths_from_lp(lp, dnsdomain, private_dir=None): paths = ProvisionPaths() if private_dir is None: private_dir = lp.get("private dir") + paths.keytab = "secrets.keytab" + paths.dns_keytab = "dns.keytab" + else: + paths.keytab = os.path.join(private_dir, "secrets.keytab") + paths.dns_keytab = os.path.join(private_dir, "dns.keytab") + paths.shareconf = os.path.join(private_dir, "share.ldb") paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") - paths.keytab = os.path.join(private_dir, "secrets.keytab") - paths.dns_keytab = os.path.join(private_dir, "dns.keytab") + paths.dns = os.path.join(private_dir, dnsdomain + ".zone") paths.winsdb = os.path.join(private_dir, "wins.ldb") paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") @@ -407,6 +412,8 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): lp=lp) secrets_ldb.erase() secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif")) + secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, + lp=lp) secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) return secrets_ldb @@ -695,18 +702,18 @@ def provision(lp, setup_dir, message, paths, session_info, if dnspass is None: dnspass = misc.random_password(12) if root is None: - root = findnss(pwd.getpwnam, "root")[4] + root = findnss(pwd.getpwnam, "root")[0] if nobody is None: - nobody = findnss(pwd.getpwnam, "nobody")[4] + nobody = findnss(pwd.getpwnam, "nobody")[0] if nogroup is None: - nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[0] if users is None: users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", - "usr")[2] + "usr")[0] if wheel is None: - wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] + wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[0] if backup is None: - backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] + backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[0] if aci is None: aci = "# no aci for local ldb" if serverrole is None: @@ -721,11 +728,11 @@ def provision(lp, setup_dir, message, paths, session_info, raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % (lp.get("realm"), realm)) - ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path) + ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") if ldap_backend == "ldapi": # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), "") + ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), safe="") assert realm is not None realm = realm.upper() -- cgit From 6c2d4f2806bae8072d61ba8795832d9a9e75573e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 25 Jan 2008 11:47:44 +0100 Subject: python/provision: Reload secrets when necessary, fix unix names in mappings. Pair programmed with Andrew. (This used to be commit 04fe8c8aefae8da8966954d0654c37adf2d0361d) --- source4/scripting/python/samba/provision.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0e498f65e5..4d99cd9cd9 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -193,7 +193,7 @@ def provision_paths_from_lp(lp, dnsdomain, private_dir=None): paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") paths.keytab = os.path.join(private_dir, "secrets.keytab") - paths.dns_keytab = os.path.join(private_dir, "dns.keytab") + paths.dns_keytab = "dns.keytab" paths.dns = os.path.join(private_dir, dnsdomain + ".zone") paths.winsdb = os.path.join(private_dir, "wins.ldb") paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") @@ -407,6 +407,8 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): lp=lp) secrets_ldb.erase() secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif")) + secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, + lp=lp) secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) return secrets_ldb @@ -695,18 +697,18 @@ def provision(lp, setup_dir, message, paths, session_info, if dnspass is None: dnspass = misc.random_password(12) if root is None: - root = findnss(pwd.getpwnam, "root")[4] + root = findnss(pwd.getpwnam, "root")[0] if nobody is None: - nobody = findnss(pwd.getpwnam, "nobody")[4] + nobody = findnss(pwd.getpwnam, "nobody")[0] if nogroup is None: - nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[0] if users is None: users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", - "usr")[2] + "usr")[0] if wheel is None: - wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] + wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[0] if backup is None: - backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] + backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[0] if aci is None: aci = "# no aci for local ldb" if serverrole is None: -- cgit From 172e00d8a174646e4e1279e66805c24eeac00c40 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 26 Jan 2008 02:55:03 +0100 Subject: python: Load smb.conf file for the provision tests. (This used to be commit 41571bbb933c763a9608f4ba56f1a5a97af133ab) --- source4/scripting/python/samba/tests/provision.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index 1456b6751c..4e9fa9c3ef 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -21,6 +21,10 @@ import os from samba.provision import setup_secretsdb, secretsdb_become_dc import samba.tests from ldb import Dn +import param + +lp = param.LoadParm() +lp.load("st/dc/etc/smb.conf") setup_dir = "setup" def setup_path(file): @@ -30,7 +34,7 @@ def setup_path(file): class ProvisionTestCase(samba.tests.TestCaseInTempDir): def test_setup_secretsdb(self): path = os.path.join(self.tempdir, "secrets.ldb") - ldb = setup_secretsdb(path, setup_path, None, None, None) + ldb = setup_secretsdb(path, setup_path, None, None, lp=lp) try: self.assertEquals("LSA Secrets", ldb.searchone(basedn="CN=LSA Secrets", attribute="CN")) @@ -40,7 +44,7 @@ class ProvisionTestCase(samba.tests.TestCaseInTempDir): def test_become_dc(self): path = os.path.join(self.tempdir, "secrets.ldb") - secrets_ldb = setup_secretsdb(path, setup_path, None, None, None) + secrets_ldb = setup_secretsdb(path, setup_path, None, None, lp=lp) try: secretsdb_become_dc(secrets_ldb, setup_path, domain="EXAMPLE", realm="example", netbiosname="myhost", -- cgit From cab677a33f0376cd1bf96ec561dc0463bbf80edd Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 26 Jan 2008 04:22:42 +0100 Subject: python: Use relative paths for registry. (This used to be commit 079200b824de6dd8c7de3e5b76ed1805fde02965) --- source4/scripting/python/samba/provision.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f244679eb5..d2a4f28b64 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -203,7 +203,13 @@ def provision_paths_from_lp(lp, dnsdomain, private_dir=None): paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php") - paths.hklm = os.path.join(private_dir, "hklm.ldb") + paths.hklm = "hklm.ldb" + paths.hkcr = "hkcr.ldb" + paths.hkcu = "hkcu.ldb" + paths.hku = "hku.ldb" + paths.hkpd = "hkpd.ldb" + paths.hkpt = "hkpt.ldb" + paths.sysvol = lp.get("sysvol", "path") if paths.sysvol is None: paths.sysvol = os.path.join(lp.get("lock dir"), "sysvol") @@ -442,6 +448,7 @@ def setup_registry(path, setup_path, session_info, credentials, lp): :param lp: Loadparm context """ reg = registry.Registry() + print path hive = registry.open_ldb(path, session_info=session_info, credentials=credentials, lp_ctx=lp) reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") -- cgit From fffe4f3bdd27b11dce75c9b2c931f5291f04ab6b Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 8 Feb 2008 03:03:44 +0100 Subject: Fix formatting. (This used to be commit 73d1b0fcb64fdc7be1e1e1002f3f182fcbe476ae) --- source4/scripting/python/samba/provision.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d2a4f28b64..bcadcca583 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -319,14 +319,14 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, domaindn_ldb = "users.ldb" if ldap_backend is not None: - domaindn_ldb = ldap_backend + domaindn_ldb = ldap_backend configdn_ldb = "configuration.ldb" if ldap_backend is not None: - configdn_ldb = ldap_backend + configdn_ldb = ldap_backend schema_ldb = "schema.ldb" if ldap_backend is not None: - schema_ldb = ldap_backend - + schema_ldb = ldap_backend + if ldap_backend_type == "fedora-ds": backend_modules = ["nsuniqueid","paged_searches"] elif ldap_backend_type == "openldap": @@ -737,8 +737,8 @@ def provision(lp, setup_dir, message, paths, session_info, ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") if ldap_backend == "ldapi": - # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), safe="") + # provision-backend will set this path suggested slapd command line / fedorads.inf + ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), safe="") assert realm is not None realm = realm.upper() @@ -755,7 +755,7 @@ def provision(lp, setup_dir, message, paths, session_info, dnsdomain = realm.lower() if serverrole == "domain controller": - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") if domain is None: domain = lp.get("workgroup") @@ -769,9 +769,9 @@ def provision(lp, setup_dir, message, paths, session_info, raise InvalidNetbiosName(domain) else: - domaindn = "CN=" + netbiosname - domain = netbiosname - + domaindn = "CN=" + netbiosname + domain = netbiosname + if rootdn is None: rootdn = domaindn -- cgit From 26897518ea88e6c70eda4031e62c02fcbcdb0fc0 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 8 Feb 2008 17:11:26 +1100 Subject: Fix LDAP backend with python We were still setting the hard-coded users.ldb etc, rather than switching to the ldapi:// URI Andrew Bartlett (This used to be commit 603e981250b26b533ec35dd607cb635226cf99df) --- source4/scripting/python/samba/provision.py | 44 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d2a4f28b64..9a44983d8e 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -323,9 +323,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, configdn_ldb = "configuration.ldb" if ldap_backend is not None: configdn_ldb = ldap_backend - schema_ldb = "schema.ldb" + schemadn_ldb = "schema.ldb" if ldap_backend is not None: - schema_ldb = ldap_backend + schemadn_ldb = ldap_backend if ldap_backend_type == "fedora-ds": backend_modules = ["nsuniqueid","paged_searches"] @@ -336,23 +336,31 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, else: backend_modules = ["objectguid"] - setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { - "SCHEMADN": schemadn, - "SCHEMADN_LDB": "schema.ldb", - "SCHEMADN_MOD2": ",objectguid", - "CONFIGDN": configdn, - "CONFIGDN_LDB": "configuration.ldb", - "DOMAINDN": domaindn, - "DOMAINDN_LDB": "users.ldb", - "SCHEMADN_MOD": "schema_fsmo,instancetype", - "CONFIGDN_MOD": "naming_fsmo,instancetype", - "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype", - "MODULES_LIST": ",".join(modules_list), - "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), - "MODULES_LIST2": ",".join(modules_list2), - "BACKEND_MOD": ",".join(backend_modules), + samdb.transaction_start() + try: + setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { + "SCHEMADN": schemadn, + "SCHEMADN_LDB": schemadn_ldb, + "SCHEMADN_MOD2": ",objectguid", + "CONFIGDN": configdn, + "CONFIGDN_LDB": configdn_ldb, + "DOMAINDN": domaindn, + "DOMAINDN_LDB": domaindn_ldb, + "SCHEMADN_MOD": "schema_fsmo,instancetype", + "CONFIGDN_MOD": "naming_fsmo,instancetype", + "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype", + "MODULES_LIST": ",".join(modules_list), + "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), + "MODULES_LIST2": ",".join(modules_list2), + "BACKEND_MOD": ",".join(backend_modules), }) + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + samdb = SamDB(samdb_path, session_info=session_info, credentials=credentials, lp=lp) @@ -680,7 +688,7 @@ FILL_NT4SYNC = "NT4SYNC" FILL_DRS = "DRS" def provision(lp, setup_dir, message, paths, session_info, - credentials, ldapbackend, samdb_fill=FILL_FULL, realm=None, rootdn=None, + credentials, samdb_fill=FILL_FULL, realm=None, rootdn=None, domain=None, hostname=None, hostip=None, domainsid=None, hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, -- cgit From c1d8ac0ab1226c27a46fcbb0101c2921d63de599 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 9 Feb 2008 01:42:38 +0100 Subject: Remove unused class members. (This used to be commit 373ef4287f998b79bf9ba6364d6a67e5c522833d) --- source4/scripting/python/samba/provision.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0c16ab3bfe..e15f205813 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -64,9 +64,6 @@ class ProvisionPaths: self.dns_keytab = None self.dns = None self.winsdb = None - self.ldap_basedn_ldif = None - self.ldap_config_basedn_ldif = None - self.ldap_schema_basedn_ldif = None def check_install(lp, session_info, credentials): @@ -201,6 +198,7 @@ def provision_paths_from_lp(lp, dnsdomain, private_dir=None): paths.dns = os.path.join(private_dir, dnsdomain + ".zone") paths.winsdb = os.path.join(private_dir, "wins.ldb") paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") + paths.smbconf = os.path.join(private_dir, "smb.conf") paths.phpldapadminconfig = os.path.join(private_dir, "phpldapadmin-config.php") paths.hklm = "hklm.ldb" @@ -812,7 +810,7 @@ def provision(lp, setup_dir, message, paths, session_info, "NETLOGONPATH": paths.netlogon, "SYSVOLPATH": paths.sysvol, }) - lp.reload() + lp.load(paths.smbconf) # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): -- cgit From 2aac2a5df8a03a42ed92e84f093b8aa5ba16dd1d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 9 Feb 2008 02:10:49 +0100 Subject: Add tests for findnss(), add some docstrings. (This used to be commit 4eec2bbc9a139e927ce21c615ebfbb3026b26384) --- source4/scripting/python/samba/provision.py | 39 +++++++++++++++-------- source4/scripting/python/samba/tests/provision.py | 23 ++++++++++++- 2 files changed, 48 insertions(+), 14 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index e15f205813..b094581fb4 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -81,14 +81,19 @@ def check_install(lp, session_info, credentials): raise "No administrator account found" -def findnss(nssfn, *names): - """Find a user or group from a list of possibilities.""" +def findnss(nssfn, names): + """Find a user or group from a list of possibilities. + + :param nssfn: NSS Function to try (should raise KeyError if not found) + :param names: Names to check. + :return: Value return by first names list. + """ for name in names: try: return nssfn(name) except KeyError: pass - raise Exception("Unable to find user/group for %s" % arguments[1]) + raise KeyError("Unable to find user/group %r" % names) def open_ldb(session_info, credentials, lp, dbname): @@ -146,6 +151,14 @@ def setup_modify_ldif(ldb, ldif_path, substvars=None): def setup_ldb(ldb, ldif_path, subst_vars): + """Import a LDIF a file into a LDB handle, optionally substituting variables. + + :note: Either all LDIF data will be added or none (using transactions). + + :param ldb: LDB file to import into. + :param ldif_path: Path to the LDIF file. + :param subst_vars: Dictionary with substitution variables. + """ assert ldb is not None ldb.transaction_start() try: @@ -716,18 +729,18 @@ def provision(lp, setup_dir, message, paths, session_info, if dnspass is None: dnspass = misc.random_password(12) if root is None: - root = findnss(pwd.getpwnam, "root")[0] + root = findnss(pwd.getpwnam, ["root"])[0] if nobody is None: - nobody = findnss(pwd.getpwnam, "nobody")[0] + nobody = findnss(pwd.getpwnam, ["nobody"])[0] if nogroup is None: - nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[0] + nogroup = findnss(grp.getgrnam, ["nogroup", "nobody"])[0] if users is None: - users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", - "usr")[0] + users = findnss(grp.getgrnam, ["users", "guest", "other", "unknown", + "usr"])[0] if wheel is None: - wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[0] + wheel = findnss(grp.getgrnam, ["wheel", "root", "staff", "adm"])[0] if backup is None: - backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[0] + backup = findnss(grp.getgrnam, ["backup", "wheel", "root", "staff"])[0] if aci is None: aci = "# no aci for local ldb" if serverrole is None: @@ -781,10 +794,10 @@ def provision(lp, setup_dir, message, paths, session_info, domain = netbiosname if rootdn is None: - rootdn = domaindn + rootdn = domaindn - configdn = "CN=Configuration," + rootdn - schemadn = "CN=Schema," + configdn + configdn = "CN=Configuration," + rootdn + schemadn = "CN=Schema," + configdn message("set DOMAIN SID: %s" % str(domainsid)) message("Provisioning for %s in realm %s" % (domain, realm)) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index 4e9fa9c3ef..eb49f7af83 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -18,10 +18,11 @@ # import os -from samba.provision import setup_secretsdb, secretsdb_become_dc +from samba.provision import setup_secretsdb, secretsdb_become_dc, findnss import samba.tests from ldb import Dn import param +import unittest lp = param.LoadParm() lp.load("st/dc/etc/smb.conf") @@ -66,6 +67,25 @@ class ProvisionTestCase(samba.tests.TestCaseInTempDir): del secrets_ldb os.unlink(path) + +class FindNssTests(unittest.TestCase): + """Test findnss() function.""" + def test_nothing(self): + def x(y): + raise KeyError + self.assertRaises(KeyError, findnss, x, []) + + def test_first(self): + self.assertEquals("bla", findnss(lambda x: "bla", ["bla"])) + + def test_skip_first(self): + def x(y): + if y != "bla": + raise KeyError + return "ha" + self.assertEquals("ha", findnss(x, ["bloe", "bla"])) + + class Disabled: def test_setup_templatesdb(self): raise NotImplementedError(self.test_setup_templatesdb) @@ -100,3 +120,4 @@ class Disabled: def test_erase_partitions(self): raise NotImplementedError(self.test_erase_partitions) + -- cgit From bd0bfe683386f983318b507c5a614f818cdfb38d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 9 Feb 2008 03:09:56 +0100 Subject: Fix provision python test. (This used to be commit b173fa6bd2b24b5a3e7b4fbcb926f6c9771c10ba) --- source4/scripting/python/samba/provision.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index b094581fb4..7dd564fae1 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -189,20 +189,16 @@ def setup_file(template, fname, substvars): open(f, 'w').write(data) -def provision_paths_from_lp(lp, dnsdomain, private_dir=None): +def provision_paths_from_lp(lp, dnsdomain): """Set the default paths for provisioning. :param lp: Loadparm context. :param dnsdomain: DNS Domain name """ paths = ProvisionPaths() - if private_dir is None: - private_dir = lp.get("private dir") - paths.keytab = "secrets.keytab" - paths.dns_keytab = "dns.keytab" - else: - paths.keytab = os.path.join(private_dir, "secrets.keytab") - paths.dns_keytab = os.path.join(private_dir, "dns.keytab") + private_dir = lp.get("private dir") + paths.keytab = "secrets.keytab" + paths.dns_keytab = "dns.keytab" paths.shareconf = os.path.join(private_dir, "share.ldb") paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") @@ -469,7 +465,6 @@ def setup_registry(path, setup_path, session_info, credentials, lp): :param lp: Loadparm context """ reg = registry.Registry() - print path hive = registry.open_ldb(path, session_info=session_info, credentials=credentials, lp_ctx=lp) reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") @@ -540,6 +535,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, serverrole, ldap_backend=None, ldap_backend_type=None): """Setup a complete SAM Database. + :note: This will wipe the main SAM database file! """ # Also wipes the database @@ -745,6 +741,7 @@ def provision(lp, setup_dir, message, paths, session_info, aci = "# no aci for local ldb" if serverrole is None: serverrole = lp.get("server role") + assert serverrole in ("domain controller", "member server") if invocationid is None and serverrole == "domain controller": invocationid = uuid.random() @@ -774,9 +771,9 @@ def provision(lp, setup_dir, message, paths, session_info, if not valid_netbios_name(netbiosname): raise InvalidNetbiosName(netbiosname) - dnsdomain = realm.lower() + dnsdomain = realm.lower() if serverrole == "domain controller": - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") if domain is None: domain = lp.get("workgroup") @@ -788,7 +785,6 @@ def provision(lp, setup_dir, message, paths, session_info, domain = domain.upper() if not valid_netbios_name(domain): raise InvalidNetbiosName(domain) - else: domaindn = "CN=" + netbiosname domain = netbiosname @@ -812,8 +808,6 @@ def provision(lp, setup_dir, message, paths, session_info, smbconfsuffix = "dc" elif serverrole == "member": smbconfsuffix = "member" - else: - assert "Invalid server role setting: %s" % serverrole setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { "HOSTNAME": hostname, @@ -953,7 +947,7 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): - """Load schema. + """Load schema for the SamDB. :param samdb: Load a schema into a SamDB. :param setup_path: Setup path function. -- cgit From 4932e4bb7ad11c6ef8ad3187063dba4e7481afa7 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 9 Feb 2008 03:59:45 +0100 Subject: Fix upgrade after provision parameter rename. (This used to be commit 361b9f43fb2abb64f2cbae7740b89a616a3c2646) --- source4/scripting/python/samba/upgrade.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index a118af2526..b332bb89ae 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -246,8 +246,8 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, machinepass = None domaindn = provision(lp=lp, setup_dir=setup_dir, message=message, - samdb_fill=FILL_DRS, ldapbackend=None, - paths=paths, session_info=session_info, credentials=credentials, realm=realm, + samdb_fill=FILL_DRS, paths=paths, session_info=session_info, + credentials=credentials, realm=realm, domain=domainname, domainsid=domainsid, domainguid=domainguid, machinepass=machinepass, serverrole=serverrole) -- cgit From 2fa4c158580a1e3efea7f8d121305d16eda815cb Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 9 Feb 2008 17:37:42 +0100 Subject: Fix syntax of docstrings, set project name when generating Python API documentation. (This used to be commit 68f13d87eb034fdbc712169f2d1b1a0475751ec5) --- source4/scripting/python/samba/provision.py | 6 ++---- source4/scripting/python/samba/upgrade.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 7dd564fae1..4f52d36167 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -278,13 +278,12 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, Alternatively, provision() may call this, and then populate the database. :param erase: Remove the existing data present in the database. - :param :note: This will wipe the Sam Database! :note: This function always removes the local SAM LDB file. The erase - parameter controls whether to erase the existing data, which - may not be stored locally but in LDAP. + parameter controls whether to erase the existing data, which + may not be stored locally but in LDAP. """ assert session_info is not None @@ -479,7 +478,6 @@ def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, :param samdb: Sam Database handle :param setup_path: Obtain setup path - ... """ setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), { "SCHEMADN": schemadn, diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index b332bb89ae..8bf75d776e 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -10,6 +10,7 @@ from provision import findnss, provision, FILL_DRS import grp import ldb +import time import pwd import uuid import registry @@ -162,7 +163,6 @@ def import_wins(samba4_winsdb, samba3_winsdb): :param samba3_winsdb: WINS database to import from """ version_id = 0 - import time for (name, (ttl, ips, nb_flags)) in samba3_winsdb.items(): version_id+=1 -- cgit From cf287aa831a538c9f6c95882cee382fa836756d1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 9 Feb 2008 17:42:31 +0100 Subject: Add docstring. (This used to be commit 073ed0dd1cc8fae9eb4a2f7ff6763124917c56e8) --- source4/scripting/python/samba/tests/provision.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index eb49f7af83..54a7782b3d 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -33,6 +33,8 @@ def setup_path(file): class ProvisionTestCase(samba.tests.TestCaseInTempDir): + """Some simple tests for individual functions in the provisioning code. + """ def test_setup_secretsdb(self): path = os.path.join(self.tempdir, "secrets.ldb") ldb = setup_secretsdb(path, setup_path, None, None, lp=lp) -- cgit From 2cf29aebff0dc821487e60ce86c18c6bbf1be866 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 9 Feb 2008 22:29:42 +0100 Subject: Add tests for upgrade of WINS database. (This used to be commit 7777611c0f32a693f0fa057c130e4ea491658f6b) --- source4/scripting/python/samba/tests/upgrade.py | 19 +++++++++++++++++-- source4/scripting/python/samba/upgrade.py | 4 +++- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/upgrade.py b/source4/scripting/python/samba/tests/upgrade.py index ddafa00691..4dc86ace8a 100644 --- a/source4/scripting/python/samba/tests/upgrade.py +++ b/source4/scripting/python/samba/tests/upgrade.py @@ -17,6 +17,21 @@ # along with this program. If not, see . # -import samba.upgrade -from unittest import TestCase +from samba import Ldb +from samba.upgrade import import_wins +from samba.tests import LdbTestCase +class WinsUpgradeTests(LdbTestCase): + def test_upgrade(self): + winsdb = { + "FOO#20": (200, ["127.0.0.1", "127.0.0.2"], 0x60) + } + import_wins(self.ldb, winsdb) + + self.assertEquals(['name=FOO,type=0x20'], + [str(m.dn) for m in self.ldb.search(expression="(objectClass=winsRecord)")]) + + def test_version(self): + import_wins(self.ldb, {}) + self.assertEquals("VERSION", + self.ldb.search(expression="(objectClass=winsMaxVersion)")[0]["cn"]) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 8bf75d776e..01b62ff984 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -18,6 +18,7 @@ from samba import Ldb from samba.samdb import SamDB def import_sam_policy(samldb, samba3_policy, domaindn): + """Import a Samba 3 policy database.""" samldb.modify_ldif(""" dn: %s changetype: modify @@ -201,7 +202,8 @@ def import_wins(samba4_winsdb, samba3_winsdb): "versionID": str(version_id), "address": ips}) - samba4_winsdb.add({"dn": "CN=VERSION", + samba4_winsdb.add({"dn": "cn=VERSION", + "cn": "VERSION", "objectClass": "winsMaxVersion", "maxVersion": str(version_id)}) -- cgit From af007e5837ac472f0527505c8013b837932136bc Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 11 Feb 2008 13:20:24 +0100 Subject: Use SMB_CONF_PATH environment variable inside tests rather than hardcoded paths. (This used to be commit eb04de69c0e319e18b148191946808f81e1cc8c4) --- source4/scripting/python/samba/tests/__init__.py | 6 ++++++ source4/scripting/python/samba/tests/dcerpc/registry.py | 4 ++-- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 5 ++--- source4/scripting/python/samba/tests/dcerpc/sam.py | 3 ++- source4/scripting/python/samba/tests/provision.py | 3 +-- 5 files changed, 13 insertions(+), 8 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index 9402002674..c8673d3fae 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -84,3 +84,9 @@ class LdbExtensionTests(TestCaseInTempDir): del l os.unlink(path) + +def get_loadparm(): + import param + lp = param.LoadParm() + lp.load(os.getenv("SMB_CONF_PATH")) + return lp diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index f3f0b0fb1a..147acc5098 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -20,11 +20,11 @@ import winreg from param import LoadParm import unittest +from samba.tests import get_loadparm class WinregTests(unittest.TestCase): def setUp(self): - lp_ctx = LoadParm() - lp_ctx.load("st/client/client.conf") + lp_ctx = get_loadparm() self.conn = winreg.winreg("ncalrpc:", lp_ctx) def get_hklm(self): diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 52c2bb8c72..8c1a8bec71 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -18,13 +18,12 @@ # import echo -from param import LoadParm import unittest +from samba.tests import get_loadparm class RpcEchoTests(unittest.TestCase): def setUp(self): - lp_ctx = LoadParm() - lp_ctx.load("st/client/client.conf") + lp_ctx = get_loadparm() self.conn = echo.rpcecho("ncalrpc:", lp_ctx) def test_addone(self): diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py index 50caaf2348..96348f2f69 100644 --- a/source4/scripting/python/samba/tests/dcerpc/sam.py +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -19,10 +19,11 @@ import samr import unittest +from samba.tests import get_loadparm class SamrTests(unittest.TestCase): def setUp(self): - self.conn = samr.samr("ncalrpc:", "st/client/client.conf") + self.conn = samr.samr("ncalrpc:", get_loadparm()) def test_connect5(self): (level, info, handle) = self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index 54a7782b3d..514582cbe4 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -24,8 +24,7 @@ from ldb import Dn import param import unittest -lp = param.LoadParm() -lp.load("st/dc/etc/smb.conf") +lp = samba.tests.get_loadparm() setup_dir = "setup" def setup_path(file): -- cgit From b4ce9dc3609aafd6df17bd3b57c0da63fdaba4b1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 13 Feb 2008 01:21:06 +0100 Subject: Fix invalid symbol. (This used to be commit bd0ef811c4e6419ba05076fbc151827cea5d1ca1) --- source4/scripting/python/samba/samdb.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index c11fabf553..3c6bb23c02 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -100,12 +100,14 @@ userAccountControl: %u self.transaction_start() # find the DNs for the domain and the domain users group - res = self.search("", SCOPE_BASE, "defaultNamingContext=*", - ["defaultNamingContext"]) + res = self.search("", scope=ldb.SCOPE_BASE, + expression="(defaultNamingContext=*)", + attrs=["defaultNamingContext"]) assert(len(res) == 1 and res[0].defaultNamingContext is not None) domain_dn = res[0]["defaultNamingContext"][0] assert(domain_dn is not None) - dom_users = self.searchone(basedn=domain_dn, attribute="dn", expression="name=Domain Users") + dom_users = self.searchone(basedn=domain_dn, attribute="dn", + expression="name=Domain Users") assert(dom_users is not None) user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) -- cgit From 08e3f99f14f178e87f3543261be59a7f97f60b4f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 13 Feb 2008 02:18:45 +0100 Subject: Initial work on a test for samba.tests.samdb (This used to be commit 8b33860954ca03be1ea45fd8d40963dbbd5b162f) --- source4/scripting/python/samba/provision.py | 3 +- source4/scripting/python/samba/tests/samdb.py | 55 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 source4/scripting/python/samba/tests/samdb.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 4f52d36167..97021fceb2 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -332,7 +332,6 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, schemadn_ldb = "schema.ldb" if ldap_backend is not None: schema_ldb = ldap_backend - schemadn_ldb = ldap_backend if ldap_backend_type == "fedora-ds": @@ -536,6 +535,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, :note: This will wipe the main SAM database file! """ + assert serverrole in ("domain controller", "member server") + # Also wipes the database setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, domaindn=domaindn, message=message, lp=lp, diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py new file mode 100644 index 0000000000..40e56bebb5 --- /dev/null +++ b/source4/scripting/python/samba/tests/samdb.py @@ -0,0 +1,55 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. Tests for SamDB +# Copyright (C) Jelmer Vernooij 2008 +# +# 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 . +# +from auth import system_session +from credentials import Credentials +import os +from samba.provision import setup_samdb +from samba.samdb import SamDB +from samba.tests import get_loadparm, TestCaseInTempDir +import security +from unittest import TestCase +import uuid + +class SamDBTestCase(TestCaseInTempDir): + def setUp(self): + super(SamDBTestCase, self).setUp() + invocationid = uuid.random() + domaindn = "DC=COM,DC=EXAMPLE" + self.domaindn = domaindn + configdn = "CN=Configuration," + domaindn + schemadn = "CN=Schema," + configdn + domainguid = uuid.random() + policyguid = uuid.random() + setup_path = lambda x: os.path.join("setup", x) + creds = Credentials() + domainsid = security.random_sid() + hostguid = uuid.random() + path = os.path.join(self.tempdir, "samdb.ldb") + self.samdb = setup_samdb(path, setup_path, system_session(), creds, + get_loadparm(), schemadn, configdn, + self.domaindn, "example.com", "EXAMPLE.COM", + "FOO", lambda x: None, "foo", domaindn, + False, domainsid, "# no aci", domainguid, + policyguid, "EXAMPLE", True, "secret", + "secret", "secret", hostguid, invocationid, + "secret", "domain controller") + + def test_add_foreign(self): + self.samdb.add_foreign(self.domaindn, "S-1-5-7", "Somedescription") + -- cgit From 85fe22a85fe7e8db7d2f6e2fdd6f02836f116b8e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 15 Feb 2008 15:14:55 +0100 Subject: Use struct for provision parameters since there are so many of them. (This used to be commit 4b9d5bc57ca4ee14c142ea720dce5e4ee97f8c16) --- source4/scripting/python/samba/provision.py | 40 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 97021fceb2..d30eaf3d7f 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -271,7 +271,7 @@ def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, credentials, configdn, schemadn, domaindn, hostname, netbiosname, dnsdomain, realm, - rootdn, serverrole, ldap_backend=None, + rootdn, serverrole, sitename, ldap_backend=None, ldap_backend_type=None, erase=False): """Setup the partitions for the SAM database. @@ -378,7 +378,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, message("Setting up sam.ldb rootDSE") setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, - dnsdomain, realm, rootdn, configdn, netbiosname) + dnsdomain, realm, rootdn, configdn, netbiosname, + sitename) if erase: message("Erasing data from partitions") @@ -472,7 +473,8 @@ def setup_registry(path, setup_path, session_info, credentials, lp): def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, - dnsdomain, realm, rootdn, configdn, netbiosname): + dnsdomain, realm, rootdn, configdn, netbiosname, + sitename): """Setup the SamDB rootdse. :param samdb: Sam Database handle @@ -482,7 +484,7 @@ def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "DNSDOMAIN": dnsdomain, - "DEFAULTSITE": DEFAULTSITE, + "DEFAULTSITE": sitename, "REALM": realm, "DNSNAME": "%s.%s" % (hostname, dnsdomain), "DOMAINDN": domaindn, @@ -495,7 +497,7 @@ def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, def setup_self_join(samdb, configdn, schemadn, domaindn, netbiosname, hostname, dnsdomain, machinepass, dnspass, realm, domainname, domainsid, invocationid, setup_path, - policyguid, hostguid=None): + policyguid, sitename, hostguid=None): """Join a host to its own domain.""" if hostguid is not None: hostguid_add = "objectGUID: %s" % hostguid @@ -508,7 +510,7 @@ def setup_self_join(samdb, configdn, schemadn, domaindn, "DOMAINDN": domaindn, "INVOCATIONID": invocationid, "NETBIOSNAME": netbiosname, - "DEFAULTSITE": DEFAULTSITE, + "DEFAULTSITE": sitename, "DNSNAME": "%s.%s" % (hostname, dnsdomain), "MACHINEPASS_B64": b64encode(machinepass), "DNSPASS_B64": b64encode(dnspass), @@ -529,7 +531,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, domainsid, aci, domainguid, policyguid, domainname, fill, adminpass, krbtgtpass, machinepass, hostguid, invocationid, dnspass, - serverrole, ldap_backend=None, ldap_backend_type=None): + serverrole, sitename, ldap_backend=None, + ldap_backend_type=None): """Setup a complete SAM Database. :note: This will wipe the main SAM database file! @@ -544,7 +547,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, hostname=hostname, netbiosname=netbiosname, dnsdomain=dnsdomain, realm=realm, rootdn=rootdn, ldap_backend=ldap_backend, serverrole=serverrole, - ldap_backend_type=ldap_backend_type, erase=erase) + ldap_backend_type=ldap_backend_type, erase=erase, + sitename=sitename) samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) @@ -562,7 +566,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, if lp.get("server role") == "domain controller": samdb.set_invocation_id(invocationid) - load_schema(setup_path, samdb, schemadn, netbiosname, configdn) + load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename) samdb.transaction_start() @@ -584,7 +588,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "DOMAINSID": str(domainsid), "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, - "DEFAULTSITE": DEFAULTSITE, + "DEFAULTSITE": sitename, "CONFIGDN": configdn, "POLICYGUID": policyguid, "DOMAINDN": domaindn, @@ -614,7 +618,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_path("provision_schema_basedn_modify.ldif"), { "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, - "DEFAULTSITE": DEFAULTSITE, + "DEFAULTSITE": sitename, "CONFIGDN": configdn, }) @@ -629,7 +633,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), { "CONFIGDN": configdn, "NETBIOSNAME": netbiosname, - "DEFAULTSITE": DEFAULTSITE, + "DEFAULTSITE": sitename, "DNSDOMAIN": dnsdomain, "DOMAIN": domainname, "SCHEMADN": schemadn, @@ -656,7 +660,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("provision.ldif"), { "DOMAINDN": domaindn, "NETBIOSNAME": netbiosname, - "DEFAULTSITE": DEFAULTSITE, + "DEFAULTSITE": sitename, "CONFIGDN": configdn, }) @@ -679,7 +683,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, machinepass=machinepass, domainname=domainname, domainsid=domainsid, policyguid=policyguid, hostname=hostname, hostguid=hostguid, - setup_path=setup_path) + setup_path=setup_path, sitename=sitename) #We want to setup the index last, as adds are faster unindexed message("Setting up sam.ldb index") @@ -702,7 +706,7 @@ def provision(lp, setup_dir, message, paths, session_info, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, wheel=None, backup=None, aci=None, serverrole=None, erase=False, - ldap_backend=None, ldap_backend_type=None): + ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): """Provision samba4 :note: caution, this wipes all existing data! @@ -851,7 +855,7 @@ def provision(lp, setup_dir, message, paths, session_info, hostguid=hostguid, invocationid=invocationid, machinepass=machinepass, dnspass=dnspass, serverrole=serverrole, ldap_backend=ldap_backend, - ldap_backend_type=ldap_backend_type) + ldap_backend_type=ldap_backend_type, sitename=sitename) if lp.get("server role") == "domain controller": policy_path = os.path.join(paths.sysvol, dnsdomain, "Policies", @@ -945,7 +949,7 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, }) -def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): +def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): """Load schema for the SamDB. :param samdb: Load a schema into a SamDB. @@ -962,7 +966,7 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "CONFIGDN": configdn, - "DEFAULTSITE": DEFAULTSITE + "DEFAULTSITE":sitename }) samdb.attach_schema_from_ldif(head_data, schema_data) -- cgit From 7c96ca88c4e6fc5bd9b0c585b0700cc04e0f517c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 16 Feb 2008 15:23:26 +0100 Subject: Formatting fixes. (This used to be commit bc0fab89e325ebb6ab870b1c3f4b263c50631b70) --- source4/scripting/python/samba/provision.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d30eaf3d7f..3e88b68509 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -335,9 +335,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, schemadn_ldb = ldap_backend if ldap_backend_type == "fedora-ds": - backend_modules = ["nsuniqueid","paged_searches"] + backend_modules = ["nsuniqueid", "paged_searches"] elif ldap_backend_type == "openldap": - backend_modules = ["normalise","entryuuid","paged_searches"] + backend_modules = ["normalise", "entryuuid", "paged_searches"] elif serverrole == "domain controller": backend_modules = ["repl_meta_data"] else: @@ -695,6 +695,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb.transaction_commit() return samdb + FILL_FULL = "FULL" FILL_NT4SYNC = "NT4SYNC" FILL_DRS = "DRS" -- cgit From 895874d9663ccb95883579d145018ec8a8add9c8 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Mon, 18 Feb 2008 14:33:58 +0100 Subject: idmap: Handle uid->SID mapping (This used to be commit 6ac6de8476ba036eb041e054bc37e4503dc2fde8) --- source4/scripting/python/samba/provision.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 3e88b68509..e3c47ff4a2 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -59,6 +59,7 @@ class ProvisionPaths: self.hkpd = None self.hkpt = None self.samdb = None + self.idmapdb = None self.secrets = None self.keytab = None self.dns_keytab = None @@ -202,6 +203,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.shareconf = os.path.join(private_dir, "share.ldb") paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") + paths.idmapdb = os.path.join(private_dir, lp.get("idmap database") or "idmap.ldb") paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") paths.dns = os.path.join(private_dir, dnsdomain + ".zone") @@ -471,6 +473,24 @@ def setup_registry(path, setup_path, session_info, credentials, lp): assert os.path.exists(provision_reg) reg.diff_apply(provision_reg) +def setup_idmapdb(path, setup_path, session_info, credentials, lp): + """Setup the idmap database. + + :param path: path to the idmap database + :param setup_path: Function that returns a path to a setup file + :param session_info: Session information + :param credentials: Credentials + :param lp: Loadparm context + """ + if os.path.exists(path): + os.unlink(path) + + idmap_ldb = Ldb(path, session_info=session_info, credentials=credentials, + lp=lp) + + idmap_ldb.erase() + idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) + return idmap_ldb def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, dnsdomain, realm, rootdn, configdn, netbiosname, @@ -844,6 +864,10 @@ def provision(lp, setup_dir, message, paths, session_info, setup_templatesdb(paths.templates, setup_path, session_info=session_info, credentials=credentials, lp=lp) + message("Setting up idmap db") + setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, + credentials=credentials, lp=lp) + samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials, lp=lp, schemadn=schemadn, configdn=configdn, domaindn=domaindn, -- cgit From 9b7baec42bc00985697be895e5d21aae50322f4d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 28 Feb 2008 08:39:45 +1100 Subject: Reorder modules to have rdn_name before objectclass. This ensures the relative DN is placed in the correct case into the DB. Andrew Bartlett (This used to be commit 16378219fbf9e8a26621f848e85426180822ea29) --- source4/scripting/python/samba/provision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index e3c47ff4a2..55935b0037 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -313,9 +313,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "server_sort", "extended_dn", "asq", - "samldb", "rdn_name", "objectclass", + "samldb", "kludge_acl", "operational"] tdb_modules_list = [ -- cgit From c20cf59768d585baf4524c54dadba1ec60673894 Mon Sep 17 00:00:00 2001 From: Douglas VanLeuven Date: Mon, 3 Mar 2008 11:08:59 +1100 Subject: Fix member server provision Can't add "member server" because the script aborts with null reference when no match on serverrole. This is fixed by checking for the keyword "member server". (This used to be commit 62536750ae06248a49c6b56c86d01b0062bb54f0) --- source4/scripting/python/samba/provision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 55935b0037..e9aded205a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -830,7 +830,7 @@ def provision(lp, setup_dir, message, paths, session_info, message("Setting up smb.conf") if serverrole == "domain controller": smbconfsuffix = "dc" - elif serverrole == "member": + elif serverrole == "member server": smbconfsuffix = "member" setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { -- cgit From 4d4a898742a0439d3f60c84194b02901412f4679 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 3 Mar 2008 13:03:19 +1100 Subject: Fix failure to re-provision. Somewhere in the conversion from ejs we lost calling the 'delete partitions' code. However, we have to be careful not to wipe partitions when we are the second client connecting to an LDAP server. Andrew Bartlett (This used to be commit 272eb765b81e3eab216a07249334f9b7d20e530b) --- source4/scripting/python/samba/__init__.py | 11 +++++++++-- source4/scripting/python/samba/provision.py | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index b041165800..8d5f4250c9 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -127,7 +127,7 @@ class Ldb(ldb.Ldb): try: self.delete(msg.dn) except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): - # Ignor eno such object errors + # Ignore no such object errors pass res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", ["distinguishedName"]) @@ -151,7 +151,14 @@ class Ldb(ldb.Ldb): previous_remaining = current_remaining current_remaining = len(res2) for msg in res2: - self.delete(msg.dn) + try: + self.delete(msg.dn) + # Ignore no such object errors + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + pass + # Ignore not allowed on non leaf errors + except ldb.LdbError, (LDB_ERR_NOT_ALLOWED_ON_NON_LEAF, _): + pass def load_ldif_file_add(self, ldif_path): """Load a LDIF file. diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index e9aded205a..ea2feb981b 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -279,8 +279,6 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, Alternatively, provision() may call this, and then populate the database. - :param erase: Remove the existing data present in the database. - :note: This will wipe the Sam Database! :note: This function always removes the local SAM LDB file. The erase @@ -289,10 +287,15 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, """ assert session_info is not None - if os.path.exists(samdb_path): + samdb = SamDB(samdb_path, session_info=session_info, + credentials=credentials, lp=lp) + + # Wipes the database + try: + samdb.erase() + except: os.unlink(samdb_path) - # Also wipes the database samdb = SamDB(samdb_path, session_info=session_info, credentials=credentials, lp=lp) @@ -547,7 +550,7 @@ def setup_self_join(samdb, configdn, schemadn, domaindn, def setup_samdb(path, setup_path, session_info, credentials, lp, schemadn, configdn, domaindn, dnsdomain, realm, - netbiosname, message, hostname, rootdn, erase, + netbiosname, message, hostname, rootdn, domainsid, aci, domainguid, policyguid, domainname, fill, adminpass, krbtgtpass, machinepass, hostguid, invocationid, dnspass, @@ -560,6 +563,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, assert serverrole in ("domain controller", "member server") + erase = (fill != FILL_DRS) + # Also wipes the database setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, domaindn=domaindn, message=message, lp=lp, @@ -726,7 +731,7 @@ def provision(lp, setup_dir, message, paths, session_info, hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, erase=False, + wheel=None, backup=None, aci=None, serverrole=None, ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): """Provision samba4 @@ -873,7 +878,7 @@ def provision(lp, setup_dir, message, paths, session_info, configdn=configdn, domaindn=domaindn, dnsdomain=dnsdomain, netbiosname=netbiosname, realm=realm, message=message, hostname=hostname, - rootdn=rootdn, erase=erase, domainsid=domainsid, + rootdn=rootdn, domainsid=domainsid, aci=aci, domainguid=domainguid, policyguid=policyguid, domainname=domain, fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass, -- cgit From 7e0ef3fd0ef4dba827f331cbe43fa0524be91130 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 6 Mar 2008 21:55:26 +1100 Subject: Make Samba4 pass the NET-API-BECOMEDC test against Win2k3 (again). To make Samba4, using the python provision system, pass this test required some major rework. Untested code is broken code, and some of the refactoring for a seperate provision test (which also now passes) broke things. Similarly, the iconv work has compiled, but these codepaths have never been run (NULL pointer de-reference). In working to use a local, rather than global, loadparm context, and to support using a target directory, a few things needed to be reworked, particularly around path handling. Andrew Bartlett (This used to be commit 1169e8d7bee20477b0efbfea3534ac63c83fb3d6) --- source4/scripting/python/samba/provision.py | 214 ++++++++++++++++++---------- 1 file changed, 138 insertions(+), 76 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ea2feb981b..ab8c51595f 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -32,6 +32,7 @@ from socket import gethostname, gethostbyname import param import registry import samba +from auth import system_session from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted from samba.samdb import SamDB import security @@ -65,6 +66,7 @@ class ProvisionPaths: self.dns_keytab = None self.dns = None self.winsdb = None + self.private_dir = None def check_install(lp, session_info, credentials): @@ -197,20 +199,20 @@ def provision_paths_from_lp(lp, dnsdomain): :param dnsdomain: DNS Domain name """ paths = ProvisionPaths() - private_dir = lp.get("private dir") + paths.private_dir = lp.get("private dir") paths.keytab = "secrets.keytab" paths.dns_keytab = "dns.keytab" - paths.shareconf = os.path.join(private_dir, "share.ldb") - paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") - paths.idmapdb = os.path.join(private_dir, lp.get("idmap database") or "idmap.ldb") - paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") - paths.templates = os.path.join(private_dir, "templates.ldb") - paths.dns = os.path.join(private_dir, dnsdomain + ".zone") - paths.winsdb = os.path.join(private_dir, "wins.ldb") - paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") - paths.smbconf = os.path.join(private_dir, "smb.conf") - paths.phpldapadminconfig = os.path.join(private_dir, + paths.shareconf = os.path.join(paths.private_dir, "share.ldb") + paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb") + paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb") + paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb") + paths.templates = os.path.join(paths.private_dir, "templates.ldb") + paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") + paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") + paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") + paths.smbconf = os.path.join(paths.private_dir, "smb.conf") + paths.phpldapadminconfig = os.path.join(paths.private_dir, "phpldapadmin-config.php") paths.hklm = "hklm.ldb" paths.hkcr = "hkcr.ldb" @@ -588,7 +590,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(domainsid) - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": samdb.set_invocation_id(invocationid) load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename) @@ -699,7 +701,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "KRBTGTPASS_B64": b64encode(krbtgtpass), }) - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": message("Setting up self join") setup_self_join(samdb, configdn=configdn, schemadn=schemadn, domaindn=domaindn, invocationid=invocationid, @@ -725,13 +727,14 @@ FILL_FULL = "FULL" FILL_NT4SYNC = "NT4SYNC" FILL_DRS = "DRS" -def provision(lp, setup_dir, message, paths, session_info, - credentials, samdb_fill=FILL_FULL, realm=None, rootdn=None, +def provision(setup_dir, message, session_info, + credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, hostip=None, domainsid=None, hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, + wheel=None, backup=None, aci=None, serverrole=None, ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): """Provision samba4 @@ -768,6 +771,65 @@ def provision(lp, setup_dir, message, paths, session_info, backup = findnss(grp.getgrnam, ["backup", "wheel", "root", "staff"])[0] if aci is None: aci = "# no aci for local ldb" + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + if hostip is None: + hostip = gethostbyname(hostname) + + netbiosname = hostname.upper() + if not valid_netbios_name(netbiosname): + raise InvalidNetbiosName(netbiosname) + + if targetdir is not None: + if not os.path.exists(targetdir): + os.mkdir(targetdir) + if not os.path.exists(os.path.join(targetdir, "etc")): + os.mkdir(os.path.join(targetdir, "etc")) + + if smbconf is None: + smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): + message("Setting up smb.conf") + assert serverrole is not None + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member server": + smbconfsuffix = "member" + + assert domain is not None + assert realm is not None + + default_lp = param.LoadParm() + #Load non-existant file + default_lp.load(smbconf) + + if targetdir is not None: + privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) + lockdir_line = "lock dir = " + os.path.abspath(targetdir) + + default_lp.set("lock dir", os.path.abspath(targetdir)) + + sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") + netlogon = os.path.join(os.path.join(sysvol, "scripts")) + + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), + smbconf, { + "HOSTNAME": hostname, + "DOMAIN_CONF": domain, + "REALM_CONF": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": netlogon, + "SYSVOLPATH": sysvol, + "PRIVATEDIR_LINE": privatedir_line, + "LOCKDIR_LINE": lockdir_line + }) + + lp = param.LoadParm() + lp.load(smbconf) + if serverrole is None: serverrole = lp.get("server role") assert serverrole in ("domain controller", "member server") @@ -777,32 +839,26 @@ def provision(lp, setup_dir, message, paths, session_info, if realm is None: realm = lp.get("realm") - if lp.get("realm").upper() != realm.upper(): - raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % - (lp.get("realm"), realm)) - - ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") - - if ldap_backend == "ldapi": - # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), safe="") - assert realm is not None realm = realm.upper() - if hostname is None: - hostname = gethostname().split(".")[0].lower() + dnsdomain = realm.lower() - if hostip is None: - hostip = gethostbyname(hostname) + paths = provision_paths_from_lp(lp, dnsdomain) - netbiosname = hostname.upper() - if not valid_netbios_name(netbiosname): - raise InvalidNetbiosName(netbiosname) + if targetdir is not None: + if not os.path.exists(paths.private_dir): + os.mkdir(paths.private_dir) + + ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") + + if ldap_backend == "ldapi": + # provision-backend will set this path suggested slapd command line / fedorads.inf + ldap_backend = "ldapi://" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - dnsdomain = realm.lower() if serverrole == "domain controller": - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + if domaindn is None: + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") if domain is None: domain = lp.get("workgroup") @@ -815,38 +871,25 @@ def provision(lp, setup_dir, message, paths, session_info, if not valid_netbios_name(domain): raise InvalidNetbiosName(domain) else: - domaindn = "CN=" + netbiosname + if domaindn is None: + domaindn = "CN=" + netbiosname domain = netbiosname if rootdn is None: rootdn = domaindn - configdn = "CN=Configuration," + rootdn - schemadn = "CN=Schema," + configdn + if configdn is None: + configdn = "CN=Configuration," + rootdn + if schemadn is None: + schemadn = "CN=Schema," + configdn message("set DOMAIN SID: %s" % str(domainsid)) message("Provisioning for %s in realm %s" % (domain, realm)) message("Using administrator password: %s" % adminpass) - assert paths.smbconf is not None - - # only install a new smb.conf if there isn't one there already - if not os.path.exists(paths.smbconf): - message("Setting up smb.conf") - if serverrole == "domain controller": - smbconfsuffix = "dc" - elif serverrole == "member server": - smbconfsuffix = "member" - setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), - paths.smbconf, { - "HOSTNAME": hostname, - "DOMAIN_CONF": domain, - "REALM_CONF": realm, - "SERVERROLE": serverrole, - "NETLOGONPATH": paths.netlogon, - "SYSVOLPATH": paths.sysvol, - }) - lp.load(paths.smbconf) + if lp.get("realm").upper() != realm.upper(): + raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % + (lp.get("realm"), realm)) # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): @@ -911,32 +954,52 @@ def provision(lp, setup_dir, message, paths, session_info, message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) + # Only make a zone file on the first DC, it should be replicated with DNS replication + if serverrole == "domain controller": + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + + domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") + assert isinstance(domainguid, str) + hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", + expression="(&(objectClass=computer)(cn=%s))" % hostname, + scope=SCOPE_SUBTREE) + assert isinstance(hostguid, str) + + message("Setting up DNS zone: %s" % dnsdomain) + create_zone_file(paths.dns, setup_path, samdb, + hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, + domaindn=domaindn, dnspass=dnspass, realm=realm, + domainguid=domainguid, hostguid=hostguid) + message("Please install the zone located in %s into your DNS server" % paths.dns) + message("Setting up phpLDAPadmin configuration") create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) - if lp.get("server role") == "domain controller": - samdb = SamDB(paths.samdb, session_info=session_info, - credentials=credentials, lp=lp) - - domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") - assert isinstance(domainguid, str) - hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", - expression="(&(objectClass=computer)(cn=%s))" % hostname, - scope=SCOPE_SUBTREE) - assert isinstance(hostguid, str) - - message("Setting up DNS zone: %s" % dnsdomain) - create_zone_file(paths.dns, setup_path, samdb, - hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, - domaindn=domaindn, dnspass=dnspass, realm=realm, - domainguid=domainguid, hostguid=hostguid) - message("Please install the zone located in %s into your DNS server" % paths.dns) - return domaindn +def provision_become_dc(setup_dir=None, + smbconf=None, targetdir=None, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + domain=None, hostname=None, domainsid=None, + hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, + policyguid=None, invocationid=None, machinepass=None, + dnspass=None, root=None, nobody=None, nogroup=None, users=None, + wheel=None, backup=None, aci=None, serverrole=None, + ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): + + def message(text): + """print a message if quiet is not set.""" + print text + + provision(setup_dir, message, system_session(), None, + smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, + rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, + domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); + def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. @@ -978,7 +1041,6 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, "HOSTGUID": hostguid, }) - def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): """Load schema for the SamDB. -- cgit From 8b24d248b7c928fd3b20f95ede34302ca274c4ae Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Mar 2008 07:33:14 +1100 Subject: Start to rework provision for LDAP backends This is the start of the rework of the provision script to handle an LDAP backend correctly. For example, we must not set the 'tdb modules' against an LDAP backend such as OpenLDAP that handles subtree renames. Andrew Bartlett (This used to be commit e462a107d3bafcc546ca4d53dcc8eb32e4280745) --- source4/scripting/python/samba/__init__.py | 7 ++++++- source4/scripting/python/samba/provision.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 8d5f4250c9..e91b320c07 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -147,7 +147,12 @@ class Ldb(ldb.Ldb): k = 0 while ++k < 10 and (previous_remaining != current_remaining): # and the rest - res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) + try: + res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + return + previous_remaining = current_remaining current_remaining = len(res2) for msg in res2: diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ea2feb981b..b140071f41 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -341,12 +341,21 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, if ldap_backend_type == "fedora-ds": backend_modules = ["nsuniqueid", "paged_searches"] + # We can handle linked attributes here, as we don't have directory-side subtree operations + tdb_modules_list = ["linked_attributes"] elif ldap_backend_type == "openldap": backend_modules = ["normalise", "entryuuid", "paged_searches"] + # OpenLDAP handles subtree renames, so we don't want to do any of these things + tdb_modules_list = None elif serverrole == "domain controller": backend_modules = ["repl_meta_data"] else: backend_modules = ["objectguid"] + + if tdb_modules_list is None: + tdb_modules_list_as_string = "" + else: + tdb_modules_list_as_string = ","+",".join(tdb_modules_list) samdb.transaction_start() try: @@ -362,7 +371,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "CONFIGDN_MOD": "naming_fsmo,instancetype", "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype", "MODULES_LIST": ",".join(modules_list), - "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), + "TDB_MODULES_LIST": tdb_modules_list_as_string, "MODULES_LIST2": ",".join(modules_list2), "BACKEND_MOD": ",".join(backend_modules), }) -- cgit From 14c5f968e1f99ceabc5a42d9a38a00ea137b00ea Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Mar 2008 10:57:52 +1100 Subject: Rework provision scripts for more testing This fixes up some issues with testdir (was not honoured) and increases test coverage. We now check all the major provision modes. In doing so, to make it possible to call from the multiple layers of 'sh', I have allowed 'dc' to alias 'domain controller' and 'member' to alias 'member server'. Fighting shell quoting in the test system was just too hard... Also fix upgrade.py Andrew Bartlett (This used to be commit 0923de12282b0e063dd73bc3e056dd5c3663c190) --- source4/scripting/python/samba/provision.py | 29 ++++++++++++++++------------- source4/scripting/python/samba/upgrade.py | 5 +---- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 37c4c5b082..25c1a995ef 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -572,9 +572,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, :note: This will wipe the main SAM database file! """ - assert serverrole in ("domain controller", "member server") - - erase = (fill != FILL_DRS) + erase = (fill != FILL_DRS) # Also wipes the database setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, @@ -796,17 +794,22 @@ def provision(setup_dir, message, session_info, if not os.path.exists(os.path.join(targetdir, "etc")): os.mkdir(os.path.join(targetdir, "etc")) - if smbconf is None: - smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) + smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): message("Setting up smb.conf") - assert serverrole is not None + if serverrole is None: + serverrole = "standalone" + + assert serverrole in ("domain controller", "member server", "standalone") if serverrole == "domain controller": smbconfsuffix = "dc" elif serverrole == "member server": smbconfsuffix = "member" + elif serverrole == "standalone": + smbconfsuffix = "standalone" assert domain is not None assert realm is not None @@ -827,8 +830,8 @@ def provision(setup_dir, message, session_info, setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), smbconf, { "HOSTNAME": hostname, - "DOMAIN_CONF": domain, - "REALM_CONF": realm, + "DOMAIN": domain, + "REALM": realm, "SERVERROLE": serverrole, "NETLOGONPATH": netlogon, "SYSVOLPATH": sysvol, @@ -841,7 +844,7 @@ def provision(setup_dir, message, session_info, if serverrole is None: serverrole = lp.get("server role") - assert serverrole in ("domain controller", "member server") + assert serverrole in ("domain controller", "member server", "standalone") if invocationid is None and serverrole == "domain controller": invocationid = uuid.random() @@ -851,6 +854,10 @@ def provision(setup_dir, message, session_info, assert realm is not None realm = realm.upper() + if lp.get("realm").upper() != realm.upper(): + raise Exception("realm '%s' in %s must match chosen realm '%s'" % + (lp.get("realm"), smbconf, realm)) + dnsdomain = realm.lower() paths = provision_paths_from_lp(lp, dnsdomain) @@ -896,10 +903,6 @@ def provision(setup_dir, message, session_info, message("Provisioning for %s in realm %s" % (domain, realm)) message("Using administrator password: %s" % adminpass) - if lp.get("realm").upper() != realm.upper(): - raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % - (lp.get("realm"), realm)) - # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 01b62ff984..c5086846d8 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -218,11 +218,9 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: serverrole = "member server" - lp.set("server role", serverrole) domainname = oldconf.get("workgroup") if domainname: domainname = str(domainname) - lp.set("workgroup", domainname) realm = oldconf.get("realm") netbiosname = oldconf.get("netbios name") @@ -235,7 +233,6 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, if realm is None: realm = domainname.lower() message("No realm specified in smb.conf file, assuming '%s'\n" % realm) - lp.set("realm", realm) domainguid = secrets_db.get_domain_guid(domainname) domainsid = secrets_db.get_sid(domainname) @@ -247,7 +244,7 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: machinepass = None - domaindn = provision(lp=lp, setup_dir=setup_dir, message=message, + domaindn = provision(setup_dir=setup_dir, message=message, samdb_fill=FILL_DRS, paths=paths, session_info=session_info, credentials=credentials, realm=realm, domain=domainname, domainsid=domainsid, domainguid=domainguid, -- cgit From a7e1fa0bef17ecc46f642b23ef635acfb09fea04 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Mar 2008 19:20:39 +1100 Subject: Try to fix up part of the upgrade test. There are still problems with the upgrade test, but these are not related to the provision system. Andrew Bartlett (This used to be commit d331bc400fb138bc43be88d0ca8ab3bcd590d2cd) --- source4/scripting/python/samba/provision.py | 13 ++++++++++++- source4/scripting/python/samba/upgrade.py | 20 +++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 25c1a995ef..ebca1f8e40 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -68,6 +68,12 @@ class ProvisionPaths: self.winsdb = None self.private_dir = None +class ProvisionResult: + def __init__(self): + self.paths = None + self.domaindn = None + self.lp = None + self.samdb = None def check_install(lp, session_info, credentials): """Check whether the current install seems ok. @@ -991,7 +997,12 @@ def provision(setup_dir, message, session_info, message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) - return domaindn + result = ProvisionResult() + result.domaindn = domaindn + result.paths = paths + result.lp = lp + result.samdb = samdb + return result def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None, realm=None, diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index c5086846d8..f40f2cffe7 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -207,7 +207,7 @@ def import_wins(samba4_winsdb, samba3_winsdb): "objectClass": "winsMaxVersion", "maxVersion": str(version_id)}) -def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, paths): +def upgrade_provision(samba3, setup_dir, message, credentials, session_info, smbconf, targetdir): oldconf = samba3.get_conf() if oldconf.get("domain logons") == "True": @@ -244,15 +244,13 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: machinepass = None - domaindn = provision(setup_dir=setup_dir, message=message, - samdb_fill=FILL_DRS, paths=paths, session_info=session_info, - credentials=credentials, realm=realm, - domain=domainname, domainsid=domainsid, domainguid=domainguid, - machinepass=machinepass, serverrole=serverrole) + result = provision(setup_dir=setup_dir, message=message, + samdb_fill=FILL_DRS, smbconf=smbconf, session_info=session_info, + credentials=credentials, realm=realm, + domain=domainname, domainsid=domainsid, domainguid=domainguid, + machinepass=machinepass, serverrole=serverrole, targetdir=targetdir) - samdb = SamDB(paths.samdb, credentials=credentials, lp=lp, session_info=session_info) - - import_wins(Ldb(paths.winsdb), samba3.get_wins_db()) + import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db()) # FIXME: import_registry(registry.Registry(), samba3.get_registry()) @@ -268,12 +266,12 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, passdb = samba3.get_sam_db() for name in passdb: user = passdb[name] - #FIXME: import_sam_account(samdb, user, domaindn, domainsid) + #FIXME: import_sam_account(result.samdb, user, domaindn, domainsid) if hasattr(passdb, 'ldap_url'): message("Enabling Samba3 LDAP mappings for SAM database") - enable_samba3sam(samdb, passdb.ldap_url) + enable_samba3sam(result.samdb, passdb.ldap_url) def enable_samba3sam(samdb, ldapurl): -- cgit From 9703948850fb6febb237d701ce6b6300e9df8e1f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 11 Mar 2008 14:41:10 +1100 Subject: Fix provision script to work without smb.conf location specified. Andrew Bartlett (This used to be commit b4da374a998caac18c288a0a6e3fcd2c50cbffa7) --- source4/scripting/python/samba/provision.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ebca1f8e40..24870c2fbd 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -51,7 +51,6 @@ class InvalidNetbiosName(Exception): class ProvisionPaths: def __init__(self): - self.smbconf = None self.shareconf = None self.hklm = None self.hkcu = None @@ -217,7 +216,6 @@ def provision_paths_from_lp(lp, dnsdomain): paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") - paths.smbconf = os.path.join(paths.private_dir, "smb.conf") paths.phpldapadminconfig = os.path.join(paths.private_dir, "phpldapadmin-config.php") paths.hklm = "hklm.ldb" @@ -759,6 +757,9 @@ def provision(setup_dir, message, session_info, if domainsid is None: domainsid = security.random_sid() + else: + domainsid = security.Sid(domainsid) + if policyguid is None: policyguid = uuid.random() if adminpass is None: -- cgit From 69d66e6fb09b2449dec9bf0af49408b9a6c3cc65 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 13 Mar 2008 08:08:05 +1100 Subject: Upgrade provision-backend to python. This required a large rework of the provision code, so as to move much of the 'guess' logic into subprocedures, rather than just inline in the provision code. Andrew Bartlett (This used to be commit a0754c2a857217ca831c2295b17255d8f38dfbc2) --- source4/scripting/python/samba/provision.py | 621 ++++++++++++++++++---------- 1 file changed, 411 insertions(+), 210 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 24870c2fbd..2ede4b8d3d 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -66,7 +66,27 @@ class ProvisionPaths: self.dns = None self.winsdb = None self.private_dir = None - + self.ldapdir = None + self.slapdconf = None + self.modulesconf = None + self.memberofconf = None + self.fedoradsinf = None + self.fedoradspartitions = None + +class ProvisionNames: + def __init__(self): + self.rootdn = None + self.domaindn = None + self.configdn = None + self.schemadn = None + self.ldapmanagerdn = None + self.dnsdomain = None + self.realm = None + self.netbiosname = None + self.domain = None + self.hostname = None + self.sitename = None + class ProvisionResult: def __init__(self): self.paths = None @@ -218,6 +238,18 @@ def provision_paths_from_lp(lp, dnsdomain): paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") paths.phpldapadminconfig = os.path.join(paths.private_dir, "phpldapadmin-config.php") + paths.ldapdir = os.path.join(paths.private_dir, + "ldap") + paths.slapdconf = os.path.join(paths.ldapdir, + "slapd.conf") + paths.modulesconf = os.path.join(paths.ldapdir, + "modules.conf") + paths.memberofconf = os.path.join(paths.ldapdir, + "memberof.conf") + paths.fedoradsinf = os.path.join(paths.ldapdir, + "fedorads.inf") + paths.fedoradspartitions = os.path.join(paths.ldapdir, + "fedorads-partitions.ldif") paths.hklm = "hklm.ldb" paths.hkcr = "hkcr.ldb" paths.hkcu = "hkcu.ldb" @@ -225,16 +257,142 @@ def provision_paths_from_lp(lp, dnsdomain): paths.hkpd = "hkpd.ldb" paths.hkpt = "hkpt.ldb" - paths.sysvol = lp.get("sysvol", "path") - if paths.sysvol is None: - paths.sysvol = os.path.join(lp.get("lock dir"), "sysvol") + paths.sysvol = lp.get("path", "sysvol") - paths.netlogon = lp.get("netlogon", "path") - if paths.netlogon is None: - paths.netlogon = os.path.join(os.path.join(paths.sysvol, "scripts")) + paths.netlogon = lp.get("path", "netlogon") return paths +def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None, + rootdn=None, domaindn=None, configdn=None, schemadn=None, sitename=None): + + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + netbiosname = hostname.upper() + if not valid_netbios_name(netbiosname): + raise InvalidNetbiosName(netbiosname) + + hostname = hostname.lower() + + if dnsdomain is None: + dnsdomain = lp.get("realm") + + if serverrole is None: + serverrole = lp.get("server role") + + assert dnsdomain is not None + realm = dnsdomain.upper() + + if lp.get("realm").upper() != realm: + raise Exception("realm '%s' in %s must match chosen realm '%s'" % + (lp.get("realm"), smbconf, realm)) + + dnsdomain = dnsdomain.lower() + + if (serverrole == "domain controller"): + if domain is None: + domain = lp.get("workgroup") + if domaindn is None: + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + if lp.get("workgroup").upper() != domain.upper(): + raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'", + lp.get("workgroup"), domain) + else: + domain = netbiosname + if domaindn is None: + domaindn = "CN=" + netbiosname + + assert domain is not None + domain = domain.upper() + if not valid_netbios_name(domain): + raise InvalidNetbiosName(domain) + + if rootdn is None: + rootdn = domaindn + + if configdn is None: + configdn = "CN=Configuration," + rootdn + if schemadn is None: + schemadn = "CN=Schema," + configdn + + if sitename is None: + sitename=DEFAULTSITE + + names = ProvisionNames() + names.rootdn = rootdn + names.domaindn = domaindn + names.configdn = configdn + names.schemadn = schemadn + names.ldapmanagerdn = "CN=Manager," + rootdn + names.dnsdomain = dnsdomain + names.domain = domain + names.realm = realm + names.netbiosname = netbiosname + names.hostname = hostname + names.sitename = sitename + + return names + + +def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, targetdir): + if targetdir is not None: + if not os.path.exists(targetdir): + os.mkdir(targetdir) + if not os.path.exists(os.path.join(targetdir, "etc")): + os.mkdir(os.path.join(targetdir, "etc")) + + smbconf = os.path.join(targetdir, "etc", "smb.conf") + + # only install a new smb.conf if there isn't one there already + + if not os.path.exists(smbconf): + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + if serverrole is None: + serverrole = "standalone" + + assert serverrole in ("domain controller", "member server", "standalone") + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member server": + smbconfsuffix = "member" + elif serverrole == "standalone": + smbconfsuffix = "standalone" + + assert domain is not None + assert realm is not None + + default_lp = param.LoadParm() + #Load non-existant file + default_lp.load(smbconf) + + if targetdir is not None: + privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) + lockdir_line = "lock dir = " + os.path.abspath(targetdir) + + default_lp.set("lock dir", os.path.abspath(targetdir)) + + sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") + netlogon = os.path.join(sysvol, realm.lower(), "scripts") + + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), + smbconf, { + "HOSTNAME": hostname, + "DOMAIN": domain, + "REALM": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": netlogon, + "SYSVOLPATH": sysvol, + "PRIVATEDIR_LINE": privatedir_line, + "LOCKDIR_LINE": lockdir_line + }) + + lp = param.LoadParm() + lp.load(smbconf) + + return lp def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, wheel, backup): @@ -277,9 +435,8 @@ def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, - credentials, configdn, schemadn, domaindn, - hostname, netbiosname, dnsdomain, realm, - rootdn, serverrole, sitename, ldap_backend=None, + credentials, names, + serverrole, ldap_backend=None, ldap_backend_type=None, erase=False): """Setup the partitions for the SAM database. @@ -366,12 +523,12 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, samdb.transaction_start() try: setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { - "SCHEMADN": schemadn, + "SCHEMADN": names.schemadn, "SCHEMADN_LDB": schemadn_ldb, "SCHEMADN_MOD2": ",objectguid", - "CONFIGDN": configdn, + "CONFIGDN": names.configdn, "CONFIGDN_LDB": configdn_ldb, - "DOMAINDN": domaindn, + "DOMAINDN": names.domaindn, "DOMAINDN_LDB": domaindn_ldb, "SCHEMADN_MOD": "schema_fsmo,instancetype", "CONFIGDN_MOD": "naming_fsmo,instancetype", @@ -397,9 +554,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, samdb.load_ldif_file_add(setup_path("provision_init.ldif")) message("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, - dnsdomain, realm, rootdn, configdn, netbiosname, - sitename) + setup_samdb_rootdse(samdb, setup_path, names.schemadn, names.domaindn, names.hostname, + names.dnsdomain, names.realm, names.rootdn, names.configdn, names.netbiosname, + names.sitename) if erase: message("Erasing data from partitions") @@ -532,10 +689,10 @@ def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, }) -def setup_self_join(samdb, configdn, schemadn, domaindn, - netbiosname, hostname, dnsdomain, machinepass, dnspass, - realm, domainname, domainsid, invocationid, setup_path, - policyguid, sitename, hostguid=None): +def setup_self_join(samdb, names, + machinepass, dnspass, + domainsid, invocationid, setup_path, + policyguid, hostguid=None): """Join a host to its own domain.""" if hostguid is not None: hostguid_add = "objectGUID: %s" % hostguid @@ -543,33 +700,32 @@ def setup_self_join(samdb, configdn, schemadn, domaindn, hostguid_add = "" setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { - "CONFIGDN": configdn, - "SCHEMADN": schemadn, - "DOMAINDN": domaindn, + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + "DOMAINDN": names.domaindn, "INVOCATIONID": invocationid, - "NETBIOSNAME": netbiosname, - "DEFAULTSITE": sitename, - "DNSNAME": "%s.%s" % (hostname, dnsdomain), + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain), "MACHINEPASS_B64": b64encode(machinepass), "DNSPASS_B64": b64encode(dnspass), - "REALM": realm, - "DOMAIN": domainname, + "REALM": names.realm, + "DOMAIN": names.domain, "HOSTGUID_ADD": hostguid_add, - "DNSDOMAIN": dnsdomain}) + "DNSDOMAIN": names.dnsdomain}) setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { "POLICYGUID": policyguid, - "DNSDOMAIN": dnsdomain, + "DNSDOMAIN": names.dnsdomain, "DOMAINSID": str(domainsid), - "DOMAINDN": domaindn}) + "DOMAINDN": names.domaindn}) def setup_samdb(path, setup_path, session_info, credentials, lp, - schemadn, configdn, domaindn, dnsdomain, realm, - netbiosname, message, hostname, rootdn, + names, message, domainsid, aci, domainguid, policyguid, - domainname, fill, adminpass, krbtgtpass, + fill, adminpass, krbtgtpass, machinepass, hostguid, invocationid, dnspass, - serverrole, sitename, ldap_backend=None, + serverrole, ldap_backend=None, ldap_backend_type=None): """Setup a complete SAM Database. @@ -579,14 +735,11 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, erase = (fill != FILL_DRS) # Also wipes the database - setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, - domaindn=domaindn, message=message, lp=lp, + setup_samdb_partitions(path, setup_path, message=message, lp=lp, credentials=credentials, session_info=session_info, - hostname=hostname, netbiosname=netbiosname, - dnsdomain=dnsdomain, realm=realm, rootdn=rootdn, + names=names, ldap_backend=ldap_backend, serverrole=serverrole, - ldap_backend_type=ldap_backend_type, erase=erase, - sitename=sitename) + ldap_backend_type=ldap_backend_type, erase=erase) samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) @@ -604,18 +757,18 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, if serverrole == "domain controller": samdb.set_invocation_id(invocationid) - load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename) + load_schema(setup_path, samdb, names.schemadn, names.netbiosname, names.configdn, names.sitename) samdb.transaction_start() try: - message("Adding DomainDN: %s (permitted to fail)" % domaindn) + message("Adding DomainDN: %s (permitted to fail)" % names.domaindn) setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { - "DOMAINDN": domaindn, + "DOMAINDN": names.domaindn, "ACI": aci, }) - message("Modifying DomainDN: " + domaindn + "") + message("Modifying DomainDN: " + names.domaindn + "") if domainguid is not None: domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid else: @@ -624,104 +777,102 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), { "LDAPTIME": timestring(int(time.time())), "DOMAINSID": str(domainsid), - "SCHEMADN": schemadn, - "NETBIOSNAME": netbiosname, - "DEFAULTSITE": sitename, - "CONFIGDN": configdn, + "SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "CONFIGDN": names.configdn, "POLICYGUID": policyguid, - "DOMAINDN": domaindn, + "DOMAINDN": names.domaindn, "DOMAINGUID_MOD": domainguid_mod, }) message("Adding configuration container (permitted to fail)") setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), { - "CONFIGDN": configdn, + "CONFIGDN": names.configdn, "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", }) message("Modifying configuration container") setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), { - "CONFIGDN": configdn, - "SCHEMADN": schemadn, + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, }) message("Adding schema container (permitted to fail)") setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), { - "SCHEMADN": schemadn, + "SCHEMADN": names.schemadn, "ACI": aci, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") setup_modify_ldif(samdb, setup_path("provision_schema_basedn_modify.ldif"), { - "SCHEMADN": schemadn, - "NETBIOSNAME": netbiosname, - "DEFAULTSITE": sitename, - "CONFIGDN": configdn, + "SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "CONFIGDN": names.configdn, }) message("Setting up sam.ldb Samba4 schema") setup_add_ldif(samdb, setup_path("schema_samba4.ldif"), - {"SCHEMADN": schemadn }) + {"SCHEMADN": names.schemadn }) message("Setting up sam.ldb AD schema") setup_add_ldif(samdb, setup_path("schema.ldif"), - {"SCHEMADN": schemadn}) + {"SCHEMADN": names.schemadn}) message("Setting up sam.ldb configuration data") setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), { - "CONFIGDN": configdn, - "NETBIOSNAME": netbiosname, - "DEFAULTSITE": sitename, - "DNSDOMAIN": dnsdomain, - "DOMAIN": domainname, - "SCHEMADN": schemadn, - "DOMAINDN": domaindn, + "CONFIGDN": names.configdn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "DNSDOMAIN": names.dnsdomain, + "DOMAIN": names.domain, + "SCHEMADN": names.schemadn, + "DOMAINDN": names.domaindn, }) message("Setting up display specifiers") setup_add_ldif(samdb, setup_path("display_specifiers.ldif"), - {"CONFIGDN": configdn}) + {"CONFIGDN": names.configdn}) message("Adding users container (permitted to fail)") setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), { - "DOMAINDN": domaindn}) + "DOMAINDN": names.domaindn}) message("Modifying users container") setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), { - "DOMAINDN": domaindn}) + "DOMAINDN": names.domaindn}) message("Adding computers container (permitted to fail)") setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), { - "DOMAINDN": domaindn}) + "DOMAINDN": names.domaindn}) message("Modifying computers container") setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), { - "DOMAINDN": domaindn}) + "DOMAINDN": names.domaindn}) message("Setting up sam.ldb data") setup_add_ldif(samdb, setup_path("provision.ldif"), { - "DOMAINDN": domaindn, - "NETBIOSNAME": netbiosname, - "DEFAULTSITE": sitename, - "CONFIGDN": configdn, + "DOMAINDN": names.domaindn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": names.sitename, + "CONFIGDN": names.configdn, }) if fill == FILL_FULL: message("Setting up sam.ldb users and groups") setup_add_ldif(samdb, setup_path("provision_users.ldif"), { - "DOMAINDN": domaindn, + "DOMAINDN": names.domaindn, "DOMAINSID": str(domainsid), - "CONFIGDN": configdn, + "CONFIGDN": names.configdn, "ADMINPASS_B64": b64encode(adminpass), "KRBTGTPASS_B64": b64encode(krbtgtpass), }) if serverrole == "domain controller": message("Setting up self join") - setup_self_join(samdb, configdn=configdn, schemadn=schemadn, - domaindn=domaindn, invocationid=invocationid, - dnspass=dnspass, netbiosname=netbiosname, - dnsdomain=dnsdomain, realm=realm, - machinepass=machinepass, domainname=domainname, + setup_self_join(samdb, names=names, invocationid=invocationid, + dnspass=dnspass, + machinepass=machinepass, domainsid=domainsid, policyguid=policyguid, - hostname=hostname, hostguid=hostguid, - setup_path=setup_path, sitename=sitename) + hostguid=hostguid, + setup_path=setup_path) #We want to setup the index last, as adds are faster unindexed message("Setting up sam.ldb index") @@ -746,7 +897,7 @@ def provision(setup_dir, message, session_info, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, wheel=None, backup=None, aci=None, serverrole=None, - ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): + ldap_backend=None, ldap_backend_type=None, sitename=None): """Provision samba4 :note: caution, this wipes all existing data! @@ -785,129 +936,37 @@ def provision(setup_dir, message, session_info, backup = findnss(grp.getgrnam, ["backup", "wheel", "root", "staff"])[0] if aci is None: aci = "# no aci for local ldb" - if hostname is None: - hostname = gethostname().split(".")[0].lower() - if hostip is None: - hostip = gethostbyname(hostname) + lp = load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, targetdir) - netbiosname = hostname.upper() - if not valid_netbios_name(netbiosname): - raise InvalidNetbiosName(netbiosname) + names = guess_names(lp=lp, hostname=hostname, domain=domain, + dnsdomain=realm, serverrole=serverrole, sitename=sitename, + rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn) - if targetdir is not None: - if not os.path.exists(targetdir): - os.mkdir(targetdir) - if not os.path.exists(os.path.join(targetdir, "etc")): - os.mkdir(os.path.join(targetdir, "etc")) - - smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) - - # only install a new smb.conf if there isn't one there already - - if not os.path.exists(smbconf): - message("Setting up smb.conf") - if serverrole is None: - serverrole = "standalone" - - assert serverrole in ("domain controller", "member server", "standalone") - if serverrole == "domain controller": - smbconfsuffix = "dc" - elif serverrole == "member server": - smbconfsuffix = "member" - elif serverrole == "standalone": - smbconfsuffix = "standalone" - - assert domain is not None - assert realm is not None - - default_lp = param.LoadParm() - #Load non-existant file - default_lp.load(smbconf) - - if targetdir is not None: - privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) - lockdir_line = "lock dir = " + os.path.abspath(targetdir) - - default_lp.set("lock dir", os.path.abspath(targetdir)) - - sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") - netlogon = os.path.join(os.path.join(sysvol, "scripts")) - - setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), - smbconf, { - "HOSTNAME": hostname, - "DOMAIN": domain, - "REALM": realm, - "SERVERROLE": serverrole, - "NETLOGONPATH": netlogon, - "SYSVOLPATH": sysvol, - "PRIVATEDIR_LINE": privatedir_line, - "LOCKDIR_LINE": lockdir_line - }) + paths = provision_paths_from_lp(lp, names.dnsdomain) - lp = param.LoadParm() - lp.load(smbconf) + if hostip is None: + hostip = gethostbyname(names.hostname) if serverrole is None: serverrole = lp.get("server role") + assert serverrole in ("domain controller", "member server", "standalone") if invocationid is None and serverrole == "domain controller": invocationid = uuid.random() - if realm is None: - realm = lp.get("realm") - - assert realm is not None - realm = realm.upper() - - if lp.get("realm").upper() != realm.upper(): - raise Exception("realm '%s' in %s must match chosen realm '%s'" % - (lp.get("realm"), smbconf, realm)) - - dnsdomain = realm.lower() - - paths = provision_paths_from_lp(lp, dnsdomain) - - if targetdir is not None: - if not os.path.exists(paths.private_dir): - os.mkdir(paths.private_dir) + if not os.path.exists(paths.private_dir): + os.mkdir(paths.private_dir) ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") - if ldap_backend == "ldapi": - # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - - if serverrole == "domain controller": - if domaindn is None: - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") - if domain is None: - domain = lp.get("workgroup") - - if lp.get("workgroup").upper() != domain.upper(): - raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'", - lp.get("workgroup"), domain) - - assert domain is not None - domain = domain.upper() - if not valid_netbios_name(domain): - raise InvalidNetbiosName(domain) - else: - if domaindn is None: - domaindn = "CN=" + netbiosname - domain = netbiosname - - if rootdn is None: - rootdn = domaindn - - if configdn is None: - configdn = "CN=Configuration," + rootdn - if schemadn is None: - schemadn = "CN=Schema," + configdn - + if ldap_backend is not None: + if ldap_backend == "ldapi": + # provision-backend will set this path suggested slapd command line / fedorads.inf + ldap_backend = "ldapi://" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + message("set DOMAIN SID: %s" % str(domainsid)) - message("Provisioning for %s in realm %s" % (domain, realm)) + message("Provisioning for %s in realm %s" % (names.domain, realm)) message("Using administrator password: %s" % adminpass) # only install a new shares config db if there is none @@ -936,21 +995,19 @@ def provision(setup_dir, message, session_info, credentials=credentials, lp=lp) samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, - credentials=credentials, lp=lp, schemadn=schemadn, - configdn=configdn, domaindn=domaindn, - dnsdomain=dnsdomain, netbiosname=netbiosname, - realm=realm, message=message, hostname=hostname, - rootdn=rootdn, domainsid=domainsid, + credentials=credentials, lp=lp, names=names, + message=message, + domainsid=domainsid, aci=aci, domainguid=domainguid, policyguid=policyguid, - domainname=domain, fill=samdb_fill, + fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass, hostguid=hostguid, invocationid=invocationid, machinepass=machinepass, dnspass=dnspass, serverrole=serverrole, ldap_backend=ldap_backend, - ldap_backend_type=ldap_backend_type, sitename=sitename) + ldap_backend_type=ldap_backend_type) if lp.get("server role") == "domain controller": - policy_path = os.path.join(paths.sysvol, dnsdomain, "Policies", + policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies", "{" + policyguid + "}") os.makedirs(policy_path, 0755) os.makedirs(os.path.join(policy_path, "Machine"), 0755) @@ -959,14 +1016,14 @@ def provision(setup_dir, message, session_info, os.makedirs(paths.netlogon, 0755) secrets_ldb = Ldb(paths.secrets, session_info=session_info, credentials=credentials, lp=lp) - secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=realm, - netbiosname=netbiosname, domainsid=domainsid, + secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm, + netbiosname=names.netbiosname, domainsid=domainsid, keytab_path=paths.keytab, samdb_url=paths.samdb, dns_keytab_path=paths.dns_keytab, dnspass=dnspass, - machinepass=machinepass, dnsdomain=dnsdomain) + machinepass=machinepass, dnsdomain=names.dnsdomain) if samdb_fill == FILL_FULL: - setup_name_mappings(samdb, str(domainsid), domaindn, root=root, + setup_name_mappings(samdb, str(domainsid), names.domaindn, root=root, nobody=nobody, nogroup=nogroup, wheel=wheel, users=users, backup=backup) @@ -981,14 +1038,14 @@ def provision(setup_dir, message, session_info, domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") assert isinstance(domainguid, str) hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", - expression="(&(objectClass=computer)(cn=%s))" % hostname, + expression="(&(objectClass=computer)(cn=%s))" % names.hostname, scope=SCOPE_SUBTREE) assert isinstance(hostguid, str) - message("Setting up DNS zone: %s" % dnsdomain) + message("Setting up DNS zone: %s" % names.dnsdomain) create_zone_file(paths.dns, setup_path, samdb, - hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, - domaindn=domaindn, dnspass=dnspass, realm=realm, + hostname=names.hostname, hostip=hostip, dnsdomain=names.dnsdomain, + domaindn=names.domaindn, dnspass=dnspass, realm=names.realm, domainguid=domainguid, hostguid=hostguid) message("Please install the zone located in %s into your DNS server" % paths.dns) @@ -1025,6 +1082,150 @@ def provision_become_dc(setup_dir=None, domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); +def setup_db_config(setup_path, file, dbdir): + if not os.path.isdir(os.path.join(dbdir, "bdb-logs")): + os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700); + if not os.path.isdir(os.path.join(dbdir, "tmp")): + os.makedirs(os.path.join(dbdir, "tmp"), 0700); + + setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"), + {"LDAPDBDIR": dbdir}) + + + +def provision_backend(setup_dir=None, message=None, + smbconf=None, targetdir=None, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + domain=None, hostname=None, adminpass=None, root=None, serverrole=None, + ldap_backend_type=None): + + def setup_path(file): + return os.path.join(setup_dir, file) + + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + if root is None: + root = findnss(pwd.getpwnam, ["root"])[0] + + lp = load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, targetdir) + + names = guess_names(lp=lp, hostname=hostname, domain=domain, + dnsdomain=realm, serverrole=serverrole, + rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn) + + paths = provision_paths_from_lp(lp, names.dnsdomain) + + if not os.path.isdir(paths.ldapdir): + os.makedirs(paths.ldapdir) + schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb") + try: + os.unlink(schemadb_path) + except: + pass + + schemadb = Ldb(schemadb_path, lp=lp) + + setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"), + {"SCHEMADN": names.schemadn, + "ACI": "#", + "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" + }) + setup_modify_ldif(schemadb, + setup_path("provision_schema_basedn_modify.ldif"), \ + {"SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": names.configdn, + }) + + setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"), + {"SCHEMADN": names.schemadn }) + setup_add_ldif(schemadb, setup_path("schema.ldif"), + {"SCHEMADN": names.schemadn}) + + if ldap_backend_type == "fedora-ds": + setup_file(setup_path("fedora-ds.inf"), paths.fedoradsinf, + {"ROOT": root, + "HOSTNAME": hostname, + "DNSDOMAIN": names.dnsdomain, + "LDAPDIR": paths.ldapdir, + "DOMAINDN": names.domaindn, + "LDAPMANAGERDN": names.ldapmanagerdn, + "LDAPMANAGERPASS": adminpass, + "SERVERPORT": ""}) + + setup_file(setup_path("fedora-partitions.ldif"), paths.fedoradspartitions, + {"CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + }) + + setup_file(setup_path("fedora-partitions.ldif"), paths.fedoradspartitions, + {"CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + }) + mapping = "schema-map-fedora-ds-1.0" + backend_schema = "99_ad.ldif" + elif ldap_backend_type == "openldap": + setup_file(setup_path("slapd.conf"), paths.slapdconf, + {"DNSDOMAIN": names.dnsdomain, + "LDAPDIR": paths.ldapdir, + "DOMAINDN": names.domaindn, + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + "LDAPMANAGERDN": names.ldapmanagerdn, + "LDAPMANAGERPASS": adminpass}) + setup_file(setup_path("modules.conf"), paths.modulesconf, + {"REALM": names.realm}) + + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "user")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "config")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "schema")) + mapping = "schema-map-openldap-2.3" + backend_schema = "backend-schema.schema" + + attrs = ["linkID", "lDAPDisplayName"] + res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs); + + memberof_config = "# This is a generated file, do not edit!\n"; + refint_attributes = ""; + for i in range (0, len(res)): + linkid = res[i]["linkID"][0] + linkid = str(int(linkid) + 1) + target = schemadb.searchone(basedn=names.schemadn, + expression="(&(objectclass=attributeSchema)(linkID=" + (linkid) + "))", + attribute="lDAPDisplayName"); + if target is not None: + refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"]; + memberof_config = memberof_config + """overlay memberof +memberof-dangling error +memberof-refint TRUE +memberof-group-oc top +memberof-member-ad """ + res[i]["lDAPDisplayName"] + """ +memberof-memberof-ad """ + target + """ +memberof-dangling-error 32 + +"""; + + memberof_config = memberof_config + """ +overlay refint +refint_attributes""" + refint_attributes + "\n"; + + if os.path.exists(paths.memberofconf): + os.unlink(paths.memberof.conf) + + open(paths.memberofconf, 'w').write(memberof_config) + + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + message("Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri) + + + schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema); + + os.system(schema_command) + + + def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. -- cgit From 07a7c8fa0d76cb7cb10cc88fb5bbe5439b746d01 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 13 Mar 2008 09:55:06 +1100 Subject: Update the provision scripts and selftest for LDAP This should allow us to provision onto an OpenLDAP backend again. Also ensure we always have a sysvol and netlogon share in the selftest environment. Andrew Bartlett (This used to be commit b2d9b03ba3434e76d4d476233a198728523d17f9) --- source4/scripting/python/samba/provision.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 2ede4b8d3d..f9604a84b2 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1192,16 +1192,18 @@ def provision_backend(setup_dir=None, message=None, for i in range (0, len(res)): linkid = res[i]["linkID"][0] linkid = str(int(linkid) + 1) + expression = "(&(objectclass=attributeSchema)(linkID=" + (linkid) + "))" target = schemadb.searchone(basedn=names.schemadn, - expression="(&(objectclass=attributeSchema)(linkID=" + (linkid) + "))", - attribute="lDAPDisplayName"); + expression=expression, + attribute="lDAPDisplayName", + scope=SCOPE_SUBTREE); if target is not None: - refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"]; + refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]; memberof_config = memberof_config + """overlay memberof memberof-dangling error memberof-refint TRUE memberof-group-oc top -memberof-member-ad """ + res[i]["lDAPDisplayName"] + """ +memberof-member-ad """ + res[i]["lDAPDisplayName"][0] + """ memberof-memberof-ad """ + target + """ memberof-dangling-error 32 @@ -1214,7 +1216,7 @@ refint_attributes""" + refint_attributes + "\n"; if os.path.exists(paths.memberofconf): os.unlink(paths.memberof.conf) - open(paths.memberofconf, 'w').write(memberof_config) + open(paths.memberofconf, 'w').write(memberof_config) ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") message("Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri) -- cgit From 0c882402360a10b19a038bce9f87e241051c9ba8 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 13 Mar 2008 11:36:58 +1100 Subject: Rework to have member server 'domains' be CN=NETBIOSNAME This reworks quite a few parts of our provision system to use CN=NETBIOSNAME as the domain for member servers. This makes it clear that these domains are not in the DNS structure, while complying with our own schema (found by OpenLDAP's schema validation). Andrew Bartlett (This used to be commit bda6a38b055fed2394e65cdc0b308a1442116402) --- source4/scripting/python/samba/provision.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f9604a84b2..25316e888a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -763,9 +763,15 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, try: message("Adding DomainDN: %s (permitted to fail)" % names.domaindn) + if serverrole == "domain controller": + domain_oc = "domainDNS" + else: + domain_oc = "samba4LocalDomain" + setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { "DOMAINDN": names.domaindn, "ACI": aci, + "DOMAIN_OC": domain_oc }) message("Modifying DomainDN: " + names.domaindn + "") -- cgit From d7299d82c31f08750d5d378b0e1f0226dbff5d05 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sat, 15 Mar 2008 19:03:04 +1100 Subject: Rework memberof handling in slapd.conf (used for OpenLDAP backend) Instead of using an include file, put the generated configurationd directly into slapd.conf. Andrew Bartlett (This used to be commit 95ac786136aebfe5ededeb3fb81cbd4e296e3988) --- source4/scripting/python/samba/provision.py | 41 +++++++++++++---------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 25316e888a..47d00f8871 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1173,27 +1173,10 @@ def provision_backend(setup_dir=None, message=None, mapping = "schema-map-fedora-ds-1.0" backend_schema = "99_ad.ldif" elif ldap_backend_type == "openldap": - setup_file(setup_path("slapd.conf"), paths.slapdconf, - {"DNSDOMAIN": names.dnsdomain, - "LDAPDIR": paths.ldapdir, - "DOMAINDN": names.domaindn, - "CONFIGDN": names.configdn, - "SCHEMADN": names.schemadn, - "LDAPMANAGERDN": names.ldapmanagerdn, - "LDAPMANAGERPASS": adminpass}) - setup_file(setup_path("modules.conf"), paths.modulesconf, - {"REALM": names.realm}) - - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "user")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "config")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "schema")) - mapping = "schema-map-openldap-2.3" - backend_schema = "backend-schema.schema" - attrs = ["linkID", "lDAPDisplayName"] res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs); - memberof_config = "# This is a generated file, do not edit!\n"; + memberof_config = "# Generated from schema in " + schemadb_path + "\n"; refint_attributes = ""; for i in range (0, len(res)): linkid = res[i]["linkID"][0] @@ -1219,10 +1202,24 @@ memberof-dangling-error 32 overlay refint refint_attributes""" + refint_attributes + "\n"; - if os.path.exists(paths.memberofconf): - os.unlink(paths.memberof.conf) - - open(paths.memberofconf, 'w').write(memberof_config) + setup_file(setup_path("slapd.conf"), paths.slapdconf, + {"DNSDOMAIN": names.dnsdomain, + "LDAPDIR": paths.ldapdir, + "DOMAINDN": names.domaindn, + "CONFIGDN": names.configdn, + "SCHEMADN": names.schemadn, + "LDAPMANAGERDN": names.ldapmanagerdn, + "LDAPMANAGERPASS": adminpass, + "MEMBEROF_CONFIG": memberof_config}) + setup_file(setup_path("modules.conf"), paths.modulesconf, + {"REALM": names.realm}) + + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "user")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "config")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "schema")) + mapping = "schema-map-openldap-2.3" + backend_schema = "backend-schema.schema" + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") message("Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri) -- cgit From 677dc6aa897aed0919050545155fbd868c210b89 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Thu, 27 Mar 2008 17:49:56 +0100 Subject: provision: Initialize uninitialized variables if "targetdir" is not defined and there is no smb.conf file (This used to be commit 19c29f473883be0a17fa740de9feb226f347df4a) --- source4/scripting/python/samba/provision.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 47d00f8871..e97ce694b4 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -373,7 +373,10 @@ def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrol lockdir_line = "lock dir = " + os.path.abspath(targetdir) default_lp.set("lock dir", os.path.abspath(targetdir)) - + else: + privatedir_line = "private_dir = " + default_lp.get("private dir") + lockdir_line = "lock dir = " + default_lp.get("lock dir") + sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") netlogon = os.path.join(sysvol, realm.lower(), "scripts") -- cgit From b2c6ba69a453aaa7cbabb7be7b8c2a05b48a76c4 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Thu, 27 Mar 2008 16:30:18 -0500 Subject: provision: Increase max NetBIOS name length from 13 to 15. Issue originally reported by user Julsa-FR on IRC. (This used to be commit ee9ad77009ef5e36655a49c41730a4a963ba9d43) --- source4/scripting/python/samba/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index e91b320c07..b9d81c6c3c 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -225,7 +225,7 @@ def valid_netbios_name(name): """Check whether a name is valid as a NetBIOS name. """ # FIXME: There are probably more constraints here. # crh has a paragraph on this in his book (1.4.1.1) - if len(name) > 13: + if len(name) > 15: return False return True -- cgit From 4ddce8c28ca5abe2ac52cfb3a2956803f585b51a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 28 Mar 2008 10:38:12 +1100 Subject: Don't specify what should be a default option in the generated smb.conf Instead, sub in "", so that the default continued to come from the code. Andrew Bartlett (This used to be commit b1829da8f75175fcc569a3a9195f2358731055a9) --- source4/scripting/python/samba/provision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index e97ce694b4..d5e66d842c 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -374,8 +374,8 @@ def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrol default_lp.set("lock dir", os.path.abspath(targetdir)) else: - privatedir_line = "private_dir = " + default_lp.get("private dir") - lockdir_line = "lock dir = " + default_lp.get("lock dir") + privatedir_line = "" + lockdir_line = "" sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") netlogon = os.path.join(sysvol, realm.lower(), "scripts") -- cgit From 786deaf9288c77b40892d6639113e580a7be6904 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 28 Mar 2008 12:08:54 +1100 Subject: Make the setup/newuser and setup/setpassword scripts actually work... These need a testsuite, but this will come soon. Andrew Bartlett (This used to be commit fbcaa622bd1929399e32326349e96b6676a49b96) --- source4/scripting/python/samba/samdb.py | 58 ++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 3c6bb23c02..de0fd4ba04 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -77,10 +77,15 @@ unixName: %s :param user_dn: Dn of the account to enable. """ - res = self.search(user_dn, SCOPE_ONELEVEL, None, ["userAccountControl"]) + res = self.search(user_dn, ldb.SCOPE_BASE, None, ["userAccountControl"]) assert len(res) == 1 - userAccountControl = res[0].userAccountControl - userAccountControl = userAccountControl - 2 # remove disabled bit + userAccountControl = res[0]["userAccountControl"][0] + userAccountControl = int(userAccountControl) + if (userAccountControl & 0x2): + userAccountControl = userAccountControl & ~0x2 # remove disabled bit + if (userAccountControl & 0x20): + userAccountControl = userAccountControl & ~0x20 # remove 'no password required' bit + mod = """ dn: %s changetype: modify @@ -103,13 +108,9 @@ userAccountControl: %u res = self.search("", scope=ldb.SCOPE_BASE, expression="(defaultNamingContext=*)", attrs=["defaultNamingContext"]) - assert(len(res) == 1 and res[0].defaultNamingContext is not None) + assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None) domain_dn = res[0]["defaultNamingContext"][0] assert(domain_dn is not None) - dom_users = self.searchone(basedn=domain_dn, attribute="dn", - expression="name=Domain Users") - assert(dom_users is not None) - user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) # @@ -123,19 +124,44 @@ userAccountControl: %u "sambaPassword": password, "objectClass": "user"}) - # add the user to the users group as well - modgroup = """ + # modify the userAccountControl to remove the disabled bit + self.enable_account(user_dn) + self.transaction_commit() + + def setpassword(self, filter, password): + """Set a password on a user record + + :param filter: LDAP filter to find the user (eg samccountname=name) + :param password: Password for the user + """ + # connect to the sam + self.transaction_start() + + # find the DNs for the domain + res = self.search("", scope=ldb.SCOPE_BASE, + expression="(defaultNamingContext=*)", + attrs=["defaultNamingContext"]) + assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None) + domain_dn = res[0]["defaultNamingContext"][0] + assert(domain_dn is not None) + + res = self.search(domain_dn, scope=ldb.SCOPE_SUBTREE, + expression=filter, + attrs=[]) + assert(len(res) == 1) + user_dn = res[0].dn + + setpw = """ dn: %s changetype: modify -add: member -member: %s -""" % (dom_users, user_dn) - +replace: sambaPassword +sambaPassword: %s +""" % (user_dn, password) - self.modify(modgroup) + self.modify_ldif(setpw) # modify the userAccountControl to remove the disabled bit - enable_account(self, user_dn) + self.enable_account(user_dn) self.transaction_commit() def set_domain_sid(self, sid): -- cgit From 142fbfb3c1f9f8cda7f0edaa801f8345f23d805f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 28 Mar 2008 21:57:15 +1100 Subject: Fix and test python scripts and kerberos This fixes up the python credentials interface in a number of areas, with the aim of supporting '-k yes' as a command line option. (This enables the use of kerberos). As such, I've had to change the get_credentials call to take a loadparm context, so that the credentials can be initialised correctly. The test_kinit script has been modified to prove that this continues to work, as well as to provide greater code coverage of the kerberos paths. Andrew Bartlett (This used to be commit 727ef40c2b56910028ef3c1092b8eab1bfa6ce63) --- source4/scripting/python/samba/getopt.py | 15 ++++++++++++--- source4/scripting/python/samba/tests/samdb.py | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 088a5acf6f..82cb004b62 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -18,7 +18,7 @@ # import optparse -from credentials import Credentials +from credentials import Credentials, AUTO_USE_KERBEROS, DONT_USE_KERBEROS, MUST_USE_KERBEROS class SambaOptions(optparse.OptionGroup): def __init__(self, parser): @@ -65,6 +65,9 @@ class CredentialsOptions(optparse.OptionGroup): help="Workgroup", callback=self._parse_workgroup) self.add_option("-N", "--no-pass", action="store_true", help="Don't ask for a password") + self.add_option("-k", "--kerberos", metavar="KERBEROS", + action="callback", type=str, + help="Use Kerberos", callback=self._set_kerberos) self.creds = Credentials() def _parse_username(self, option, opt_str, arg, parser): @@ -76,11 +79,17 @@ class CredentialsOptions(optparse.OptionGroup): def _set_password(self, option, opt_str, arg, parser): self.creds.set_password(arg) + def _set_kerberos(self, option, opt_str, arg, parser): + if bool(arg) or arg.lower() == "yes": + self.creds.set_kerberos_state(MUST_USE_KERBEROS) + else: + self.creds.set_kerberos_state(DONT_USE_KERBEROS) + def _set_simple_bind_dn(self, option, opt_str, arg, parser): self.creds.set_bind_dn(arg) - def get_credentials(self): - self.creds.guess() + def get_credentials(self, lp): + self.creds.guess(lp) if not self.no_pass: self.creds.set_cmdline_callbacks() return self.creds diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 40e56bebb5..3745dba6fc 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -38,6 +38,7 @@ class SamDBTestCase(TestCaseInTempDir): policyguid = uuid.random() setup_path = lambda x: os.path.join("setup", x) creds = Credentials() + creds.set_anonymous() domainsid = security.random_sid() hostguid = uuid.random() path = os.path.join(self.tempdir, "samdb.ldb") -- cgit From 238a1a52f1fd3cce0a0fd980c1717c8540a1c7a1 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sat, 29 Mar 2008 17:17:56 +1100 Subject: Rework 'compleated' message in provision to be more useful. In particular, this should draw attention to accidential 'standalone' server provisions and therefore cause less frustration. Andrew Bartlett (This used to be commit e906ae041a2b589ffceff97b74f7c4b01386382a) --- source4/scripting/python/samba/provision.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d5e66d842c..b03457e57b 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -974,10 +974,6 @@ def provision(setup_dir, message, session_info, # provision-backend will set this path suggested slapd command line / fedorads.inf ldap_backend = "ldapi://" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - message("set DOMAIN SID: %s" % str(domainsid)) - message("Provisioning for %s in realm %s" % (names.domain, realm)) - message("Using administrator password: %s" % adminpass) - # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") @@ -1036,7 +1032,7 @@ def provision(setup_dir, message, session_info, nobody=nobody, nogroup=nogroup, wheel=wheel, users=users, backup=backup) - message("Setting up sam.ldb rootDSE marking as synchronized") + message("Compleating sam.ldb setup by marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) # Only make a zone file on the first DC, it should be replicated with DNS replication @@ -1051,19 +1047,25 @@ def provision(setup_dir, message, session_info, scope=SCOPE_SUBTREE) assert isinstance(hostguid, str) - message("Setting up DNS zone: %s" % names.dnsdomain) create_zone_file(paths.dns, setup_path, samdb, hostname=names.hostname, hostip=hostip, dnsdomain=names.dnsdomain, domaindn=names.domaindn, dnspass=dnspass, realm=names.realm, domainguid=domainguid, hostguid=hostguid) message("Please install the zone located in %s into your DNS server" % paths.dns) - message("Setting up phpLDAPadmin configuration") create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) + message("Once the above files are installed, your server will be ready to use") + message("Server Type: %s" % serverrole) + message("Hostname: %s" % names.hostname) + message("NetBIOS Domain: %s" % names.domain) + message("DNS Domain: %s" % names.dnsdomain) + message("DOMAIN SID: %s" % str(domainsid)) + message("Admin password: %s" % adminpass) + result = ProvisionResult() result.domaindn = domaindn result.paths = paths -- cgit From 2ab6dd9ea58c7f09791f45077df084447fc7de69 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 2 Apr 2008 11:38:58 +1100 Subject: Remove references to setting the host GUID, as the repl_meta_data module prohibits it anyway. Andrew Bartlett (This used to be commit c5b287c056855892f30fbbf32efe7d65da31ce91) --- source4/scripting/python/samba/provision.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index b03457e57b..50d9f8d2ff 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -695,13 +695,8 @@ def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, def setup_self_join(samdb, names, machinepass, dnspass, domainsid, invocationid, setup_path, - policyguid, hostguid=None): + policyguid): """Join a host to its own domain.""" - if hostguid is not None: - hostguid_add = "objectGUID: %s" % hostguid - else: - hostguid_add = "" - setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, @@ -714,7 +709,6 @@ def setup_self_join(samdb, names, "DNSPASS_B64": b64encode(dnspass), "REALM": names.realm, "DOMAIN": names.domain, - "HOSTGUID_ADD": hostguid_add, "DNSDOMAIN": names.dnsdomain}) setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { "POLICYGUID": policyguid, @@ -727,7 +721,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, names, message, domainsid, aci, domainguid, policyguid, fill, adminpass, krbtgtpass, - machinepass, hostguid, invocationid, dnspass, + machinepass, invocationid, dnspass, serverrole, ldap_backend=None, ldap_backend_type=None): """Setup a complete SAM Database. @@ -880,7 +874,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, dnspass=dnspass, machinepass=machinepass, domainsid=domainsid, policyguid=policyguid, - hostguid=hostguid, setup_path=setup_path) #We want to setup the index last, as adds are faster unindexed @@ -902,7 +895,7 @@ def provision(setup_dir, message, session_info, credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, hostip=None, domainsid=None, - hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, + adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, wheel=None, backup=None, aci=None, serverrole=None, @@ -1006,7 +999,7 @@ def provision(setup_dir, message, session_info, aci=aci, domainguid=domainguid, policyguid=policyguid, fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass, - hostguid=hostguid, invocationid=invocationid, + invocationid=invocationid, machinepass=machinepass, dnspass=dnspass, serverrole=serverrole, ldap_backend=ldap_backend, ldap_backend_type=ldap_backend_type) @@ -1077,7 +1070,7 @@ def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, domainsid=None, - hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, + adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, wheel=None, backup=None, aci=None, serverrole=None, -- cgit From 3c0c6acc594fba1f1d28e49cb105c99fa1649a18 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Tue, 1 Apr 2008 19:51:24 -0500 Subject: provision: Add support for IPv6 (bz #4593). (This used to be commit 8585a3c77d5dfe97bca3f08716fc06ac2819f578) --- source4/scripting/python/samba/provision.py | 34 +++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index b03457e57b..870f64ecc9 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -28,7 +28,7 @@ import pwd import grp import time import uuid, misc -from socket import gethostname, gethostbyname +import socket import param import registry import samba @@ -267,7 +267,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole= rootdn=None, domaindn=None, configdn=None, schemadn=None, sitename=None): if hostname is None: - hostname = gethostname().split(".")[0].lower() + hostname = socket.gethostname().split(".")[0].lower() netbiosname = hostname.upper() if not valid_netbios_name(netbiosname): @@ -348,7 +348,7 @@ def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrol if not os.path.exists(smbconf): if hostname is None: - hostname = gethostname().split(".")[0].lower() + hostname = socket.gethostname().split(".")[0].lower() if serverrole is None: serverrole = "standalone" @@ -901,7 +901,7 @@ FILL_DRS = "DRS" def provision(setup_dir, message, session_info, credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, - domain=None, hostname=None, hostip=None, domainsid=None, + domain=None, hostname=None, hostip=None, hostip6=None, domainsid=None, hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, @@ -955,7 +955,12 @@ def provision(setup_dir, message, session_info, paths = provision_paths_from_lp(lp, names.dnsdomain) if hostip is None: - hostip = gethostbyname(names.hostname) + hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0] + + if hostip6 is None: + try: + hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0] + except socket.gaierror: pass if serverrole is None: serverrole = lp.get("server role") @@ -1048,7 +1053,8 @@ def provision(setup_dir, message, session_info, assert isinstance(hostguid, str) create_zone_file(paths.dns, setup_path, samdb, - hostname=names.hostname, hostip=hostip, dnsdomain=names.dnsdomain, + hostname=names.hostname, hostip=hostip, + hostip6=hostip6, dnsdomain=names.dnsdomain, domaindn=names.domaindn, dnspass=dnspass, realm=names.realm, domainguid=domainguid, hostguid=hostguid) message("Please install the zone located in %s into your DNS server" % paths.dns) @@ -1114,7 +1120,7 @@ def provision_backend(setup_dir=None, message=None, return os.path.join(setup_dir, file) if hostname is None: - hostname = gethostname().split(".")[0].lower() + hostname = socket.gethostname().split(".")[0].lower() if root is None: root = findnss(pwd.getpwnam, ["root"])[0] @@ -1247,7 +1253,7 @@ def create_phpldapadmin_config(path, setup_path, ldapi_uri): def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, - hostip, hostname, dnspass, realm, domainguid, hostguid): + hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid): """Write out a DNS zone file, from the info in the current database. :param path: Path of the new file. @@ -1255,7 +1261,8 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, :param samdb: SamDB object :param dnsdomain: DNS Domain name :param domaindn: DN of the Domain - :param hostip: Local IP + :param hostip: Local IPv4 IP + :param hostip6: Local IPv6 IP :param hostname: Local hostname :param dnspass: Password for DNS :param realm: Realm name @@ -1264,6 +1271,13 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, """ assert isinstance(domainguid, str) + hostip6_base_line = "" + hostip6_host_line = "" + + if hostip6 is not None: + hostip6_base_line = " IN AAAA " + hostip6 + hostip6_host_line = hostname + " IN AAAA " + hostip6 + setup_file(setup_path("provision.zone"), path, { "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": hostname, @@ -1274,6 +1288,8 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, "DATESTRING": time.strftime("%Y%m%d%H"), "DEFAULTSITE": DEFAULTSITE, "HOSTGUID": hostguid, + "HOSTIP6_BASE_LINE": hostip6_base_line, + "HOSTIP6_HOST_LINE": hostip6_host_line, }) def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): -- cgit From 8ac91d913231ecd7ead595b93032c7486f67c949 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Tue, 1 Apr 2008 00:17:00 +0200 Subject: provision: Set up id mappings in the idmap db, only map Administrator. (This used to be commit 206b7d387c6d17e5cc40fd45b489abac9235a7a4) --- source4/scripting/python/samba/idmap.py | 73 +++++++++++++++++++++ source4/scripting/python/samba/provision.py | 98 ++++++++++++++--------------- source4/scripting/python/samba/samdb.py | 19 ------ 3 files changed, 120 insertions(+), 70 deletions(-) create mode 100644 source4/scripting/python/samba/idmap.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py new file mode 100644 index 0000000000..355565968a --- /dev/null +++ b/source4/scripting/python/samba/idmap.py @@ -0,0 +1,73 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) 2008 Kai Blin +# +# +# 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 . +# + +"""Convenience functions for using the idmap database.""" + +import samba +import ldb + +class IDmapDB(samba.Ldb): + """The IDmap database.""" + + # Mappings for ID_TYPE_UID, ID_TYPE_GID and ID_TYPE_BOTH + TYPE_UID = 1 + TYPE_GID = 2 + TYPE_BOTH = 3 + + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + """Open the IDmap Database. + + :param url: URL of the database. + """ + super(IDmapDB, self).__init__(session_info=session_info, credentials=credentials, + modules_dir=modules_dir, lp=lp) + if url: + self.connect(url) + + + def setup_name_mapping(self, sid, type, unixid): + """Setup a mapping between a sam name and a unix name. + + :param sid: SID of the NT-side of the mapping. + :param unixname: Unix name to map to. + """ + type_string = "" + if type == self.TYPE_UID: + type_string = "ID_TYPE_UID" + elif type == self.TYPE_GID: + type_string = "ID_TYPE_GID" + elif type == self.TYPE_BOTH: + type_string = "ID_TYPE_BOTH" + else: + return + + mod = """ +dn: CN=%s +xidNumber: %s +objectSid: %s +objectClass: sidMap +type: %s +cn: %s + +""" % (sid, unixid, sid, type_string, sid) + self.add(self.parse_ldif(mod).next()[1]) + + diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index dfeb61e52b..a8ced61c4b 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -35,6 +35,7 @@ import samba from auth import system_session from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted from samba.samdb import SamDB +from samba.idmap import IDmapDB import security import urllib from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ @@ -397,45 +398,32 @@ def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrol return lp -def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, - wheel, backup): +def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, + users_gid, wheel_gid, backup_gid): """setup reasonable name mappings for sam names to unix names. - - :param ldb: SamDB object. + + :param samdb: SamDB object. + :param idmap: IDmap db 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.""" + :param root_uid: uid of the UNIX root user. + :param nobody_uid: uid of the UNIX nobody user. + :param users_gid: gid of the UNIX users group. + :param wheel_gid: gid of the UNIX wheel group. + :param backup_gid: gid of the UNIX backup group.""" # 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-1-0", "World") - ldb.add_foreign(domaindn, "S-1-5-2", "Network") - ldb.add_foreign(domaindn, "S-1-5-18", "System") - ldb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users") - - # some well known sids - ldb.setup_name_mapping(domaindn, "S-1-5-7", nobody) - ldb.setup_name_mapping(domaindn, "S-1-1-0", nogroup) - ldb.setup_name_mapping(domaindn, "S-1-5-2", nogroup) - ldb.setup_name_mapping(domaindn, "S-1-5-18", root) - ldb.setup_name_mapping(domaindn, "S-1-5-11", users) - ldb.setup_name_mapping(domaindn, "S-1-5-32-544", wheel) - ldb.setup_name_mapping(domaindn, "S-1-5-32-545", users) - ldb.setup_name_mapping(domaindn, "S-1-5-32-546", nogroup) - ldb.setup_name_mapping(domaindn, "S-1-5-32-551", backup) - - # and some well known domain rids - ldb.setup_name_mapping(domaindn, sid + "-500", root) - ldb.setup_name_mapping(domaindn, sid + "-518", wheel) - ldb.setup_name_mapping(domaindn, sid + "-519", wheel) - ldb.setup_name_mapping(domaindn, sid + "-512", wheel) - ldb.setup_name_mapping(domaindn, sid + "-513", users) - ldb.setup_name_mapping(domaindn, sid + "-520", wheel) + samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous") + samdb.add_foreign(domaindn, "S-1-1-0", "World") + samdb.add_foreign(domaindn, "S-1-5-2", "Network") + samdb.add_foreign(domaindn, "S-1-5-18", "System") + samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users") + idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid) + idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid) + idmap.setup_name_mapping("S-1-5-32-551", idmap.TYPE_GID, backup_gid) + + idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid) + idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid) def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, credentials, names, @@ -663,8 +651,8 @@ def setup_idmapdb(path, setup_path, session_info, credentials, lp): if os.path.exists(path): os.unlink(path) - idmap_ldb = Ldb(path, session_info=session_info, credentials=credentials, - lp=lp) + idmap_ldb = IDmapDB(path, session_info=session_info, + credentials=credentials, lp=lp) idmap_ldb.erase() idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) @@ -924,18 +912,25 @@ def provision(setup_dir, message, session_info, if dnspass is None: dnspass = misc.random_password(12) if root is None: - root = findnss(pwd.getpwnam, ["root"])[0] + root_uid = findnss(pwd.getpwnam, ["root"])[2] + else: + root_uid = findnss(pwd.getpwnam, [root])[2] if nobody is None: - nobody = findnss(pwd.getpwnam, ["nobody"])[0] - if nogroup is None: - nogroup = findnss(grp.getgrnam, ["nogroup", "nobody"])[0] + nobody_uid = findnss(pwd.getpwnam, ["nobody"])[2] + else: + nobody_uid = findnss(pwd.getpwnam, [nobody])[2] if users is None: - users = findnss(grp.getgrnam, ["users", "guest", "other", "unknown", - "usr"])[0] + users_gid = findnss(grp.getgrnam, ["users"])[2] + else: + users_gid = findnss(grp.getgrnam, [users])[2] if wheel is None: - wheel = findnss(grp.getgrnam, ["wheel", "root", "staff", "adm"])[0] + wheel_gid = findnss(grp.getgrnam, ["wheel", "adm"])[2] + else: + wheel_gid = findnss(grp.getgrnam, [wheel])[2] if backup is None: - backup = findnss(grp.getgrnam, ["backup", "wheel", "root", "staff"])[0] + backup_gid = findnss(grp.getgrnam, ["backup", "staff"])[2] + else: + backup_gid = findnss(grp.getgrnam, [backup])[2] if aci is None: aci = "# no aci for local ldb" @@ -994,8 +989,8 @@ def provision(setup_dir, message, session_info, credentials=credentials, lp=lp) message("Setting up idmap db") - setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, - credentials=credentials, lp=lp) + idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, + credentials=credentials, lp=lp) samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials, lp=lp, names=names, @@ -1026,11 +1021,12 @@ def provision(setup_dir, message, session_info, machinepass=machinepass, dnsdomain=names.dnsdomain) if samdb_fill == FILL_FULL: - setup_name_mappings(samdb, str(domainsid), names.domaindn, root=root, - nobody=nobody, nogroup=nogroup, wheel=wheel, - users=users, backup=backup) - - message("Compleating sam.ldb setup by marking as synchronized") + setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn, + root_uid=root_uid, nobody_uid=nobody_uid, + users_gid=users_gid, wheel_gid=wheel_gid, + backup_gid=backup_gid) + + message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) # Only make a zone file on the first DC, it should be replicated with DNS replication diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index de0fd4ba04..bc3eef7879 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -53,25 +53,6 @@ description: %s for msg in self.parse_ldif(add): self.add(msg[1]) - def setup_name_mapping(self, domaindn, sid, unixname): - """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(domaindn, ldb.SCOPE_SUBTREE, - "objectSid=%s" % sid, ["dn"]) - assert len(res) == 1, "Failed to find record for objectSid %s" % sid - - mod = """ -dn: %s -changetype: modify -replace: unixName -unixName: %s -""" % (res[0].dn, unixname) - self.modify(self.parse_ldif(mod).next()[1]) - def enable_account(self, user_dn): """Enable an account. -- cgit From c26387a473fd26ac51c74c001b520d7fd7d353ec Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Thu, 3 Apr 2008 00:01:34 +0200 Subject: provision: Remove backup group mapping Some distros seem to neither have a backup nor a staff group. (This used to be commit 21fcf7c419658b3ae296428ca7a4ccf2288c17fe) --- source4/scripting/python/samba/provision.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index a8ced61c4b..6917aa1a54 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -399,7 +399,7 @@ def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrol return lp def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, - users_gid, wheel_gid, backup_gid): + users_gid, wheel_gid): """setup reasonable name mappings for sam names to unix names. :param samdb: SamDB object. @@ -409,8 +409,7 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, :param root_uid: uid of the UNIX root user. :param nobody_uid: uid of the UNIX nobody user. :param users_gid: gid of the UNIX users group. - :param wheel_gid: gid of the UNIX wheel group. - :param backup_gid: gid of the UNIX backup group.""" + :param wheel_gid: gid of the UNIX wheel group.""" # add some foreign sids if they are not present already samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous") samdb.add_foreign(domaindn, "S-1-1-0", "World") @@ -420,7 +419,6 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid) idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid) - idmap.setup_name_mapping("S-1-5-32-551", idmap.TYPE_GID, backup_gid) idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid) idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid) @@ -927,10 +925,6 @@ def provision(setup_dir, message, session_info, wheel_gid = findnss(grp.getgrnam, ["wheel", "adm"])[2] else: wheel_gid = findnss(grp.getgrnam, [wheel])[2] - if backup is None: - backup_gid = findnss(grp.getgrnam, ["backup", "staff"])[2] - else: - backup_gid = findnss(grp.getgrnam, [backup])[2] if aci is None: aci = "# no aci for local ldb" @@ -1023,8 +1017,7 @@ def provision(setup_dir, message, session_info, if samdb_fill == FILL_FULL: setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn, root_uid=root_uid, nobody_uid=nobody_uid, - users_gid=users_gid, wheel_gid=wheel_gid, - backup_gid=backup_gid) + users_gid=users_gid, wheel_gid=wheel_gid) message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) -- cgit From c764791100079ed447c07ca6b99d33f9695255c3 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 4 Apr 2008 12:25:19 +1100 Subject: Clean up provision and rootdse module to hard-code less stuff. In particular, allow for the server DN to be in a different site (possible outcome of a DRS replication). Andrew Bartlett (This used to be commit 9ee4e39fe178317f42fd9a0adceea24b55dfe0f1) --- source4/scripting/python/samba/provision.py | 42 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6917aa1a54..02460070b4 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -265,7 +265,8 @@ def provision_paths_from_lp(lp, dnsdomain): return paths def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None, - rootdn=None, domaindn=None, configdn=None, schemadn=None, sitename=None): + rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None, + sitename=None): if hostname is None: hostname = socket.gethostname().split(".")[0].lower() @@ -332,6 +333,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole= names.netbiosname = netbiosname names.hostname = hostname names.sitename = sitename + names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn) return names @@ -543,9 +545,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, samdb.load_ldif_file_add(setup_path("provision_init.ldif")) message("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, setup_path, names.schemadn, names.domaindn, names.hostname, - names.dnsdomain, names.realm, names.rootdn, names.configdn, names.netbiosname, - names.sitename) + setup_samdb_rootdse(samdb, setup_path, names) if erase: message("Erasing data from partitions") @@ -656,25 +656,22 @@ def setup_idmapdb(path, setup_path, session_info, credentials, lp): idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) return idmap_ldb -def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, - dnsdomain, realm, rootdn, configdn, netbiosname, - sitename): +def setup_samdb_rootdse(samdb, setup_path, names): """Setup the SamDB rootdse. :param samdb: Sam Database handle :param setup_path: Obtain setup path """ setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), { - "SCHEMADN": schemadn, - "NETBIOSNAME": netbiosname, - "DNSDOMAIN": dnsdomain, - "DEFAULTSITE": sitename, - "REALM": realm, - "DNSNAME": "%s.%s" % (hostname, dnsdomain), - "DOMAINDN": domaindn, - "ROOTDN": rootdn, - "CONFIGDN": configdn, - "VERSION": samba.version(), + "SCHEMADN": names.schemadn, + "NETBIOSNAME": names.netbiosname, + "DNSDOMAIN": names.dnsdomain, + "REALM": names.realm, + "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain), + "DOMAINDN": names.domaindn, + "ROOTDN": names.rootdn, + "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn, }) @@ -879,7 +876,8 @@ FILL_DRS = "DRS" def provision(setup_dir, message, session_info, credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, - rootdn=None, domaindn=None, schemadn=None, configdn=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + serverdn=None, domain=None, hostname=None, hostip=None, hostip6=None, domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, @@ -932,7 +930,8 @@ def provision(setup_dir, message, session_info, names = guess_names(lp=lp, hostname=hostname, domain=domain, dnsdomain=realm, serverrole=serverrole, sitename=sitename, - rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn) + rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn, + serverdn=serverdn) paths = provision_paths_from_lp(lp, names.dnsdomain) @@ -1064,12 +1063,13 @@ def provision(setup_dir, message, session_info, def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, + serverdn=None, domain=None, hostname=None, domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, wheel=None, backup=None, aci=None, serverrole=None, - ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): + ldap_backend=None, ldap_backend_type=None, sitename=None): def message(text): """print a message if quiet is not set.""" @@ -1077,7 +1077,7 @@ def provision_become_dc(setup_dir=None, provision(setup_dir, message, system_session(), None, smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, - rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, + rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn, domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); -- cgit From 14e443b868f56db0b29c3221c175f1a2cd2a8d1d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 5 Apr 2008 16:13:42 +0200 Subject: Improve PEP8 (Python code style) compliancy a bit. (This used to be commit c7d388a6e2153234fe67daf1af094fc346e1da61) --- source4/scripting/python/samba/provision.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6917aa1a54..9151f29603 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -264,8 +264,10 @@ def provision_paths_from_lp(lp, dnsdomain): return paths -def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None, - rootdn=None, domaindn=None, configdn=None, schemadn=None, sitename=None): + +def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, + serverrole=None, rootdn=None, domaindn=None, configdn=None, + schemadn=None, sitename=None): if hostname is None: hostname = socket.gethostname().split(".")[0].lower() @@ -336,7 +338,8 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole= return names -def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, targetdir): +def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, + serverrole, targetdir): if targetdir is not None: if not os.path.exists(targetdir): os.mkdir(targetdir) @@ -423,6 +426,7 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid) idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid) + def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, credentials, names, serverrole, ldap_backend=None, @@ -543,8 +547,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, samdb.load_ldif_file_add(setup_path("provision_init.ldif")) message("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, setup_path, names.schemadn, names.domaindn, names.hostname, - names.dnsdomain, names.realm, names.rootdn, names.configdn, names.netbiosname, + setup_samdb_rootdse(samdb, setup_path, names.schemadn, names.domaindn, + names.hostname, names.dnsdomain, names.realm, + names.rootdn, names.configdn, names.netbiosname, names.sitename) if erase: @@ -637,6 +642,7 @@ def setup_registry(path, setup_path, session_info, credentials, lp): assert os.path.exists(provision_reg) reg.diff_apply(provision_reg) + def setup_idmapdb(path, setup_path, session_info, credentials, lp): """Setup the idmap database. @@ -656,6 +662,7 @@ def setup_idmapdb(path, setup_path, session_info, credentials, lp): idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) return idmap_ldb + def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, dnsdomain, realm, rootdn, configdn, netbiosname, sitename): @@ -740,7 +747,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, if serverrole == "domain controller": samdb.set_invocation_id(invocationid) - load_schema(setup_path, samdb, names.schemadn, names.netbiosname, names.configdn, names.sitename) + load_schema(setup_path, samdb, names.schemadn, names.netbiosname, + names.configdn, names.sitename) samdb.transaction_start() -- cgit From 3e97aa73c22ea036afb586b16a1d130ee46e5697 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 5 Apr 2008 16:32:28 +0200 Subject: Simplify some code, fix style. (This used to be commit 1c983e4e4dfb93387791c36dc96696c4fffcfeb7) --- source4/scripting/python/samba/provision.py | 201 ++++++++++++++-------------- 1 file changed, 99 insertions(+), 102 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 9151f29603..f81cedc729 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -103,7 +103,7 @@ def check_install(lp, session_info, credentials): :param credentials: Credentials """ if lp.get("realm") == "": - raise Error("Realm empty") + raise Exception("Realm empty") ldb = Ldb(lp.get("sam database"), session_info=session_info, credentials=credentials, lp=lp) if len(ldb.search("(cn=Administrator)")) != 1: @@ -288,8 +288,8 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, realm = dnsdomain.upper() if lp.get("realm").upper() != realm: - raise Exception("realm '%s' in %s must match chosen realm '%s'" % - (lp.get("realm"), smbconf, realm)) + raise Exception("realm '%s' must match chosen realm '%s'" % + (lp.get("realm"), realm)) dnsdomain = dnsdomain.lower() @@ -299,7 +299,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, if domaindn is None: domaindn = "DC=" + dnsdomain.replace(".", ",DC=") if lp.get("workgroup").upper() != domain.upper(): - raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'", + raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'", lp.get("workgroup"), domain) else: domain = netbiosname @@ -338,68 +338,52 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, return names -def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, - serverrole, targetdir): - if targetdir is not None: - if not os.path.exists(targetdir): - os.mkdir(targetdir) - if not os.path.exists(os.path.join(targetdir, "etc")): - os.mkdir(os.path.join(targetdir, "etc")) - - smbconf = os.path.join(targetdir, "etc", "smb.conf") +def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, + targetdir): + if hostname is None: + hostname = socket.gethostname().split(".")[0].lower() - # only install a new smb.conf if there isn't one there already + if serverrole is None: + serverrole = "standalone" - if not os.path.exists(smbconf): - if hostname is None: - hostname = socket.gethostname().split(".")[0].lower() + assert serverrole in ("domain controller", "member server", "standalone") + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member server": + smbconfsuffix = "member" + elif serverrole == "standalone": + smbconfsuffix = "standalone" - if serverrole is None: - serverrole = "standalone" + assert domain is not None + assert realm is not None - assert serverrole in ("domain controller", "member server", "standalone") - if serverrole == "domain controller": - smbconfsuffix = "dc" - elif serverrole == "member server": - smbconfsuffix = "member" - elif serverrole == "standalone": - smbconfsuffix = "standalone" - - assert domain is not None - assert realm is not None - - default_lp = param.LoadParm() - #Load non-existant file - default_lp.load(smbconf) - - if targetdir is not None: - privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) - lockdir_line = "lock dir = " + os.path.abspath(targetdir) + default_lp = param.LoadParm() + #Load non-existant file + default_lp.load(smbconf) + + if targetdir is not None: + privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) + lockdir_line = "lock dir = " + os.path.abspath(targetdir) - default_lp.set("lock dir", os.path.abspath(targetdir)) - else: - privatedir_line = "" - lockdir_line = "" - - sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") - netlogon = os.path.join(sysvol, realm.lower(), "scripts") - - setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), - smbconf, { - "HOSTNAME": hostname, - "DOMAIN": domain, - "REALM": realm, - "SERVERROLE": serverrole, - "NETLOGONPATH": netlogon, - "SYSVOLPATH": sysvol, - "PRIVATEDIR_LINE": privatedir_line, - "LOCKDIR_LINE": lockdir_line - }) + default_lp.set("lock dir", os.path.abspath(targetdir)) + else: + privatedir_line = "" + lockdir_line = "" - lp = param.LoadParm() - lp.load(smbconf) + sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") + netlogon = os.path.join(sysvol, realm.lower(), "scripts") - return lp + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), + smbconf, { + "HOSTNAME": hostname, + "DOMAIN": domain, + "REALM": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": netlogon, + "SYSVOLPATH": sysvol, + "PRIVATEDIR_LINE": privatedir_line, + "LOCKDIR_LINE": lockdir_line + }) def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, users_gid, wheel_gid): @@ -493,8 +477,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, schemadn_ldb = "schema.ldb" if ldap_backend is not None: schema_ldb = ldap_backend - schemadn_ldb = ldap_backend - + schemadn_ldb = ldap_backend + if ldap_backend_type == "fedora-ds": backend_modules = ["nsuniqueid", "paged_searches"] # We can handle linked attributes here, as we don't have directory-side subtree operations @@ -886,14 +870,15 @@ FILL_NT4SYNC = "NT4SYNC" FILL_DRS = "DRS" def provision(setup_dir, message, session_info, - credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, - rootdn=None, domaindn=None, schemadn=None, configdn=None, - domain=None, hostname=None, hostip=None, hostip6=None, - domainsid=None, adminpass=None, krbtgtpass=None, domainguid=None, - policyguid=None, invocationid=None, machinepass=None, - dnspass=None, root=None, nobody=None, nogroup=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, - ldap_backend=None, ldap_backend_type=None, sitename=None): + credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, + realm=None, rootdn=None, domaindn=None, schemadn=None, + configdn=None, domain=None, hostname=None, hostip=None, + hostip6=None, domainsid=None, adminpass=None, krbtgtpass=None, + domainguid=None, policyguid=None, invocationid=None, + machinepass=None, dnspass=None, root=None, nobody=None, + nogroup=None, users=None, wheel=None, backup=None, aci=None, + serverrole=None, ldap_backend=None, ldap_backend_type=None, + sitename=None): """Provision samba4 :note: caution, this wipes all existing data! @@ -917,18 +902,9 @@ def provision(setup_dir, message, session_info, machinepass = misc.random_password(12) if dnspass is None: dnspass = misc.random_password(12) - if root is None: - root_uid = findnss(pwd.getpwnam, ["root"])[2] - else: - root_uid = findnss(pwd.getpwnam, [root])[2] - if nobody is None: - nobody_uid = findnss(pwd.getpwnam, ["nobody"])[2] - else: - nobody_uid = findnss(pwd.getpwnam, [nobody])[2] - if users is None: - users_gid = findnss(grp.getgrnam, ["users"])[2] - else: - users_gid = findnss(grp.getgrnam, [users])[2] + root_uid = findnss(pwd.getpwnam, [root or "root"])[2] + nobody_uid = findnss(pwd.getpwnam, [nobody or "nobody"])[2] + users_gid = findnss(grp.getgrnam, [users or "users"])[2] if wheel is None: wheel_gid = findnss(grp.getgrnam, ["wheel", "adm"])[2] else: @@ -936,7 +912,17 @@ def provision(setup_dir, message, session_info, if aci is None: aci = "# no aci for local ldb" - lp = load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, targetdir) + if smbconf is None: + os.makedirs(os.path.join(targetdir, "etc")) + smbconf = os.path.join(targetdir, "etc", "smb.conf") + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): + make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, + targetdir) + + lp = param.LoadParm() + lp.load(smbconf) names = guess_names(lp=lp, hostname=hostname, domain=domain, dnsdomain=realm, serverrole=serverrole, sitename=sitename, @@ -1080,7 +1066,7 @@ def provision_become_dc(setup_dir=None, ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): def message(text): - """print a message if quiet is not set.""" + """print a message if quiet is not set.""" print text provision(setup_dir, message, system_session(), None, @@ -1115,11 +1101,22 @@ def provision_backend(setup_dir=None, message=None, if root is None: root = findnss(pwd.getpwnam, ["root"])[0] - lp = load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, targetdir) + if smbconf is None: + os.makedirs(os.path.join(targetdir, "etc")) + smbconf = os.path.join(targetdir, "etc", "smb.conf") + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): + make_smbconf(smbconf, setup_path, hostname, domain, realm, + serverrole, targetdir) + + lp = param.LoadParm() + lp.load(smbconf) names = guess_names(lp=lp, hostname=hostname, domain=domain, dnsdomain=realm, serverrole=serverrole, - rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn) + rootdn=rootdn, domaindn=domaindn, configdn=configdn, + schemadn=schemadn) paths = provision_paths_from_lp(lp, names.dnsdomain) @@ -1175,11 +1172,11 @@ def provision_backend(setup_dir=None, message=None, backend_schema = "99_ad.ldif" elif ldap_backend_type == "openldap": attrs = ["linkID", "lDAPDisplayName"] - res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs); + res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs); - memberof_config = "# Generated from schema in " + schemadb_path + "\n"; - refint_attributes = ""; - for i in range (0, len(res)): + memberof_config = "# Generated from schema in " + schemadb_path + "\n"; + refint_attributes = ""; + for i in range (0, len(res)): linkid = res[i]["linkID"][0] linkid = str(int(linkid) + 1) expression = "(&(objectclass=attributeSchema)(linkID=" + (linkid) + "))" @@ -1199,11 +1196,11 @@ memberof-dangling-error 32 """; - memberof_config = memberof_config + """ + memberof_config = memberof_config + """ overlay refint refint_attributes""" + refint_attributes + "\n"; - - setup_file(setup_path("slapd.conf"), paths.slapdconf, + + setup_file(setup_path("slapd.conf"), paths.slapdconf, {"DNSDOMAIN": names.dnsdomain, "LDAPDIR": paths.ldapdir, "DOMAINDN": names.domaindn, @@ -1212,18 +1209,18 @@ refint_attributes""" + refint_attributes + "\n"; "LDAPMANAGERDN": names.ldapmanagerdn, "LDAPMANAGERPASS": adminpass, "MEMBEROF_CONFIG": memberof_config}) - setup_file(setup_path("modules.conf"), paths.modulesconf, + setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "user")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "config")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "schema")) - mapping = "schema-map-openldap-2.3" - backend_schema = "backend-schema.schema" + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "user")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "config")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "schema")) + mapping = "schema-map-openldap-2.3" + backend_schema = "backend-schema.schema" - ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - message("Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri) + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + message("Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri) schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema); @@ -1265,8 +1262,8 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, hostip6_host_line = "" if hostip6 is not None: - hostip6_base_line = " IN AAAA " + hostip6 - hostip6_host_line = hostname + " IN AAAA " + hostip6 + hostip6_base_line = " IN AAAA " + hostip6 + hostip6_host_line = hostname + " IN AAAA " + hostip6 setup_file(setup_path("provision.zone"), path, { "DNSPASS_B64": b64encode(dnspass), -- cgit From 7c7880695b02df4cbe0faab959846c63d0cc0536 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 6 Apr 2008 00:40:01 +0200 Subject: More PEP8 compliancy. (This used to be commit d16b30d005933c9cc73f9196a3b77829d23687a0) --- source4/scripting/python/samba/provision.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f81cedc729..4d5a9cb1f1 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -125,6 +125,10 @@ def findnss(nssfn, names): raise KeyError("Unable to find user/group %r" % names) +findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2] +findnss_gid = lambda names: findnss(grp.getgrnam, names)[2] + + def open_ldb(session_info, credentials, lp, dbname): """Open a LDB, thrashing it if it is corrupt. @@ -293,7 +297,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, dnsdomain = dnsdomain.lower() - if (serverrole == "domain controller"): + if serverrole == "domain controller": if domain is None: domain = lp.get("workgroup") if domaindn is None: @@ -385,6 +389,7 @@ def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, "LOCKDIR_LINE": lockdir_line }) + def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, users_gid, wheel_gid): """setup reasonable name mappings for sam names to unix names. @@ -902,13 +907,13 @@ def provision(setup_dir, message, session_info, machinepass = misc.random_password(12) if dnspass is None: dnspass = misc.random_password(12) - root_uid = findnss(pwd.getpwnam, [root or "root"])[2] - nobody_uid = findnss(pwd.getpwnam, [nobody or "nobody"])[2] - users_gid = findnss(grp.getgrnam, [users or "users"])[2] + root_uid = findnss_uid([root or "root"]) + nobody_uid = findnss_uid([nobody or "nobody"]) + users_gid = findnss_gid([users or "users"]) if wheel is None: - wheel_gid = findnss(grp.getgrnam, ["wheel", "adm"])[2] + wheel_gid = findnss_gid(["wheel", "adm"]) else: - wheel_gid = findnss(grp.getgrnam, [wheel])[2] + wheel_gid = findnss_gid([wheel]) if aci is None: aci = "# no aci for local ldb" @@ -925,8 +930,9 @@ def provision(setup_dir, message, session_info, lp.load(smbconf) names = guess_names(lp=lp, hostname=hostname, domain=domain, - dnsdomain=realm, serverrole=serverrole, sitename=sitename, - rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn) + dnsdomain=realm, serverrole=serverrole, + sitename=sitename, rootdn=rootdn, domaindn=domaindn, + configdn=configdn, schemadn=schemadn) paths = provision_paths_from_lp(lp, names.dnsdomain) @@ -936,7 +942,8 @@ def provision(setup_dir, message, session_info, if hostip6 is None: try: hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0] - except socket.gaierror: pass + except socket.gaierror: + pass if serverrole is None: serverrole = lp.get("server role") -- cgit From 1f474f4a545752f7ac0ad402d01d1e768b973dbe Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 8 Apr 2008 03:29:12 +0200 Subject: Add trivial test for unixinfo interface. (This used to be commit b6b7171f70114bd27ca8db09964c65cacb9cea92) --- .../scripting/python/samba/tests/dcerpc/unix.py | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 source4/scripting/python/samba/tests/dcerpc/unix.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py new file mode 100644 index 0000000000..99c84c08da --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2008 +# +# 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 . +# + +import unixinfo +import unittest +from samba.tests import get_loadparm + +class UnixinfoTests(unittest.TestCase): + def setUp(self): + self.conn = unixinfo.unixinfo("ncalrpc:", get_loadparm()) + + def test_getpwuid(self): + (count, infos) = self.conn.GetPWUid(1, [0]) + self.assertEquals(1, len(infos)) -- cgit From b2805c50eecddfa4cbd0945e713567eddce05895 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 8 Apr 2008 17:28:25 +1000 Subject: Re-add support for the --ldap-backend-port option to provision-backend This option allows Fedora DS multi-master replication to work. I've tried to update the wiki and scripts to the largely consistant with each other. Andrew Bartlett (This used to be commit 42393c830733b2cc99ebccdafe944fcf3d82734f) --- source4/scripting/python/samba/provision.py | 42 ++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 02460070b4..80dcd522df 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -288,7 +288,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole= if lp.get("realm").upper() != realm: raise Exception("realm '%s' in %s must match chosen realm '%s'" % - (lp.get("realm"), smbconf, realm)) + (lp.get("realm"), lp.configfile(), realm)) dnsdomain = dnsdomain.lower() @@ -1045,8 +1045,8 @@ def provision(setup_dir, message, session_info, message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) - message("Once the above files are installed, your server will be ready to use") - message("Server Type: %s" % serverrole) + message("Once the above files are installed, your Samba4 server will be ready to use") + message("Server Role: %s" % serverrole) message("Hostname: %s" % names.hostname) message("NetBIOS Domain: %s" % names.domain) message("DNS Domain: %s" % names.dnsdomain) @@ -1096,7 +1096,7 @@ def provision_backend(setup_dir=None, message=None, smbconf=None, targetdir=None, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, adminpass=None, root=None, serverrole=None, - ldap_backend_type=None): + ldap_backend_type=None, ldap_backend_port=None): def setup_path(file): return os.path.join(setup_dir, file) @@ -1144,7 +1144,12 @@ def provision_backend(setup_dir=None, message=None, {"SCHEMADN": names.schemadn}) if ldap_backend_type == "fedora-ds": - setup_file(setup_path("fedora-ds.inf"), paths.fedoradsinf, + if ldap_backend_port is not None: + serverport = "ServerPort=%d" % ldap_backend_port + else: + serverport = "" + + setup_file(setup_path("fedorads.inf"), paths.fedoradsinf, {"ROOT": root, "HOSTNAME": hostname, "DNSDOMAIN": names.dnsdomain, @@ -1152,19 +1157,18 @@ def provision_backend(setup_dir=None, message=None, "DOMAINDN": names.domaindn, "LDAPMANAGERDN": names.ldapmanagerdn, "LDAPMANAGERPASS": adminpass, - "SERVERPORT": ""}) + "SERVERPORT": serverport}) - setup_file(setup_path("fedora-partitions.ldif"), paths.fedoradspartitions, + setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions, {"CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, }) - setup_file(setup_path("fedora-partitions.ldif"), paths.fedoradspartitions, - {"CONFIGDN": names.configdn, - "SCHEMADN": names.schemadn, - }) mapping = "schema-map-fedora-ds-1.0" backend_schema = "99_ad.ldif" + + slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf + elif ldap_backend_type == "openldap": attrs = ["linkID", "lDAPDisplayName"] res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs); @@ -1215,14 +1219,26 @@ refint_attributes""" + refint_attributes + "\n"; ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - message("Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri) - + if ldap_backend_port is not None: + server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port + else: + server_port_string = "" + slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema); os.system(schema_command) + message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ( ldap_backend_type) ) + message("Server Role: %s" % serverrole) + message("Hostname: %s" % names.hostname) + message("DNS Domain: %s" % names.dnsdomain) + message("Base DN: %s" % names.domaindn) + message("LDAP admin DN: %s" % names.ldapmanagerdn) + message("LDAP admin password: %s" % adminpass) + message(slapdcommand) + def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. -- cgit From ad823b04dab468379c7b42a8b849bb8a310cfb69 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 8 Apr 2008 14:58:38 +0200 Subject: Remove length arguments, add tests for unixinfo.GidToSid and unixinfo.UidToSid. (This used to be commit cae61e32e5b61a02c2986b74bd1d7e58460b1e80) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 2 +- source4/scripting/python/samba/tests/dcerpc/unix.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 8c1a8bec71..484af9490c 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -30,7 +30,7 @@ class RpcEchoTests(unittest.TestCase): self.assertEquals(2, self.conn.AddOne(1)) def test_echodata(self): - self.assertEquals([1,2,3], self.conn.EchoData(3, [1, 2, 3])) + self.assertEquals([1,2,3], self.conn.EchoData([1, 2, 3])) def test_call(self): self.assertEquals(u"foobar", self.conn.TestCall(u"foobar")) diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py index 99c84c08da..b2577ec898 100644 --- a/source4/scripting/python/samba/tests/dcerpc/unix.py +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -26,5 +26,11 @@ class UnixinfoTests(unittest.TestCase): self.conn = unixinfo.unixinfo("ncalrpc:", get_loadparm()) def test_getpwuid(self): - (count, infos) = self.conn.GetPWUid(1, [0]) - self.assertEquals(1, len(infos)) + infos = self.conn.GetPWUid(range(512)) + self.assertEquals(512, len(infos)) + + def test_gidtosid(self): + self.conn.GidToSid(1000) + + def test_uidtosid(self): + self.conn.UidToSid(1000) -- cgit From ac10ac62c1e9b64280f3566425af08210d57bb04 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 9 Apr 2008 03:51:41 +0200 Subject: Add docstring, PEP8. (This used to be commit f8cac3735c9a19baa313c4b61abee144da303ce1) --- source4/scripting/python/samba/provision.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 80dcd522df..c9cdcdb768 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -264,9 +264,11 @@ def provision_paths_from_lp(lp, dnsdomain): return paths + def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=None, rootdn=None, domaindn=None, configdn=None, schemadn=None, serverdn=None, sitename=None): + """Guess configuration settings to use.""" if hostname is None: hostname = socket.gethostname().split(".")[0].lower() @@ -400,6 +402,7 @@ def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrol return lp + def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, users_gid, wheel_gid): """setup reasonable name mappings for sam names to unix names. @@ -425,6 +428,7 @@ def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid) idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid) + def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, credentials, names, serverrole, ldap_backend=None, @@ -637,6 +641,7 @@ def setup_registry(path, setup_path, session_info, credentials, lp): assert os.path.exists(provision_reg) reg.diff_apply(provision_reg) + def setup_idmapdb(path, setup_path, session_info, credentials, lp): """Setup the idmap database. @@ -656,6 +661,7 @@ def setup_idmapdb(path, setup_path, session_info, credentials, lp): idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) return idmap_ldb + def setup_samdb_rootdse(samdb, setup_path, names): """Setup the SamDB rootdse. @@ -1060,6 +1066,7 @@ def provision(setup_dir, message, session_info, result.samdb = samdb return result + def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, @@ -1081,7 +1088,11 @@ def provision_become_dc(setup_dir=None, domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); -def setup_db_config(setup_path, file, dbdir): +def setup_db_config(setup_path, dbdir): + """Setup a Berkeley database. + + :param setup_path: Setup path function. + :param dbdir: Database directory.""" if not os.path.isdir(os.path.join(dbdir, "bdb-logs")): os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700); if not os.path.isdir(os.path.join(dbdir, "tmp")): @@ -1211,12 +1222,11 @@ refint_attributes""" + refint_attributes + "\n"; setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "user")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "config")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "db", "schema")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "user")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "config")) + setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "schema")) mapping = "schema-map-openldap-2.3" backend_schema = "backend-schema.schema" - ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") if ldap_backend_port is not None: -- cgit From 9d2948f4bd5f196904d27c67bf4f0baf7eaefcb0 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 9 Apr 2008 14:57:57 +1000 Subject: Don't fill in the secrets DB unless we make the entries. Leave filling in (we still initialise it) the secrets DB for the join or vampire code. Andrew Bartlett (This used to be commit c93208c13ce91b334eadf0ea02fa41354e761e97) --- source4/scripting/python/samba/provision.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index c9cdcdb768..7b4fdb772c 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1011,13 +1011,6 @@ def provision(setup_dir, message, session_info, os.makedirs(os.path.join(policy_path, "User"), 0755) if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0755) - secrets_ldb = Ldb(paths.secrets, session_info=session_info, - credentials=credentials, lp=lp) - secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm, - netbiosname=names.netbiosname, domainsid=domainsid, - keytab_path=paths.keytab, samdb_url=paths.samdb, - dns_keytab_path=paths.dns_keytab, dnspass=dnspass, - machinepass=machinepass, dnsdomain=names.dnsdomain) if samdb_fill == FILL_FULL: setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn, @@ -1029,6 +1022,14 @@ def provision(setup_dir, message, session_info, # Only make a zone file on the first DC, it should be replicated with DNS replication if serverrole == "domain controller": + secrets_ldb = Ldb(paths.secrets, session_info=session_info, + credentials=credentials, lp=lp) + secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, realm=names.realm, + netbiosname=names.netbiosname, domainsid=domainsid, + keytab_path=paths.keytab, samdb_url=paths.samdb, + dns_keytab_path=paths.dns_keytab, dnspass=dnspass, + machinepass=machinepass, dnsdomain=names.dnsdomain) + samdb = SamDB(paths.samdb, session_info=session_info, credentials=credentials, lp=lp) -- cgit From b202b6e7d45cebd9b34c8d319e75f423291b30a0 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 9 Apr 2008 15:32:49 +1000 Subject: Fix up provision to specify SERVERDN in more places. Andrew Bartlett (This used to be commit d01d542502f25d6c731204ecb3d33720a1706581) --- source4/scripting/python/samba/provision.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 7b4fdb772c..ff76681c13 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -690,6 +690,7 @@ def setup_self_join(samdb, names, "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, "DOMAINDN": names.domaindn, + "SERVERDN": names.serverdn, "INVOCATIONID": invocationid, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": names.sitename, @@ -773,6 +774,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": names.sitename, "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn, "POLICYGUID": policyguid, "DOMAINDN": names.domaindn, "DOMAINGUID_MOD": domainguid_mod, @@ -803,6 +805,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": names.sitename, "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn }) message("Setting up sam.ldb Samba4 schema") @@ -821,6 +824,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "DOMAIN": names.domain, "SCHEMADN": names.schemadn, "DOMAINDN": names.domaindn, + "SERVERDN": names.serverdn }) message("Setting up display specifiers") @@ -845,6 +849,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": names.sitename, "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn }) if fill == FILL_FULL: -- cgit From ad8e3e41923e20d401294eccd4da028e0f40c904 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 10 Apr 2008 05:23:17 +0200 Subject: Add infrastructure for returning ProvisionResult in C provision code. (This used to be commit 98c3d34eb233be284e8c8994cca337be25c72968) --- source4/scripting/python/samba/provision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index c9cdcdb768..ccf67a0b4a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1082,7 +1082,7 @@ def provision_become_dc(setup_dir=None, """print a message if quiet is not set.""" print text - provision(setup_dir, message, system_session(), None, + return provision(setup_dir, message, system_session(), None, smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn, domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); -- cgit From 393007315d56d72cd4ebccc204da703b27eb968b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 11 Apr 2008 19:04:43 +1000 Subject: Far less cryptic traceback when you have an existing smb.conf When the user has an existing smb.conf, but no [netlogon] or [sysvol] share, the provision script would trigger a traceback. While we still need to abort in this situation, we do so now with a useful error. Andrew Bartlett (This used to be commit 10a8b7ea487f9725f69b02c4dd9cf5e1f67a23ab) --- source4/scripting/python/samba/provision.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 16b1eb2156..4f264b6fc9 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -87,6 +87,7 @@ class ProvisionNames: self.domain = None self.hostname = None self.sitename = None + self.smbconf = None class ProvisionResult: def __init__(self): @@ -262,6 +263,8 @@ def provision_paths_from_lp(lp, dnsdomain): paths.netlogon = lp.get("path", "netlogon") + paths.smbconf = lp.configfile() + return paths @@ -1009,12 +1012,24 @@ def provision(setup_dir, message, session_info, ldap_backend_type=ldap_backend_type) if lp.get("server role") == "domain controller": - policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies", - "{" + policyguid + "}") - os.makedirs(policy_path, 0755) - os.makedirs(os.path.join(policy_path, "Machine"), 0755) - os.makedirs(os.path.join(policy_path, "User"), 0755) - if not os.path.isdir(paths.netlogon): + if paths.netlogon is None: + message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.") + message("Please either remove %s or see the template at %s" % + ( paths.smbconf, setup_path("provision.smb.conf.dc"))) + assert(paths.netlogon is not None) + + if paths.sysvol is None: + message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.") + message("Please either remove %s or see the template at %s" % + (paths.smbconf, setup_path("provision.smb.conf.dc"))) + assert(paths.sysvol is not None) + + policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies", + "{" + policyguid + "}") + os.makedirs(policy_path, 0755) + os.makedirs(os.path.join(policy_path, "Machine"), 0755) + os.makedirs(os.path.join(policy_path, "User"), 0755) + if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0755) if samdb_fill == FILL_FULL: -- cgit From e44f0e7b75a15e61427a6520999d0d79b78e9d2a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 11 Apr 2008 19:33:52 +1000 Subject: Don't reopen the sam.ldb again Andrew Bartlett (This used to be commit b51b8a2d846284de4dff736fc18cf747c188de96) --- source4/scripting/python/samba/provision.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 4f264b6fc9..a8d188e7a3 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -741,8 +741,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, return samdb message("Pre-loading the Samba 4 and AD schema") - samdb = SamDB(path, session_info=session_info, - credentials=credentials, lp=lp) samdb.set_domain_sid(domainsid) if serverrole == "domain controller": samdb.set_invocation_id(invocationid) -- cgit From 5a37b3fc5d42beffaf4bdca70b1f0c5f80f92280 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 14 Apr 2008 11:51:02 +0200 Subject: Fix newuser and setpassword scripts, and port to idmap. The new idmap world does not use the unixUser any more, so we need to set up the entry (if wanted) in the idmap database. Users without a backing unix user will get an allocated uid by idmap later. Andrew Bartlett (This used to be commit 8bd8bc1475ddf22d4702dcd17028a9043a5e629f) --- source4/scripting/python/samba/idmap.py | 7 +++++++ source4/scripting/python/samba/samdb.py | 28 +++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py index 355565968a..16efcd0470 100644 --- a/source4/scripting/python/samba/idmap.py +++ b/source4/scripting/python/samba/idmap.py @@ -21,6 +21,7 @@ """Convenience functions for using the idmap database.""" import samba +import misc import ldb class IDmapDB(samba.Ldb): @@ -37,11 +38,17 @@ class IDmapDB(samba.Ldb): :param url: URL of the database. """ + self.lp = lp + super(IDmapDB, self).__init__(session_info=session_info, credentials=credentials, modules_dir=modules_dir, lp=lp) if url: self.connect(url) + else: + self.connect(lp.get("idmap database")) + def connect(self, url): + super(IDmapDB, self).connect(misc.private_path(self.lp, url)) def setup_name_mapping(self, sid, type, unixid): """Setup a mapping between a sam name and a unix name. diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index bc3eef7879..198d1e9f5c 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -25,20 +25,29 @@ import samba import misc import ldb +from samba.idmap import IDmapDB +import pwd class SamDB(samba.Ldb): """The SAM database.""" + def __init__(self, url=None, session_info=None, credentials=None, modules_dir=None, lp=None): """Open the Sam Database. :param url: URL of the database. """ + self.lp = lp super(SamDB, self).__init__(session_info=session_info, credentials=credentials, modules_dir=modules_dir, lp=lp) assert misc.dsdb_set_global_schema(self) == 0 if url: self.connect(url) + else: + self.connect(lp.get("sam database")) + + def connect(self, url): + super(SamDB, self).connect(misc.private_path(self.lp, url)) def add_foreign(self, domaindn, sid, desc): """Add a foreign security principle.""" @@ -101,10 +110,27 @@ userAccountControl: %u # now the real work self.add({"dn": user_dn, "sAMAccountName": username, - "unixName": unixname, "sambaPassword": password, "objectClass": "user"}) + res = self.search(user_dn, scope=ldb.SCOPE_BASE, + expression="objectclass=*", + attrs=["objectSid"]) + assert(len(res) == 1) + user_sid = self.schema_format_value("objectSid", res[0]["objectSid"][0]) + + + try: + idmap = IDmapDB(lp=self.lp) + + user = pwd.getpwnam(unixname) + # setup ID mapping for this UID + + idmap.setup_name_mapping(user_sid, idmap.TYPE_UID, user[2]) + + except KeyError: + pass + # modify the userAccountControl to remove the disabled bit self.enable_account(user_dn) self.transaction_commit() -- cgit From 02f3695897dddb013fc1268a4f1a852cd4a3465e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Apr 2008 18:30:07 +0200 Subject: Add convenience TestCase class for testing RPC interfaces. (This used to be commit 2f19f981449bf6f4d29f231259817c8b66104a9b) --- source4/scripting/python/samba/tests/__init__.py | 7 +++++++ source4/scripting/python/samba/tests/dcerpc/registry.py | 9 ++++----- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index c8673d3fae..ceb7dd23f3 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -90,3 +90,10 @@ def get_loadparm(): lp = param.LoadParm() lp.load(os.getenv("SMB_CONF_PATH")) return lp + +class RpcInterfaceTestCase(unittest.TestCase): + def get_loadparm(self): + return get_loadparm() + + def get_credentials(self): + return None diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index 147acc5098..1afdc582a7 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -18,14 +18,13 @@ # import winreg -from param import LoadParm import unittest -from samba.tests import get_loadparm +from samba.tests import RpcInterfaceTestCase -class WinregTests(unittest.TestCase): +class WinregTests(RpcInterfaceTestCase): def setUp(self): - lp_ctx = get_loadparm() - self.conn = winreg.winreg("ncalrpc:", lp_ctx) + self.conn = winreg.winreg("ncalrpc:", self.get_loadparm(), + self.get_credentials()) def get_hklm(self): return self.conn.OpenHKLM(None, -- cgit From c1d9167fbcc5df9da4f603084ad732915c68c0c0 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Apr 2008 19:01:32 +0200 Subject: Also look in the environment for smb.conf path. (This used to be commit 8be7d93735a357a3b73a1c4413d6fd9ec09b7555) --- source4/scripting/python/samba/getopt.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 82cb004b62..7ec684a9d6 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -35,12 +35,14 @@ class SambaOptions(optparse.OptionGroup): self._configfile = arg def get_loadparm(self): - import param + import os, param lp = param.LoadParm() - if self._configfile is None: - lp.load_default() - else: + if self._configfile is not None: lp.load(self._configfile) + elif os.getenv("SMB_CONF_PATH") is not None: + lp.load(os.getenv("SMB_CONF_PATH")) + else: + lp.load_default() return lp class VersionOptions(optparse.OptionGroup): -- cgit From 1bcbc4afcf2f9984081652c1fbe50d329c86b3b5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Apr 2008 19:13:41 +0200 Subject: Allow command line options in the subunitrun script. (This used to be commit 524ec0796efebd48e7b5b2eb5fcc92ecc13c0071) --- source4/scripting/python/samba/tests/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index ceb7dd23f3..e29b4a87d5 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -85,15 +85,13 @@ class LdbExtensionTests(TestCaseInTempDir): os.unlink(path) -def get_loadparm(): - import param - lp = param.LoadParm() - lp.load(os.getenv("SMB_CONF_PATH")) - return lp +cmdline_loadparm = None +cmdline_credentials = None class RpcInterfaceTestCase(unittest.TestCase): def get_loadparm(self): - return get_loadparm() + assert cmdline_loadparm is not None + return cmdline_loadparm def get_credentials(self): - return None + return cmdline_credentials -- cgit From 2cdfaedee203a726bddfb46fb10d9604de32a05f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Apr 2008 19:20:43 +0200 Subject: Make sure credentials are specified when running the Python winreg RPC tests. (This used to be commit 280339e3d126f5c72dc271051b72839fde0c5c9f) --- source4/scripting/python/samba/tests/dcerpc/registry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index 1afdc582a7..05ac7c66ee 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -23,8 +23,8 @@ from samba.tests import RpcInterfaceTestCase class WinregTests(RpcInterfaceTestCase): def setUp(self): - self.conn = winreg.winreg("ncalrpc:", self.get_loadparm(), - self.get_credentials()) + lp = self.get_loadparm() + self.conn = winreg.winreg("ncalrpc:", lp, self.get_credentials()) def get_hklm(self): return self.conn.OpenHKLM(None, -- cgit From 1b5f32128d1867829647a4e1f20b6e8363444f66 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 14 Apr 2008 23:28:14 +0200 Subject: Use RpcInterfaceTestCase everywhere. (This used to be commit 799095b4e567f4495adf7d1d7bcb81dda6782959) --- source4/scripting/python/samba/tests/dcerpc/registry.py | 4 ++-- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 7 +++---- source4/scripting/python/samba/tests/dcerpc/sam.py | 7 +++---- source4/scripting/python/samba/tests/dcerpc/unix.py | 7 +++---- source4/scripting/python/samba/tests/provision.py | 2 +- source4/scripting/python/samba/tests/samdb.py | 4 ++-- 6 files changed, 14 insertions(+), 17 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index 05ac7c66ee..1afdc582a7 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -23,8 +23,8 @@ from samba.tests import RpcInterfaceTestCase class WinregTests(RpcInterfaceTestCase): def setUp(self): - lp = self.get_loadparm() - self.conn = winreg.winreg("ncalrpc:", lp, self.get_credentials()) + self.conn = winreg.winreg("ncalrpc:", self.get_loadparm(), + self.get_credentials()) def get_hklm(self): return self.conn.OpenHKLM(None, diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 484af9490c..6c43632d97 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -19,12 +19,11 @@ import echo import unittest -from samba.tests import get_loadparm +from samba.tests import RpcInterfaceTestCase -class RpcEchoTests(unittest.TestCase): +class RpcEchoTests(RpcInterfaceTestCase): def setUp(self): - lp_ctx = get_loadparm() - self.conn = echo.rpcecho("ncalrpc:", lp_ctx) + self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm()) def test_addone(self): self.assertEquals(2, self.conn.AddOne(1)) diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py index 96348f2f69..8ef12dad86 100644 --- a/source4/scripting/python/samba/tests/dcerpc/sam.py +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -18,12 +18,11 @@ # import samr -import unittest -from samba.tests import get_loadparm +from samba.tests import RpcInterfaceTestCase -class SamrTests(unittest.TestCase): +class SamrTests(RpcInterfaceTestCase): def setUp(self): - self.conn = samr.samr("ncalrpc:", get_loadparm()) + self.conn = samr.samr("ncalrpc:", self.get_loadparm()) def test_connect5(self): (level, info, handle) = self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py index b2577ec898..bfddfdc7ec 100644 --- a/source4/scripting/python/samba/tests/dcerpc/unix.py +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -18,12 +18,11 @@ # import unixinfo -import unittest -from samba.tests import get_loadparm +from samba.tests import RpcInterfaceTestCase -class UnixinfoTests(unittest.TestCase): +class UnixinfoTests(RpcInterfaceTestCase): def setUp(self): - self.conn = unixinfo.unixinfo("ncalrpc:", get_loadparm()) + self.conn = unixinfo.unixinfo("ncalrpc:", self.get_loadparm()) def test_getpwuid(self): infos = self.conn.GetPWUid(range(512)) diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index 514582cbe4..b9e0e16d3c 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -24,7 +24,7 @@ from ldb import Dn import param import unittest -lp = samba.tests.get_loadparm() +lp = samba.tests.cmdline_loadparm setup_dir = "setup" def setup_path(file): diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 3745dba6fc..0e175bf936 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -21,7 +21,7 @@ from credentials import Credentials import os from samba.provision import setup_samdb from samba.samdb import SamDB -from samba.tests import get_loadparm, TestCaseInTempDir +from samba.tests import cmdline_loadparm, TestCaseInTempDir import security from unittest import TestCase import uuid @@ -43,7 +43,7 @@ class SamDBTestCase(TestCaseInTempDir): hostguid = uuid.random() path = os.path.join(self.tempdir, "samdb.ldb") self.samdb = setup_samdb(path, setup_path, system_session(), creds, - get_loadparm(), schemadn, configdn, + cmdline_loadparm, schemadn, configdn, self.domaindn, "example.com", "EXAMPLE.COM", "FOO", lambda x: None, "foo", domaindn, False, domainsid, "# no aci", domainguid, -- cgit From fd52fe86169ddc0adda2d1cd97215c58d06f93c4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 15 Apr 2008 14:32:13 +0200 Subject: Fix pointers when pushing strings to python during pidl generation. (This used to be commit ca72187b3e71a037780d42a57e46b60e75f724f6) --- source4/scripting/python/samba/tests/dcerpc/unix.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py index bfddfdc7ec..43978ac9dc 100644 --- a/source4/scripting/python/samba/tests/dcerpc/unix.py +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -27,6 +27,8 @@ class UnixinfoTests(RpcInterfaceTestCase): def test_getpwuid(self): infos = self.conn.GetPWUid(range(512)) self.assertEquals(512, len(infos)) + self.assertEquals("", infos[0].shell) + self.assertEquals("", infos[0].homedir) def test_gidtosid(self): self.conn.GidToSid(1000) -- cgit From f8f4856ab7330db865d1a35abff3ccaf2ac277ba Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 15 Apr 2008 15:52:52 +0200 Subject: Fix provision-backend script Andrew Bartlett (This used to be commit ee6e4f8da229ddeca856a6db94236367aae06f63) --- source4/scripting/python/samba/provision.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index a8d188e7a3..45965a2429 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1166,6 +1166,7 @@ def provision_backend(setup_dir=None, message=None, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": DEFAULTSITE, "CONFIGDN": names.configdn, + "SERVERDN": names.serverdn }) setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"), @@ -1241,9 +1242,9 @@ refint_attributes""" + refint_attributes + "\n"; setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "user")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "config")) - setup_db_config(setup_path, file, os.path.join(paths.ldapdir, "schema")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "user")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "config")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "schema")) mapping = "schema-map-openldap-2.3" backend_schema = "backend-schema.schema" -- cgit From 2ddd23a8754258b7322f37a0e0b97587b23f338b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 15 Apr 2008 17:10:47 +0200 Subject: Re-add 'db' subdirectory for LDAP backend provision Andrew Bartlett (This used to be commit 19890c0d15adf4f099365f276a4bfdd3f4de52b6) --- source4/scripting/python/samba/provision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 45965a2429..0e8840646c 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1242,9 +1242,9 @@ refint_attributes""" + refint_attributes + "\n"; setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) - setup_db_config(setup_path, os.path.join(paths.ldapdir, "user")) - setup_db_config(setup_path, os.path.join(paths.ldapdir, "config")) - setup_db_config(setup_path, os.path.join(paths.ldapdir, "schema")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "user"))) + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "config"))) + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "schema"))) mapping = "schema-map-openldap-2.3" backend_schema = "backend-schema.schema" -- cgit From 4d8f3f190215edcdbeb1725cccdc962dc68cc1a0 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 17 Apr 2008 12:03:49 +0200 Subject: Fix the expectations on the unixinfo test. Andrew Bartlett (This used to be commit 0df2b3e0b56007850cf83cfdcdb45ca29e162d34) --- source4/scripting/python/samba/tests/dcerpc/unix.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py index 43978ac9dc..78a987cedd 100644 --- a/source4/scripting/python/samba/tests/dcerpc/unix.py +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -27,8 +27,8 @@ class UnixinfoTests(RpcInterfaceTestCase): def test_getpwuid(self): infos = self.conn.GetPWUid(range(512)) self.assertEquals(512, len(infos)) - self.assertEquals("", infos[0].shell) - self.assertEquals("", infos[0].homedir) + self.assertEquals("/bin/false", infos[0].shell) + self.assertTrue(isinstance(infos[0].homedir, unicode)) def test_gidtosid(self): self.conn.GidToSid(1000) -- cgit From 5319d9620b9ef68b3687d76aeaba5fa5d5c57a18 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 11 May 2008 03:31:26 +0200 Subject: Use consistent function names with the standard Python uuid module that is available in >= 2.4. (This used to be commit 60d458e3195eef6baf655fee0da7c3f68517e8e6) --- source4/scripting/python/samba/provision.py | 4 ++-- source4/scripting/python/samba/tests/samdb.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0e8840646c..60fa22e6c4 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -910,7 +910,7 @@ def provision(setup_dir, message, session_info, domainsid = security.Sid(domainsid) if policyguid is None: - policyguid = uuid.random() + policyguid = uuid.uuid4() if adminpass is None: adminpass = misc.random_password(12) if krbtgtpass is None: @@ -960,7 +960,7 @@ def provision(setup_dir, message, session_info, assert serverrole in ("domain controller", "member server", "standalone") if invocationid is None and serverrole == "domain controller": - invocationid = uuid.random() + invocationid = uuid.uuid4() if not os.path.exists(paths.private_dir): os.mkdir(paths.private_dir) diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 0e175bf936..9da3358527 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -29,18 +29,18 @@ import uuid class SamDBTestCase(TestCaseInTempDir): def setUp(self): super(SamDBTestCase, self).setUp() - invocationid = uuid.random() + invocationid = uuid.uuid4() domaindn = "DC=COM,DC=EXAMPLE" self.domaindn = domaindn configdn = "CN=Configuration," + domaindn schemadn = "CN=Schema," + configdn - domainguid = uuid.random() - policyguid = uuid.random() + domainguid = uuid.uuid4() + policyguid = uuid.uuid4() setup_path = lambda x: os.path.join("setup", x) creds = Credentials() creds.set_anonymous() domainsid = security.random_sid() - hostguid = uuid.random() + hostguid = uuid.uuid4() path = os.path.join(self.tempdir, "samdb.ldb") self.samdb = setup_samdb(path, setup_path, system_session(), creds, cmdline_loadparm, schemadn, configdn, -- cgit From 251f6bd99159337b24b8aa8298a5c98de153bce0 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 11 May 2008 04:36:37 +0200 Subject: make sure to always use string version of uuid rather than object. (This used to be commit bcd5fc7dc9899deb9fa84fdeeb21ed2ddb921308) --- source4/scripting/python/samba/provision.py | 5 +++-- source4/scripting/python/samba/tests/samdb.py | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 60fa22e6c4..ad8eb8bffd 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -689,6 +689,7 @@ def setup_self_join(samdb, names, domainsid, invocationid, setup_path, policyguid): """Join a host to its own domain.""" + assert isinstance(invocationid, str) setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, @@ -910,7 +911,7 @@ def provision(setup_dir, message, session_info, domainsid = security.Sid(domainsid) if policyguid is None: - policyguid = uuid.uuid4() + policyguid = str(uuid.uuid4()) if adminpass is None: adminpass = misc.random_password(12) if krbtgtpass is None: @@ -960,7 +961,7 @@ def provision(setup_dir, message, session_info, assert serverrole in ("domain controller", "member server", "standalone") if invocationid is None and serverrole == "domain controller": - invocationid = uuid.uuid4() + invocationid = str(uuid.uuid4()) if not os.path.exists(paths.private_dir): os.mkdir(paths.private_dir) diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 9da3358527..0d4f7bde0e 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -29,18 +29,18 @@ import uuid class SamDBTestCase(TestCaseInTempDir): def setUp(self): super(SamDBTestCase, self).setUp() - invocationid = uuid.uuid4() + invocationid = str(uuid.uuid4()) domaindn = "DC=COM,DC=EXAMPLE" self.domaindn = domaindn configdn = "CN=Configuration," + domaindn schemadn = "CN=Schema," + configdn - domainguid = uuid.uuid4() - policyguid = uuid.uuid4() + domainguid = str(uuid.uuid4()) + policyguid = str(uuid.uuid4()) setup_path = lambda x: os.path.join("setup", x) creds = Credentials() creds.set_anonymous() domainsid = security.random_sid() - hostguid = uuid.uuid4() + hostguid = str(uuid.uuid4()) path = os.path.join(self.tempdir, "samdb.ldb") self.samdb = setup_samdb(path, setup_path, system_session(), creds, cmdline_loadparm, schemadn, configdn, -- cgit From 25ea110c3814abcb824adb3619a44622ba8d2936 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Sat, 17 May 2008 23:24:48 -0500 Subject: provision: Create instructions for enabling DNS GSS-TSIG updates. Added code to the python provisioning to create the named.conf file that was previously generated by the EJS provisioning. Updated the named.conf template to provide the additional details necessary to get things working. (This used to be commit 0b7a6bfcba1b906dc4d461882b4c3fe3c91c44e0) --- source4/scripting/python/samba/provision.py | 32 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ad8eb8bffd..4818a79f00 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -236,6 +236,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb") paths.templates = os.path.join(paths.private_dir, "templates.ldb") paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") + paths.namedconf = os.path.join(paths.private_dir, "named.conf") paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") paths.phpldapadminconfig = os.path.join(paths.private_dir, @@ -1059,12 +1060,14 @@ def provision(setup_dir, message, session_info, scope=SCOPE_SUBTREE) assert isinstance(hostguid, str) - create_zone_file(paths.dns, setup_path, samdb, + create_zone_file(paths.dns, paths.namedconf, setup_path, samdb, hostname=names.hostname, hostip=hostip, hostip6=hostip6, dnsdomain=names.dnsdomain, domaindn=names.domaindn, dnspass=dnspass, realm=names.realm, - domainguid=domainguid, hostguid=hostguid) + domainguid=domainguid, hostguid=hostguid, + private_dir=paths.private_dir, keytab_name=paths.dns_keytab) message("Please install the zone located in %s into your DNS server" % paths.dns) + message("See %s if you want to use secure GSS-TSIG updates" % paths.namedconf) create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) @@ -1281,12 +1284,18 @@ def create_phpldapadmin_config(path, setup_path, ldapi_uri): {"S4_LDAPI_URI": ldapi_uri}) -def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, - hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid): +def create_zone_file(path_zone, path_conf, setup_path, samdb, dnsdomain, domaindn, + hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid, + private_dir, keytab_name): """Write out a DNS zone file, from the info in the current database. + + Also writes a file with stubs appropriate for a DNS configuration file + (including GSS-TSIG configuration), and details as to some of the other + configuration changes that may be necessary. - :param path: Path of the new file. - :param setup_path": Setup path function. + :param path_zone: Path of the new zone file. + :param path_conf: Path of the config stubs file. + :param setup_path: Setup path function. :param samdb: SamDB object :param dnsdomain: DNS Domain name :param domaindn: DN of the Domain @@ -1307,7 +1316,7 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, hostip6_base_line = " IN AAAA " + hostip6 hostip6_host_line = hostname + " IN AAAA " + hostip6 - setup_file(setup_path("provision.zone"), path, { + setup_file(setup_path("provision.zone"), path_zone, { "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": hostname, "DNSDOMAIN": dnsdomain, @@ -1321,6 +1330,15 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, "HOSTIP6_HOST_LINE": hostip6_host_line, }) + setup_file(setup_path("named.conf"), path_conf, { + "DNSDOMAIN": dnsdomain, + "REALM": realm, + "REALM_WC": "*." + ".".join(realm.split(".")[1:]), + "HOSTNAME": hostname, + "DNS_KEYTAB": keytab_name, + "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name), + }) + def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): """Load schema for the SamDB. -- cgit From 49706ab19bd3ffd6125639e6a7753b2350cf54e1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 21 May 2008 23:59:34 +0200 Subject: Move more modules inside of the samba package. (This used to be commit 9b39e99f48266a54ed0b8890c2efde218b4b118a) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 2 +- source4/scripting/python/samba/tests/dcerpc/unix.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 6c43632d97..281d5b4cdb 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -import echo +from dcerpc import echo import unittest from samba.tests import RpcInterfaceTestCase diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py index 78a987cedd..b4b2e0aeda 100644 --- a/source4/scripting/python/samba/tests/dcerpc/unix.py +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -import unixinfo +from dcerpc import unixinfo from samba.tests import RpcInterfaceTestCase class UnixinfoTests(RpcInterfaceTestCase): -- cgit From 059c012656e6369f417c11f9984ddb1925782394 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 00:56:36 +0200 Subject: Fix dependencies and imports. (This used to be commit 37ef86f8de9039b8226b190254d842e92b5faad7) --- source4/scripting/python/samba/tests/dcerpc/registry.py | 2 +- source4/scripting/python/samba/tests/dcerpc/sam.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index 1afdc582a7..0a1b5ecd10 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -import winreg +from dcerpc import winreg import unittest from samba.tests import RpcInterfaceTestCase diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py index 8ef12dad86..50871114c0 100644 --- a/source4/scripting/python/samba/tests/dcerpc/sam.py +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -import samr +from dcerpc import samr from samba.tests import RpcInterfaceTestCase class SamrTests(RpcInterfaceTestCase): -- cgit From 6e14d44d27d208bb22e6345fff8785c74a435a59 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 01:50:38 +0200 Subject: Make sure the default ldb modules dir gets initialized. (This used to be commit 937456c69d23ece85bdb7415f52d722c2aa6b6b5) --- source4/scripting/python/samba/__init__.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index b9d81c6c3c..29afdb931d 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -33,6 +33,8 @@ if _in_source_tree(): srcdir = "%s/../../.." % os.path.dirname(__file__) sys.path.append("%s/bin/python" % srcdir) default_ldb_modules_dir = "%s/bin/modules/ldb" % srcdir +else: + default_ldb_modules_dir = None import ldb -- cgit From d77745e6920038f3b6c7c25fa6cd6549e1c24d17 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 02:21:25 +0200 Subject: Move DCE/RPC python bindings into samba package. (This used to be commit 8dafd4ce40b7348fd5f2b1f2f5d2106ef4cc0dd1) --- source4/scripting/python/samba/tests/dcerpc/registry.py | 2 +- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 2 +- source4/scripting/python/samba/tests/dcerpc/sam.py | 2 +- source4/scripting/python/samba/tests/dcerpc/unix.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index 0a1b5ecd10..81133ff641 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -from dcerpc import winreg +from samba.dcerpc import winreg import unittest from samba.tests import RpcInterfaceTestCase diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 281d5b4cdb..3b37f8a9bc 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -from dcerpc import echo +from samba.dcerpc import echo import unittest from samba.tests import RpcInterfaceTestCase diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py index 50871114c0..a6816153c0 100644 --- a/source4/scripting/python/samba/tests/dcerpc/sam.py +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -from dcerpc import samr +from samba.dcerpc import samr from samba.tests import RpcInterfaceTestCase class SamrTests(RpcInterfaceTestCase): diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py index b4b2e0aeda..aa47b71b16 100644 --- a/source4/scripting/python/samba/tests/dcerpc/unix.py +++ b/source4/scripting/python/samba/tests/dcerpc/unix.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -from dcerpc import unixinfo +from samba.dcerpc import unixinfo from samba.tests import RpcInterfaceTestCase class UnixinfoTests(RpcInterfaceTestCase): -- cgit From d8459e3e1c87577768a2a250f701f14a64c22541 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 03:09:40 +0200 Subject: Fix import in provision test. (This used to be commit 96501be38da947f02ad57217e0bc23f7a66d36f9) --- source4/scripting/python/samba/tests/provision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index b9e0e16d3c..76c10145f0 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -21,7 +21,7 @@ import os from samba.provision import setup_secretsdb, secretsdb_become_dc, findnss import samba.tests from ldb import Dn -import param +from samba import param import unittest lp = samba.tests.cmdline_loadparm -- cgit From bf3f3af92677bce8f03b0dd2be552d6c8c730ca1 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Wed, 21 May 2008 18:12:36 -0500 Subject: provision: Generate krb5.conf template separate from named.conf template. (This used to be commit ebf130e9e57b640129cf0d05dbd7d210b71ea371) --- source4/scripting/python/samba/provision.py | 74 ++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 22 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 4818a79f00..69c7e8846d 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -237,6 +237,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.templates = os.path.join(paths.private_dir, "templates.ldb") paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") paths.namedconf = os.path.join(paths.private_dir, "named.conf") + paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf") paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") paths.phpldapadminconfig = os.path.join(paths.private_dir, @@ -1059,16 +1060,23 @@ def provision(setup_dir, message, session_info, expression="(&(objectClass=computer)(cn=%s))" % names.hostname, scope=SCOPE_SUBTREE) assert isinstance(hostguid, str) - - create_zone_file(paths.dns, paths.namedconf, setup_path, samdb, - hostname=names.hostname, hostip=hostip, - hostip6=hostip6, dnsdomain=names.dnsdomain, - domaindn=names.domaindn, dnspass=dnspass, realm=names.realm, - domainguid=domainguid, hostguid=hostguid, - private_dir=paths.private_dir, keytab_name=paths.dns_keytab) + + create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain, + domaindn=names.domaindn, hostip=hostip, + hostip6=hostip6, hostname=names.hostname, + dnspass=dnspass, realm=names.realm, + domainguid=domainguid, hostguid=hostguid) message("Please install the zone located in %s into your DNS server" % paths.dns) - message("See %s if you want to use secure GSS-TSIG updates" % paths.namedconf) - + + create_named_conf(paths.namedconf, setup_path, realm=names.realm, + dnsdomain=names.dnsdomain, private_dir=paths.private_dir, + keytab_name=paths.dns_keytab) + message("See %s for example configuration statements for secure GSS-TSIG updates" % paths.namedconf) + + create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain, + hostname=names.hostname, realm=names.realm) + message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf) + create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) @@ -1284,19 +1292,12 @@ def create_phpldapadmin_config(path, setup_path, ldapi_uri): {"S4_LDAPI_URI": ldapi_uri}) -def create_zone_file(path_zone, path_conf, setup_path, samdb, dnsdomain, domaindn, - hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid, - private_dir, keytab_name): +def create_zone_file(path, setup_path, dnsdomain, domaindn, + hostip, hostip6, hostname, dnspass, realm, domainguid, hostguid): """Write out a DNS zone file, from the info in the current database. - Also writes a file with stubs appropriate for a DNS configuration file - (including GSS-TSIG configuration), and details as to some of the other - configuration changes that may be necessary. - - :param path_zone: Path of the new zone file. - :param path_conf: Path of the config stubs file. + :param path: Path of the new zone 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 IPv4 IP @@ -1316,7 +1317,7 @@ def create_zone_file(path_zone, path_conf, setup_path, samdb, dnsdomain, domaind hostip6_base_line = " IN AAAA " + hostip6 hostip6_host_line = hostname + " IN AAAA " + hostip6 - setup_file(setup_path("provision.zone"), path_zone, { + setup_file(setup_path("provision.zone"), path, { "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": hostname, "DNSDOMAIN": dnsdomain, @@ -1330,15 +1331,44 @@ def create_zone_file(path_zone, path_conf, setup_path, samdb, dnsdomain, domaind "HOSTIP6_HOST_LINE": hostip6_host_line, }) - setup_file(setup_path("named.conf"), path_conf, { +def create_named_conf(path, setup_path, realm, dnsdomain, + private_dir, keytab_name): + """Write out a file containing zone statements suitable for inclusion in a + named.conf file (including GSS-TSIG configuration). + + :param path: Path of the new named.conf file. + :param setup_path: Setup path function. + :param realm: Realm name + :param dnsdomain: DNS Domain name + :param private_dir: Path to private directory + :param keytab_name: File name of DNS keytab file + """ + + setup_file(setup_path("named.conf"), path, { "DNSDOMAIN": dnsdomain, "REALM": realm, "REALM_WC": "*." + ".".join(realm.split(".")[1:]), - "HOSTNAME": hostname, "DNS_KEYTAB": keytab_name, "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name), }) +def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): + """Write out a file containing zone statements suitable for inclusion in a + named.conf file (including GSS-TSIG configuration). + + :param path: Path of the new named.conf file. + :param setup_path: Setup path function. + :param dnsdomain: DNS Domain name + :param hostname: Local hostname + :param realm: Realm name + """ + + setup_file(setup_path("krb5.conf"), path, { + "DNSDOMAIN": dnsdomain, + "HOSTNAME": hostname, + "REALM": realm, + }) + def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): """Load schema for the SamDB. -- 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/__init__.py | 2 ++ source4/scripting/python/samba/idmap.py | 2 ++ source4/scripting/python/samba/provision.py | 2 ++ source4/scripting/python/samba/samba3.py | 2 ++ source4/scripting/python/samba/samdb.py | 2 ++ source4/scripting/python/samba/upgrade.py | 2 ++ 6 files changed, 12 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 29afdb931d..c7d71d3747 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -20,6 +20,8 @@ # along with this program. If not, see . # +__docformat__ = "restructuredText" + import os def _in_source_tree(): diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py index 16efcd0470..755ec52c7b 100644 --- a/source4/scripting/python/samba/idmap.py +++ b/source4/scripting/python/samba/idmap.py @@ -20,6 +20,8 @@ """Convenience functions for using the idmap database.""" +__docformat__ = "restructuredText" + import samba import misc import ldb diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 69c7e8846d..68b43eff40 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -43,6 +43,8 @@ from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ """Functions for setting up a Samba configuration.""" +__docformat__ = "restructuredText" + DEFAULTSITE = "Default-First-Site-Name" class InvalidNetbiosName(Exception): 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 diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 198d1e9f5c..6465f49519 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -28,6 +28,8 @@ import ldb from samba.idmap import IDmapDB import pwd +__docformat__ = "restructuredText" + class SamDB(samba.Ldb): """The SAM database.""" diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index f40f2cffe7..0c83604e82 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -7,6 +7,8 @@ """Support code for upgrading from Samba 3 to Samba 4.""" +__docformat__ = "restructuredText" + from provision import findnss, provision, FILL_DRS import grp import ldb -- 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/getopt.py | 15 +++++++++++++++ source4/scripting/python/samba/samba3.py | 3 +++ 2 files changed, 18 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 7ec684a9d6..9ecb66e21c 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -17,10 +17,15 @@ # along with this program. If not, see . # +"""Support for parsing Samba-related command-line options.""" + import optparse from credentials import Credentials, AUTO_USE_KERBEROS, DONT_USE_KERBEROS, MUST_USE_KERBEROS +__docformat__ = "restructuredText" + class SambaOptions(optparse.OptionGroup): + """General Samba-related command line options.""" def __init__(self, parser): optparse.OptionGroup.__init__(self, parser, "Samba Common Options") self.add_option("-s", "--configfile", action="callback", @@ -29,12 +34,14 @@ class SambaOptions(optparse.OptionGroup): self._configfile = None def get_loadparm_path(self): + """Return the path to the smb.conf file specified on the command line. """ return self._configfile def _load_configfile(self, option, opt_str, arg, parser): self._configfile = arg def get_loadparm(self): + """Return a loadparm object with data specified on the command line. """ import os, param lp = param.LoadParm() if self._configfile is not None: @@ -45,12 +52,15 @@ class SambaOptions(optparse.OptionGroup): lp.load_default() return lp + class VersionOptions(optparse.OptionGroup): + """Command line option for printing Samba version.""" def __init__(self, parser): optparse.OptionGroup.__init__(self, parser, "Version Options") class CredentialsOptions(optparse.OptionGroup): + """Command line options for specifying credentials.""" def __init__(self, parser): self.no_pass = False optparse.OptionGroup.__init__(self, parser, "Credentials Options") @@ -91,6 +101,11 @@ class CredentialsOptions(optparse.OptionGroup): self.creds.set_bind_dn(arg) def get_credentials(self, lp): + """Obtain the credentials set on the command-line. + + :param lp: Loadparm object to use. + :return: Credentials object + """ self.creds.guess(lp) if not self.no_pass: self.creds.set_cmdline_callbacks() 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 166105b0b6b4c23eeb563562c75abcd6fa8e01e2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 23 May 2008 03:20:37 +0200 Subject: Fix bug after reprocessing swig files with newer version of SWIG. (This used to be commit 2155d76646f4235c8857460f562a9cc4cafe3ab1) --- source4/scripting/python/samba/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index c7d71d3747..94f9e4d005 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -73,15 +73,15 @@ class Ldb(ldb.Ldb): self.set_modules_dir(default_ldb_modules_dir) if credentials is not None: - self.set_credentials(self, credentials) + self.set_credentials(credentials) if session_info is not None: - self.set_session_info(self, session_info) + self.set_session_info(session_info) assert misc.ldb_register_samba_handlers(self) == 0 if lp is not None: - self.set_loadparm(self, lp) + self.set_loadparm(lp) def msg(l,text): print text -- cgit From 27005cb7a2182c50c8bf9e683de1bea2613a3078 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 05:13:31 +0200 Subject: Convert samr test to python. (This used to be commit 88d473b202e82b462ef82ffdeb4f1710918ffda5) --- source4/scripting/python/samba/tests/dcerpc/sam.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py index a6816153c0..81300c9e81 100644 --- a/source4/scripting/python/samba/tests/dcerpc/sam.py +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -26,3 +26,5 @@ class SamrTests(RpcInterfaceTestCase): def test_connect5(self): (level, info, handle) = self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) + + -- cgit From 6ccb9785e7e1b2374a0121b5c70a2969b120a926 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 22 May 2008 12:21:26 +0200 Subject: Add another test toe the python samr testsuite. (This used to be commit 480884c696c676bb978e9197271b99cc03bb66e6) --- source4/scripting/python/samba/tests/dcerpc/sam.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py index 81300c9e81..e685f9b4f4 100644 --- a/source4/scripting/python/samba/tests/dcerpc/sam.py +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -1,7 +1,8 @@ #!/usr/bin/python +# -*- coding: utf-8 -*- # Unix SMB/CIFS implementation. -# Copyright (C) Jelmer Vernooij 2008 +# Copyright © Jelmer Vernooij 2008 # # 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 @@ -17,9 +18,17 @@ # along with this program. If not, see . # -from samba.dcerpc import samr +from samba.dcerpc import samr, security from samba.tests import RpcInterfaceTestCase +# FIXME: Pidl should be doing this for us +def toArray((handle, array, num_entries)): + ret = [] + for x in range(num_entries): + ret.append((array.entries[x].idx, array.entries[x].name)) + return ret + + class SamrTests(RpcInterfaceTestCase): def setUp(self): self.conn = samr.samr("ncalrpc:", self.get_loadparm()) @@ -27,4 +36,11 @@ class SamrTests(RpcInterfaceTestCase): def test_connect5(self): (level, info, handle) = self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) + def test_connect2(self): + (level, info, handle) = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) + + def test_EnumDomains(self): + handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) + domains = toArray(self.conn.EnumDomains(handle, 0, -1)) + self.conn.Close(handle) -- cgit From 5eed56d0ad5245a346ea564bc34e882828394611 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 23 May 2008 15:10:35 +0200 Subject: Fix bugs in samr python tests. (This used to be commit 09c6b106ac144820b8c072bda4dad3d8e2145ff0) --- source4/scripting/python/samba/tests/dcerpc/sam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py index e685f9b4f4..50e00a3f9e 100644 --- a/source4/scripting/python/samba/tests/dcerpc/sam.py +++ b/source4/scripting/python/samba/tests/dcerpc/sam.py @@ -37,7 +37,7 @@ class SamrTests(RpcInterfaceTestCase): (level, info, handle) = self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) def test_connect2(self): - (level, info, handle) = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) + handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) def test_EnumDomains(self): handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) -- cgit From e3d000f3bfad4126ab781f15848fff3bbd8abcc5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 23 May 2008 16:29:08 +0200 Subject: Some more PEP improvements. (This used to be commit 015ca850df9b4c8112b033130023909b1d0b78b7) --- source4/scripting/python/samba/provision.py | 35 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index fe9b582d56..fdcc3dad77 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1111,7 +1111,7 @@ def provision_become_dc(setup_dir=None, return provision(setup_dir, message, system_session(), None, smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn, - domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); + domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename) def setup_db_config(setup_path, dbdir): @@ -1120,9 +1120,9 @@ def setup_db_config(setup_path, dbdir): :param setup_path: Setup path function. :param dbdir: Database directory.""" if not os.path.isdir(os.path.join(dbdir, "bdb-logs")): - os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700); + os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700) if not os.path.isdir(os.path.join(dbdir, "tmp")): - os.makedirs(os.path.join(dbdir, "tmp"), 0700); + os.makedirs(os.path.join(dbdir, "tmp"), 0700) setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"), {"LDAPDBDIR": dbdir}) @@ -1145,8 +1145,9 @@ def provision_backend(setup_dir=None, message=None, root = findnss(pwd.getpwnam, ["root"])[0] if smbconf is None: - os.makedirs(os.path.join(targetdir, "etc")) - smbconf = os.path.join(targetdir, "etc", "smb.conf") + etcdir = os.path.join(targetdir, "etc") + os.makedirs(etcdir) + smbconf = os.path.join(etcdir, "smb.conf") # only install a new smb.conf if there isn't one there already if not os.path.exists(smbconf): @@ -1220,20 +1221,18 @@ def provision_backend(setup_dir=None, message=None, elif ldap_backend_type == "openldap": attrs = ["linkID", "lDAPDisplayName"] - res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs); + res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs) - memberof_config = "# Generated from schema in " + schemadb_path + "\n"; - refint_attributes = ""; + memberof_config = "# Generated from schema in %s\n" % schemadb_path + refint_attributes = "" for i in range (0, len(res)): - linkid = res[i]["linkID"][0] - linkid = str(int(linkid) + 1) - expression = "(&(objectclass=attributeSchema)(linkID=" + (linkid) + "))" + expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1) target = schemadb.searchone(basedn=names.schemadn, expression=expression, attribute="lDAPDisplayName", - scope=SCOPE_SUBTREE); + scope=SCOPE_SUBTREE) if target is not None: - refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]; + refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0] memberof_config = memberof_config + """overlay memberof memberof-dangling error memberof-refint TRUE @@ -1242,11 +1241,11 @@ memberof-member-ad """ + res[i]["lDAPDisplayName"][0] + """ memberof-memberof-ad """ + target + """ memberof-dangling-error 32 -"""; +""" memberof_config = memberof_config + """ overlay refint -refint_attributes""" + refint_attributes + "\n"; +refint_attributes""" + refint_attributes + "\n" setup_file(setup_path("slapd.conf"), paths.slapdconf, {"DNSDOMAIN": names.dnsdomain, @@ -1273,12 +1272,12 @@ refint_attributes""" + refint_attributes + "\n"; server_port_string = "" slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string - schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema); + schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) os.system(schema_command) - message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ( ldap_backend_type) ) + message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type) message("Server Role: %s" % serverrole) message("Hostname: %s" % names.hostname) message("DNS Domain: %s" % names.dnsdomain) @@ -1337,6 +1336,7 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn, "HOSTIP6_HOST_LINE": hostip6_host_line, }) + def create_named_conf(path, setup_path, realm, dnsdomain, private_dir, keytab_name): """Write out a file containing zone statements suitable for inclusion in a @@ -1375,6 +1375,7 @@ def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): "REALM": realm, }) + def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): """Load schema for the SamDB. -- cgit From a203ee1ab18ea68c6df436f8bb9fc0772611d5d1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 23 May 2008 16:43:26 +0200 Subject: Fix indentation, add docstring in provisioning script. (This used to be commit 86a8a085496c292b390c0d6362e3e4d9980df83f) --- source4/scripting/python/samba/provision.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index fdcc3dad77..a4730d8a07 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -48,6 +48,7 @@ __docformat__ = "restructuredText" DEFAULTSITE = "Default-First-Site-Name" class InvalidNetbiosName(Exception): + """A specified name was not a valid NetBIOS name.""" def __init__(self, name): super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name) @@ -1233,7 +1234,7 @@ def provision_backend(setup_dir=None, message=None, scope=SCOPE_SUBTREE) if target is not None: refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0] - memberof_config = memberof_config + """overlay memberof + memberof_config += """overlay memberof memberof-dangling error memberof-refint TRUE memberof-group-oc top @@ -1243,7 +1244,7 @@ memberof-dangling-error 32 """ - memberof_config = memberof_config + """ + memberof_config += """ overlay refint refint_attributes""" + refint_attributes + "\n" @@ -1259,18 +1260,18 @@ refint_attributes""" + refint_attributes + "\n" setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "user"))) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "config"))) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "schema"))) - mapping = "schema-map-openldap-2.3" - backend_schema = "backend-schema.schema" - - ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - if ldap_backend_port is not None: - server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port - else: - server_port_string = "" - slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "user"))) + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "config"))) + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "schema"))) + mapping = "schema-map-openldap-2.3" + backend_schema = "backend-schema.schema" + + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + if ldap_backend_port is not None: + server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port + else: + server_port_string = "" + slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) -- cgit From 73b789b6d25698dba15c867c71d0cdd8c264f352 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 24 May 2008 04:01:57 +0200 Subject: Add docstrings to a couple more python modules. (This used to be commit b4560c90e5e8d3a35367d3a21d361dc4c9c0de23) --- source4/scripting/python/samba/__init__.py | 2 ++ source4/scripting/python/samba/provision.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 94f9e4d005..e191227108 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -20,6 +20,8 @@ # along with this program. If not, see . # +"""Samba 4.""" + __docformat__ = "restructuredText" import os diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index a4730d8a07..3914fa8376 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -22,6 +22,8 @@ # along with this program. If not, see . # +"""Functions for setting up a Samba configuration.""" + from base64 import b64encode import os import pwd @@ -41,8 +43,6 @@ import urllib from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE -"""Functions for setting up a Samba configuration.""" - __docformat__ = "restructuredText" DEFAULTSITE = "Default-First-Site-Name" -- cgit From f76697ce89606aa4e5ba1bb13f1fda6e33998695 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 24 May 2008 18:57:15 +0200 Subject: Add convenience functions for packing/unpacking structs in python. (This used to be commit c5d7d48b32bcebf8a0495cbd4556e30587fa589f) --- source4/scripting/python/samba/ndr.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 source4/scripting/python/samba/ndr.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/ndr.py b/source4/scripting/python/samba/ndr.py new file mode 100644 index 0000000000..e93fbc3c2e --- /dev/null +++ b/source4/scripting/python/samba/ndr.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright © Jelmer Vernooij 2008 +# +# 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 . +# + +def ndr_pack(object): + return object.__ndr_pack__() + + +def ndr_unpack(cls, data): + object = cls() + object.__ndr_unpack__(data) + return object -- cgit From 05194ccdf875ee70cb9ee3f7c27147503d585a6d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 24 May 2008 19:50:09 +0200 Subject: Add tests for new NDR pack/unpack functionality in Python DCE/RPC bindings. (This used to be commit 468d35827fd055c82c6d43d6ce6d3d561abed54d) --- source4/scripting/python/samba/ndr.py | 1 + source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/ndr.py b/source4/scripting/python/samba/ndr.py index e93fbc3c2e..e718ff3422 100644 --- a/source4/scripting/python/samba/ndr.py +++ b/source4/scripting/python/samba/ndr.py @@ -1,4 +1,5 @@ #!/usr/bin/python +# -*- coding: utf-8 -*- # Unix SMB/CIFS implementation. # Copyright © Jelmer Vernooij 2008 diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 3b37f8a9bc..9157f83fc9 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -18,6 +18,7 @@ # from samba.dcerpc import echo +from samba.ndr import ndr_pack, ndr_unpack import unittest from samba.tests import RpcInterfaceTestCase @@ -40,3 +41,14 @@ class RpcEchoTests(RpcInterfaceTestCase): surrounding_struct.surrounding = [1,2,3,4] y = self.conn.TestSurrounding(surrounding_struct) self.assertEquals(8 * [0], y.surrounding) + + +class NdrEchoTests(unittest.TestCase): + def test_info1_push(self): + x = echo.info1() + x.v = 42 + self.assertEquals("\x2a", ndr_pack(x)) + + def test_info1_pull(self): + x = ndr_unpack(echo.info1, "\x42") + self.assertEquals(x.v, 66) -- cgit From 75e7962d2efb1aa6e45ca999b1a93829406de540 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 24 May 2008 22:13:32 +0200 Subject: Add convenience functions for setting Python objects from errors. (This used to be commit f1de723b89251cbc8140b838941f304a34871bf3) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 9157f83fc9..83279a0b30 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -42,6 +42,11 @@ class RpcEchoTests(RpcInterfaceTestCase): y = self.conn.TestSurrounding(surrounding_struct) self.assertEquals(8 * [0], y.surrounding) + def test_manual_request(self): + self.assertEquals("\x01\x00\x00\x00", self.conn.request(0, chr(0) * 4)) + + def test_server_name(self): + self.assertEquals(None, self.conn.server_name) class NdrEchoTests(unittest.TestCase): def test_info1_push(self): -- cgit From 21ce0ff00688c560e60efd6c392c71f85229c9d4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 24 May 2008 22:56:49 +0200 Subject: Allow connecting to a DCE/RPC interface with Python for which we don't have IDL. (This used to be commit e3178d522c95871f1db35d7e058906502387a553) --- .../scripting/python/samba/tests/dcerpc/bare.py | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 source4/scripting/python/samba/tests/dcerpc/bare.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py new file mode 100644 index 0000000000..dae1dedeb3 --- /dev/null +++ b/source4/scripting/python/samba/tests/dcerpc/bare.py @@ -0,0 +1,30 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Unix SMB/CIFS implementation. +# Copyright © Jelmer Vernooij 2008 +# +# 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 . +# + +from samba.dcerpc import ClientConnection +from unittest import TestCase + +class BareTestCase(TestCase): + def test_bare(self): + # Connect to the echo pipe + x = ClientConnection("ncalrpc:localhost[DEFAULT]", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) + -- cgit From 928ecbaebbde00515d08fd530db7c99169c905ef Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 25 May 2008 04:23:03 +0200 Subject: Add support for secondary contexts from Python. (This used to be commit 16d1ad050546ae6500153438db8d3c857e6f3ad5) --- source4/scripting/python/samba/tests/dcerpc/bare.py | 13 +++++++++++++ source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 4 ++++ 2 files changed, 17 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py index dae1dedeb3..eea6744e42 100644 --- a/source4/scripting/python/samba/tests/dcerpc/bare.py +++ b/source4/scripting/python/samba/tests/dcerpc/bare.py @@ -28,3 +28,16 @@ class BareTestCase(TestCase): ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) + #def test_alter_context(self): + # x = ClientConnection("ncalrpc:localhost[DEFAULT]", + # ("12345778-1234-abcd-ef00-0123456789ac", 1)) + # x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + # self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) + + def test_two_connections(self): + x = ClientConnection("ncalrpc:localhost[DEFAULT]", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + y = ClientConnection("ncalrpc:localhost", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), + basis_connection=x) + self.assertEquals("\x01\x00\x00\x00", y.request(0, chr(0) * 4)) diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 83279a0b30..7fd1bcc5b8 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -26,6 +26,10 @@ class RpcEchoTests(RpcInterfaceTestCase): def setUp(self): self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm()) + def test_two_contexts(self): + self.conn2 = echo.rpcecho("ncalrpc", basis_connection=self.conn) + self.assertEquals(3, self.conn2.AddOne(2)) + def test_addone(self): self.assertEquals(2, self.conn.AddOne(1)) -- cgit From 74126bc6d0211a7674156dfda8ab13054b403a1d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 25 May 2008 04:54:38 +0200 Subject: Expose transfer and abstract syntax. (This used to be commit a875e07a37568b7e51c290074d5e3834c2caa4d6) --- source4/scripting/python/samba/tests/dcerpc/bare.py | 13 ++++++++----- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 4 ++++ 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py index eea6744e42..d75ffc381e 100644 --- a/source4/scripting/python/samba/tests/dcerpc/bare.py +++ b/source4/scripting/python/samba/tests/dcerpc/bare.py @@ -28,11 +28,14 @@ class BareTestCase(TestCase): ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) - #def test_alter_context(self): - # x = ClientConnection("ncalrpc:localhost[DEFAULT]", - # ("12345778-1234-abcd-ef00-0123456789ac", 1)) - # x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1)) - # self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) + def test_alter_context(self): + x = ClientConnection("ncalrpc:localhost[DEFAULT]", + ("12345778-1234-abcd-ef00-0123456789ac", 1)) + y = ClientConnection("ncalrpc:localhost", + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), + basis_connection=x) + x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + # FIXME: self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) def test_two_connections(self): x = ClientConnection("ncalrpc:localhost[DEFAULT]", diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 7fd1bcc5b8..68b7a42d52 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -30,6 +30,10 @@ class RpcEchoTests(RpcInterfaceTestCase): self.conn2 = echo.rpcecho("ncalrpc", basis_connection=self.conn) self.assertEquals(3, self.conn2.AddOne(2)) + def test_abstract_syntax(self): + self.assertEquals(("60a15ec5-4de8-11d7-a637-005056a20182", 1), + self.conn.abstract_syntax) + def test_addone(self): self.assertEquals(2, self.conn.AddOne(1)) -- cgit From 5df9e0576ebd8ad737bb2580b52788601b6cf854 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 25 May 2008 14:41:54 +0200 Subject: Fix missing colon. (This used to be commit 6b1576f544e2ea2b5ea0b234b724c4989dd49cca) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 68b7a42d52..bbbd0d76ec 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -27,7 +27,7 @@ class RpcEchoTests(RpcInterfaceTestCase): self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm()) def test_two_contexts(self): - self.conn2 = echo.rpcecho("ncalrpc", basis_connection=self.conn) + self.conn2 = echo.rpcecho("ncalrpc:", basis_connection=self.conn) self.assertEquals(3, self.conn2.AddOne(2)) def test_abstract_syntax(self): -- cgit From 815c0ef2ed3bafe44c687dffe97b309b00df7a8c Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Fri, 23 May 2008 02:20:35 -0500 Subject: provision: Add missing string parameter token when assigning ldap_backend. (This used to be commit 7d26145a7fba22b2e1c7c57053aab3180a22089d) --- source4/scripting/python/samba/provision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 3914fa8376..4a9def8aa9 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -969,7 +969,7 @@ def provision(setup_dir, message, session_info, if ldap_backend is not None: if ldap_backend == "ldapi": # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + ldap_backend = "ldapi://%s" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): -- cgit From b7c8e020a6f7221d6d10f2dd7610a232edeedf83 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 29 May 2008 18:38:17 +1000 Subject: Print prefixMap in a human-readable format. This should allow the prefixMap to be edited, until we find the right way to autogenerate it. Andrew Bartlett (This used to be commit 24ae9a55ec326807afd8d5bfa0a422a6668bd7c3) --- source4/scripting/python/samba/provision.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 4a9def8aa9..71c1ac3187 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -797,13 +797,17 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") + + prefixmap = open(setup_path("prefixMap.txt"), 'r').read() + setup_modify_ldif(samdb, setup_path("provision_schema_basedn_modify.ldif"), { "SCHEMADN": names.schemadn, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": names.sitename, "CONFIGDN": names.configdn, - "SERVERDN": names.serverdn + "SERVERDN": names.serverdn, + "PREFIXMAP_B64": b64encode(prefixmap) }) message("Setting up sam.ldb Samba4 schema") @@ -1389,12 +1393,16 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): schema_data = open(setup_path("schema.ldif"), 'r').read() schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) + prefixmap = open(setup_path("prefixMap.txt"), 'r').read() + prefixmap = b64encode(prefixmap) + head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read() head_data = substitute_var(head_data, { "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "CONFIGDN": configdn, - "DEFAULTSITE":sitename + "DEFAULTSITE":sitename, + "PREFIXMAP_B64":prefixmap }) samdb.attach_schema_from_ldif(head_data, schema_data) -- cgit From 90aeca8ebdd74250038a11d4c523c01072711092 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 29 May 2008 17:29:56 +0200 Subject: Check test directory is cleaned up by Python tests. (This used to be commit c338269b4b9f2bf4d3386880c1d733a8e47e2c8d) --- source4/scripting/python/samba/tests/__init__.py | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py index e29b4a87d5..d827bfa004 100644 --- a/source4/scripting/python/samba/tests/__init__.py +++ b/source4/scripting/python/samba/tests/__init__.py @@ -47,6 +47,7 @@ class TestCaseInTempDir(unittest.TestCase): def tearDown(self): super(TestCaseInTempDir, self).tearDown() + self.assertEquals([], os.listdir(self.tempdir)) os.rmdir(self.tempdir) -- cgit From e16f0e15b40229e7a42311dddfb391cf6142462e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 29 May 2008 17:31:16 +0200 Subject: Update after changes to the provision API, make sure temp dir gets cleaned up. (This used to be commit 064e9ddb3786bd7df8785b39754b1e6674496b66) --- source4/scripting/python/samba/tests/samdb.py | 29 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 0d4f7bde0e..a022d7bb51 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -16,13 +16,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from auth import system_session -from credentials import Credentials +from samba.auth import system_session +from samba.credentials import Credentials import os -from samba.provision import setup_samdb +from samba.provision import setup_samdb, guess_names from samba.samdb import SamDB from samba.tests import cmdline_loadparm, TestCaseInTempDir -import security +from samba import security from unittest import TestCase import uuid @@ -42,14 +42,23 @@ class SamDBTestCase(TestCaseInTempDir): domainsid = security.random_sid() hostguid = str(uuid.uuid4()) path = os.path.join(self.tempdir, "samdb.ldb") + names = guess_names(lp=cmdline_loadparm, hostname="foo", + domain="EXAMPLE.COM", dnsdomain="example.com", + serverrole="domain controller", + domaindn=self.domaindn, configdn=configdn, + schemadn=schemadn) self.samdb = setup_samdb(path, setup_path, system_session(), creds, - cmdline_loadparm, schemadn, configdn, - self.domaindn, "example.com", "EXAMPLE.COM", - "FOO", lambda x: None, "foo", domaindn, - False, domainsid, "# no aci", domainguid, - policyguid, "EXAMPLE", True, "secret", - "secret", "secret", hostguid, invocationid, + cmdline_loadparm, names, + lambda x: None, domainsid, + "# no aci", domainguid, + policyguid, False, "secret", + "secret", "secret", invocationid, "secret", "domain controller") + def tearDown(self): + for f in ['templates.ldb', 'schema.ldb', 'configuration.ldb', + 'users.ldb', 'samdb.ldb']: + os.remove(os.path.join(self.tempdir, f)) + super(SamDBTestCase, self).tearDown() def test_add_foreign(self): self.samdb.add_foreign(self.domaindn, "S-1-5-7", "Somedescription") -- cgit From 6f7b2b69333230016a9538b024faec0d97095c69 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 29 May 2008 17:38:12 +0200 Subject: Fix samdb test and enable it. (This used to be commit 6b202d3780f8ff50e0bdfa4a749c43b5639e4880) --- source4/scripting/python/samba/tests/samdb.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index a022d7bb51..7e8ba053d4 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -19,7 +19,7 @@ from samba.auth import system_session from samba.credentials import Credentials import os -from samba.provision import setup_samdb, guess_names +from samba.provision import setup_samdb, guess_names, setup_templatesdb from samba.samdb import SamDB from samba.tests import cmdline_loadparm, TestCaseInTempDir from samba import security @@ -42,12 +42,16 @@ class SamDBTestCase(TestCaseInTempDir): domainsid = security.random_sid() hostguid = str(uuid.uuid4()) path = os.path.join(self.tempdir, "samdb.ldb") + session_info = system_session() names = guess_names(lp=cmdline_loadparm, hostname="foo", domain="EXAMPLE.COM", dnsdomain="example.com", serverrole="domain controller", domaindn=self.domaindn, configdn=configdn, schemadn=schemadn) - self.samdb = setup_samdb(path, setup_path, system_session(), creds, + setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"), + setup_path, session_info=session_info, + credentials=creds, lp=cmdline_loadparm) + self.samdb = setup_samdb(path, setup_path, session_info, creds, cmdline_loadparm, names, lambda x: None, domainsid, "# no aci", domainguid, -- cgit From b9babfe4cc70b96f4f1df037244cd27eae580c94 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 14:26:47 +1000 Subject: Fix up provision and samdb tests. This fixes up the provision to operate with a target directory - it must override the smb.conf in this case. Andrew Bartlett (This used to be commit 89fc39f7edb214065aff461bc225f41443eae3c7) --- source4/scripting/python/samba/provision.py | 5 +++-- source4/scripting/python/samba/tests/samdb.py | 25 ++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 71c1ac3187..b7112e16c3 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -930,8 +930,9 @@ def provision(setup_dir, message, session_info, if aci is None: aci = "# no aci for local ldb" - if smbconf is None: - os.makedirs(os.path.join(targetdir, "etc")) + if targetdir is not None: + if (not os.path.exists(os.path.join(targetdir, "etc"))): + os.makedirs(os.path.join(targetdir, "etc")) smbconf = os.path.join(targetdir, "etc", "smb.conf") # only install a new smb.conf if there isn't one there already diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 7e8ba053d4..fcf93a3fc6 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -19,12 +19,13 @@ from samba.auth import system_session from samba.credentials import Credentials import os -from samba.provision import setup_samdb, guess_names, setup_templatesdb +from samba.provision import setup_samdb, guess_names, setup_templatesdb, make_smbconf from samba.samdb import SamDB from samba.tests import cmdline_loadparm, TestCaseInTempDir from samba import security from unittest import TestCase import uuid +import param class SamDBTestCase(TestCaseInTempDir): def setUp(self): @@ -43,9 +44,22 @@ class SamDBTestCase(TestCaseInTempDir): hostguid = str(uuid.uuid4()) path = os.path.join(self.tempdir, "samdb.ldb") session_info = system_session() - names = guess_names(lp=cmdline_loadparm, hostname="foo", - domain="EXAMPLE.COM", dnsdomain="example.com", - serverrole="domain controller", + + hostname="foo" + domain="EXAMPLE" + dnsdomain="example.com" + serverrole="domain controller" + + smbconf = os.path.join(self.tempdir, "smb.conf") + make_smbconf(smbconf, setup_path, hostname, domain, dnsdomain, serverrole, + self.tempdir) + + lp = param.LoadParm() + lp.load(smbconf) + + names = guess_names(lp=lp, hostname=hostname, + domain=domain, dnsdomain=dnsdomain, + serverrole=severrole, domaindn=self.domaindn, configdn=configdn, schemadn=schemadn) setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"), @@ -58,9 +72,10 @@ class SamDBTestCase(TestCaseInTempDir): policyguid, False, "secret", "secret", "secret", invocationid, "secret", "domain controller") + def tearDown(self): for f in ['templates.ldb', 'schema.ldb', 'configuration.ldb', - 'users.ldb', 'samdb.ldb']: + 'users.ldb', 'samdb.ldb', 'smb.conf']: os.remove(os.path.join(self.tempdir, f)) super(SamDBTestCase, self).tearDown() -- cgit From d579540085133d3a3b273a653cea7f8da10ed5db Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 15:09:59 +1000 Subject: Fix rpcecho test. (This used to be commit df8399ba9dee9d1c706a3e56451c9f2cade96dae) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index bbbd0d76ec..96bb3923a6 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -27,7 +27,7 @@ class RpcEchoTests(RpcInterfaceTestCase): self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm()) def test_two_contexts(self): - self.conn2 = echo.rpcecho("ncalrpc:", basis_connection=self.conn) + self.conn2 = echo.rpcecho("ncalrpc:", self.get_loadparm(), basis_connection=self.conn) self.assertEquals(3, self.conn2.AddOne(2)) def test_abstract_syntax(self): -- cgit From 21377a7ea9800636a8bc96b3863f97062d7bf9d1 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 15:26:10 +1000 Subject: Fix the samba4.dcerpc.bare.python test. The loadparm context isn't really optional, as otherwise we can't find the right server to connect to. Andrew Bartlett (This used to be commit 2b5acb5e95b46dd39c6f54b5bb7e15ddb180f7ec) --- source4/scripting/python/samba/tests/dcerpc/bare.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py index d75ffc381e..fae699a249 100644 --- a/source4/scripting/python/samba/tests/dcerpc/bare.py +++ b/source4/scripting/python/samba/tests/dcerpc/bare.py @@ -20,27 +20,28 @@ from samba.dcerpc import ClientConnection from unittest import TestCase +from samba.tests import cmdline_loadparm class BareTestCase(TestCase): def test_bare(self): # Connect to the echo pipe x = ClientConnection("ncalrpc:localhost[DEFAULT]", - ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm) self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) def test_alter_context(self): x = ClientConnection("ncalrpc:localhost[DEFAULT]", - ("12345778-1234-abcd-ef00-0123456789ac", 1)) + ("12345778-1234-abcd-ef00-0123456789ac", 1), lp_ctx=cmdline_loadparm) y = ClientConnection("ncalrpc:localhost", ("60a15ec5-4de8-11d7-a637-005056a20182", 1), - basis_connection=x) + basis_connection=x, lp_ctx=cmdline_loadparm) x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1)) # FIXME: self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) def test_two_connections(self): x = ClientConnection("ncalrpc:localhost[DEFAULT]", - ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm) y = ClientConnection("ncalrpc:localhost", ("60a15ec5-4de8-11d7-a637-005056a20182", 1), - basis_connection=x) + basis_connection=x, lp_ctx=cmdline_loadparm) self.assertEquals("\x01\x00\x00\x00", y.request(0, chr(0) * 4)) -- cgit From 277287114679addc2ef26fbe6a82963f9cf1b196 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 30 May 2008 14:15:40 +0200 Subject: Fix samdb python test. (This used to be commit 0e3d488cc108174ca0f875aab16b9771c2933f19) --- source4/scripting/python/samba/provision.py | 6 +++--- source4/scripting/python/samba/tests/samdb.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index b7112e16c3..3f936c3301 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1321,12 +1321,12 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn, """ assert isinstance(domainguid, str) - hostip6_base_line = "" - hostip6_host_line = "" - if hostip6 is not None: hostip6_base_line = " IN AAAA " + hostip6 hostip6_host_line = hostname + " IN AAAA " + hostip6 + else: + hostip6_base_line = "" + hostip6_host_line = "" setup_file(setup_path("provision.zone"), path, { "DNSPASS_B64": b64encode(dnspass), diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index fcf93a3fc6..97be5672ce 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -25,7 +25,7 @@ from samba.tests import cmdline_loadparm, TestCaseInTempDir from samba import security from unittest import TestCase import uuid -import param +from samba import param class SamDBTestCase(TestCaseInTempDir): def setUp(self): @@ -59,7 +59,7 @@ class SamDBTestCase(TestCaseInTempDir): names = guess_names(lp=lp, hostname=hostname, domain=domain, dnsdomain=dnsdomain, - serverrole=severrole, + serverrole=serverrole, domaindn=self.domaindn, configdn=configdn, schemadn=schemadn) setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"), -- cgit From 370f95acfc197759f9140876b31ac127d3a0e10c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 16 Jun 2008 17:51:42 -0400 Subject: Try to get a bit further with provisioning (This used to be commit 649f6c0c1084828dda7d50bd2904208192de77da) --- source4/scripting/python/samba/provision.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 3f936c3301..93a4c8f502 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1180,6 +1180,8 @@ def provision_backend(setup_dir=None, message=None, schemadb = Ldb(schemadb_path, lp=lp) + prefixmap = open(setup_path("prefixMap.txt"), 'r').read() + setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"), {"SCHEMADN": names.schemadn, "ACI": "#", @@ -1191,7 +1193,8 @@ def provision_backend(setup_dir=None, message=None, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": DEFAULTSITE, "CONFIGDN": names.configdn, - "SERVERDN": names.serverdn + "SERVERDN": names.serverdn, + "PREFIXMAP_B64": b64encode(prefixmap) }) setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"), -- cgit From 9ea25cacf1c564a485897432b73beebf2e634f55 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 19 Jun 2008 11:05:20 +1000 Subject: Add a blackbox test for the provision-backend script. This test (as most tests do :-) found a few bugs, also fixed in this commit. Andrew Bartlett (This used to be commit d96a6482dad54d1d27a87107865e833a9c32cf53) --- source4/scripting/python/samba/provision.py | 57 +++++++++++++++-------------- 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 93a4c8f502..504044253e 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1150,15 +1150,18 @@ def provision_backend(setup_dir=None, message=None, if root is None: root = findnss(pwd.getpwnam, ["root"])[0] - if smbconf is None: - etcdir = os.path.join(targetdir, "etc") - os.makedirs(etcdir) - smbconf = os.path.join(etcdir, "smb.conf") + if adminpass is None: + adminpass = misc.random_password(12) + + if targetdir is not None: + if (not os.path.exists(os.path.join(targetdir, "etc"))): + os.makedirs(os.path.join(targetdir, "etc")) + smbconf = os.path.join(targetdir, "etc", "smb.conf") # only install a new smb.conf if there isn't one there already if not os.path.exists(smbconf): - make_smbconf(smbconf, setup_path, hostname, domain, realm, - serverrole, targetdir) + make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, + targetdir) lp = param.LoadParm() lp.load(smbconf) @@ -1230,11 +1233,11 @@ def provision_backend(setup_dir=None, message=None, elif ldap_backend_type == "openldap": attrs = ["linkID", "lDAPDisplayName"] - res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs) + res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs) - memberof_config = "# Generated from schema in %s\n" % schemadb_path - refint_attributes = "" - for i in range (0, len(res)): + memberof_config = "# Generated from schema in %s\n" % schemadb_path + refint_attributes = "" + for i in range (0, len(res)): expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1) target = schemadb.searchone(basedn=names.schemadn, expression=expression, @@ -1252,11 +1255,11 @@ memberof-dangling-error 32 """ - memberof_config += """ + memberof_config += """ overlay refint refint_attributes""" + refint_attributes + "\n" - setup_file(setup_path("slapd.conf"), paths.slapdconf, + setup_file(setup_path("slapd.conf"), paths.slapdconf, {"DNSDOMAIN": names.dnsdomain, "LDAPDIR": paths.ldapdir, "DOMAINDN": names.domaindn, @@ -1265,27 +1268,27 @@ refint_attributes""" + refint_attributes + "\n" "LDAPMANAGERDN": names.ldapmanagerdn, "LDAPMANAGERPASS": adminpass, "MEMBEROF_CONFIG": memberof_config}) - setup_file(setup_path("modules.conf"), paths.modulesconf, + setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "user"))) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "config"))) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "schema"))) - mapping = "schema-map-openldap-2.3" - backend_schema = "backend-schema.schema" - - ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") - if ldap_backend_port is not None: - server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port - else: - server_port_string = "" - slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "user"))) + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "config"))) + setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "schema"))) + mapping = "schema-map-openldap-2.3" + backend_schema = "backend-schema.schema" - schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) + ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + if ldap_backend_port is not None: + server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port + else: + server_port_string = "" + slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string + + schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) + os.system(schema_command) - message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type) message("Server Role: %s" % serverrole) message("Hostname: %s" % names.hostname) -- cgit From 44ea6a26fd088f0f8c86817510ebe5a6cddf9158 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sat, 12 Jul 2008 15:26:42 +1000 Subject: rename sambaPassword -> userPassword. This attribute is used in a very similar way (virtual attribute updating the password) in AD on Win2003, so eliminate the difference. This should not cause a problem for on-disk passwords, as by default we do not store the plaintext at all. Andrew Bartlett (This used to be commit 1cf0d751493b709ef6b2234ec8847a7499f48ab3) --- source4/scripting/python/samba/samdb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 6465f49519..c47cf4a0dc 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -112,7 +112,7 @@ userAccountControl: %u # now the real work self.add({"dn": user_dn, "sAMAccountName": username, - "sambaPassword": password, + "userPassword": password, "objectClass": "user"}) res = self.search(user_dn, scope=ldb.SCOPE_BASE, @@ -163,8 +163,8 @@ userAccountControl: %u setpw = """ dn: %s changetype: modify -replace: sambaPassword -sambaPassword: %s +replace: userPassword +userPassword: %s """ % (user_dn, password) self.modify_ldif(setpw) -- cgit From a6b842f9634cbeb4075c2bbaf7e49c19104602be Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 15 Jul 2008 15:15:12 +1000 Subject: Connect to the LDAP backend with SASL credentials. This reworks our LDAP backend code to move from anonymous access to a shared-secret SASL-protected connection. (SASL selects NTLM or DIGEST-MD5 on my system). To get this working, we must pre-populate the LDAP backend with a DN to store ths SASL secret on, and we use back-ldif for this. This gives us a reasonable basis to deploy a replicated OpenLDAP backend solution. Andrew Bartlett (This used to be commit cd0745253c4a9ec59a035e830e54d74a05b71aaa) --- source4/scripting/python/samba/provision.py | 47 +++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 9 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 504044253e..d0f612c7a8 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -604,6 +604,20 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp) secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) + + if credentials.authentication_requested: + if credentials.get_bind_dn() is not None: + setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), { + "LDAPMANAGERDN": credentials.get_bind_dn(), + "LDAPMANAGERPASS_B64": b64encode(credentials.get_password()) + }) + else: + setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), { + "LDAPADMINUSER": credentials.get_username(), + "LDAPADMINREALM": credentials.get_realm(), + "LDAPADMINPASS_B64": b64encode(credentials.get_password()) + }) + return secrets_ldb @@ -754,10 +768,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, domain_oc = "samba4LocalDomain" setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { - "DOMAINDN": names.domaindn, - "ACI": aci, - "DOMAIN_OC": domain_oc - }) + "DOMAINDN": names.domaindn, + "ACI": aci, + "DOMAIN_OC": domain_oc + }) message("Modifying DomainDN: " + names.domaindn + "") if domainguid is not None: @@ -1265,15 +1279,30 @@ refint_attributes""" + refint_attributes + "\n" "DOMAINDN": names.domaindn, "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, - "LDAPMANAGERDN": names.ldapmanagerdn, - "LDAPMANAGERPASS": adminpass, "MEMBEROF_CONFIG": memberof_config}) setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "user"))) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "config"))) - setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "schema"))) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config")) + setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema")) + + if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")): + os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")) + + setup_file(setup_path("cn=samba.ldif"), + os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"), + { "UUID": str(uuid.uuid4()), + "LDAPTIME": timestring(int(time.time()))} ) + setup_file(setup_path("cn=samba-admin.ldif"), + os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"), + {"LDAPADMINPASS_B64": b64encode(adminpass), + "UUID": str(uuid.uuid4()), + "LDAPTIME": timestring(int(time.time()))} ) + +#"LDAPMANAGERDN": names.ldapmanagerdn, + + mapping = "schema-map-openldap-2.3" backend_schema = "backend-schema.schema" -- cgit From 0f1eea267257eff0d75a702ee0793a86834fb76a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 15 Jul 2008 15:46:32 +1000 Subject: Rework provision to handle both simple and SASL binds. Fedora DS is still setup for simple binds only, at this point. (it also fails on other issues). Andrew Bartlett (This used to be commit b24c572d5a38c1f6906751c2ad2f809e1995b510) --- source4/scripting/python/samba/provision.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d0f612c7a8..f27cc17290 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1300,9 +1300,6 @@ refint_attributes""" + refint_attributes + "\n" "UUID": str(uuid.uuid4()), "LDAPTIME": timestring(int(time.time()))} ) -#"LDAPMANAGERDN": names.ldapmanagerdn, - - mapping = "schema-map-openldap-2.3" backend_schema = "backend-schema.schema" @@ -1323,7 +1320,12 @@ refint_attributes""" + refint_attributes + "\n" message("Hostname: %s" % names.hostname) message("DNS Domain: %s" % names.dnsdomain) message("Base DN: %s" % names.domaindn) - message("LDAP admin DN: %s" % names.ldapmanagerdn) + + if ldap_backend_type == "openldap": + message("LDAP admin user: samba-admin") + else: + message("LDAP admin DN: %s" % names.ldapmanagerdn) + message("LDAP admin password: %s" % adminpass) message(slapdcommand) -- cgit From e400b3ec4e7f32406ed8803ed22612033511d99a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 15 Jul 2008 18:44:58 +1000 Subject: Fix asking for credentials for non-LDAP provisions. (This used to be commit 78416f4840df4f8d1f9cc5e46a48b19c86888050) --- source4/scripting/python/samba/provision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f27cc17290..6102dc77ff 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -605,7 +605,7 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): lp=lp) secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) - if credentials.authentication_requested: + if credentials is not None and credentials.authentication_requested(): if credentials.get_bind_dn() is not None: setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), { "LDAPMANAGERDN": credentials.get_bind_dn(), -- cgit From fe9fa62a0529f8c8ebdbfee9b994e3787d4db58f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 16 Jul 2008 14:04:24 +1000 Subject: Reorder whitespace in generated slapd.conf This helps us see the real groupings in the generated memberOf handling. Andrew Bartlett (This used to be commit ec70ebb8310e563324233662f8e779c55fb87514) --- source4/scripting/python/samba/provision.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6102dc77ff..17e7e0fed0 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1266,12 +1266,12 @@ memberof-group-oc top memberof-member-ad """ + res[i]["lDAPDisplayName"][0] + """ memberof-memberof-ad """ + target + """ memberof-dangling-error 32 - """ - memberof_config += """ -overlay refint -refint_attributes""" + refint_attributes + "\n" + memberof_config += """overlay refint +refint_attributes""" + refint_attributes + """ + +""" setup_file(setup_path("slapd.conf"), paths.slapdconf, {"DNSDOMAIN": names.dnsdomain, -- cgit From cfc2063f230491865edb8f73174e0b12ab4dc158 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jul 2008 18:44:07 +1000 Subject: Put the memberof template into a seperate setup/ file. Set a memberof-dn in a fruitless attempt to fix the ACL problem I'm having with OpenLDAP Andrew Bartlett (This used to be commit 6d6e03834a1a77a8ceba41fbe8c9d49680065ba3) --- source4/scripting/python/samba/provision.py | 60 +++++++++++++---------------- 1 file changed, 27 insertions(+), 33 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 17e7e0fed0..301c6ef728 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -153,6 +153,19 @@ def open_ldb(session_info, credentials, lp, dbname): lp=lp) +def read_and_sub_file(file, subst_vars): + """Read a file and sub in variables found in it + + :param file: File to be read (typically from setup directory) + param subst_vars: Optional variables to subsitute in the file. + """ + data = open(file, 'r').read() + if subst_vars is not None: + data = substitute_var(data, subst_vars) + check_all_substituted(data) + return data + + def setup_add_ldif(ldb, ldif_path, subst_vars=None): """Setup a ldb in the private dir. @@ -162,27 +175,18 @@ def setup_add_ldif(ldb, ldif_path, subst_vars=None): """ assert isinstance(ldif_path, str) - data = open(ldif_path, 'r').read() - if subst_vars is not None: - data = substitute_var(data, subst_vars) - - check_all_substituted(data) - + data = read_and_sub_file(ldif_path, subst_vars) ldb.add_ldif(data) -def setup_modify_ldif(ldb, ldif_path, substvars=None): +def setup_modify_ldif(ldb, ldif_path, subst_vars=None): """Modify a ldb in the private dir. :param ldb: LDB object. :param ldif_path: LDIF file path. - :param substvars: Optional dictionary with substitution variables. + :param subst_vars: Optional dictionary with substitution variables. """ - data = open(ldif_path, 'r').read() - if substvars is not None: - data = substitute_var(data, substvars) - - check_all_substituted(data) + data = read_and_sub_file(ldif_path, subst_vars) ldb.modify_ldif(data) @@ -206,23 +210,19 @@ def setup_ldb(ldb, ldif_path, subst_vars): ldb.transaction_commit() -def setup_file(template, fname, substvars): +def setup_file(template, fname, subst_vars): """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. + :param subst_vars: Substitution variables. """ f = fname if os.path.exists(f): os.unlink(f) - data = open(template, 'r').read() - if substvars: - data = substitute_var(data, substvars) - check_all_substituted(data) - + data = read_and_sub_file(template, subst_vars) open(f, 'w').write(data) @@ -1259,19 +1259,13 @@ def provision_backend(setup_dir=None, message=None, scope=SCOPE_SUBTREE) if target is not None: refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0] - memberof_config += """overlay memberof -memberof-dangling error -memberof-refint TRUE -memberof-group-oc top -memberof-member-ad """ + res[i]["lDAPDisplayName"][0] + """ -memberof-memberof-ad """ + target + """ -memberof-dangling-error 32 -""" - - memberof_config += """overlay refint -refint_attributes""" + refint_attributes + """ - -""" + + memberof_config += read_and_sub_file(setup_path("memberof.conf"), + { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]), + "MEMBEROF_ATTR" : str(target) }) + + memberof_config += """overlay refint +refint_attributes""" + refint_attributes setup_file(setup_path("slapd.conf"), paths.slapdconf, {"DNSDOMAIN": names.dnsdomain, -- cgit From 3408a2d18fa61e2a7e3b3e05cc3c454e5e15f2ce Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 Jul 2008 18:58:56 +1000 Subject: Make a seperate template for the refint configuration too (This used to be commit d2a527acc5ee6fe9b943657dc9c3ace920b2d619) --- source4/scripting/python/samba/provision.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 301c6ef728..6eb47c8595 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1264,8 +1264,8 @@ def provision_backend(setup_dir=None, message=None, { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]), "MEMBEROF_ATTR" : str(target) }) - memberof_config += """overlay refint -refint_attributes""" + refint_attributes + refint_config = read_and_sub_file(setup_path("refint.conf"), + { "LINK_ATTRS" : refint_attributes}) setup_file(setup_path("slapd.conf"), paths.slapdconf, {"DNSDOMAIN": names.dnsdomain, @@ -1273,7 +1273,8 @@ refint_attributes""" + refint_attributes "DOMAINDN": names.domaindn, "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, - "MEMBEROF_CONFIG": memberof_config}) + "MEMBEROF_CONFIG": memberof_config, + "REFINT_CONFIG": refint_config}) setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) -- cgit From fb3e663678be412df4668b05e76480908da2c080 Mon Sep 17 00:00:00 2001 From: Matthias Dieter Wallnöfer Date: Tue, 22 Jul 2008 11:06:47 +1000 Subject: Improve DNS and Group poicy configurations. - fixes bug #4813 (simplify DNS setup) - This reworks the named.conf to be a fully fledged include - This also moves the documentation into named.txt - improves bug #4900 (Group policy support in Samba) - by creating an empty GPT.INI - fixes bug #5582 (DNS: Enhanced zone file) - This is now closer to the zone file AD creates committed by Andrew Bartlett (This used to be commit 74d684f6b329d7dd573cdc55e16bb8e629474b02) --- source4/scripting/python/samba/provision.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6eb47c8595..40b61a0ac4 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1043,6 +1043,7 @@ def provision(setup_dir, message, session_info, policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies", "{" + policyguid + "}") os.makedirs(policy_path, 0755) + open(os.path.join(policy_path, "GPT.INI"), 'w').write("") os.makedirs(os.path.join(policy_path, "Machine"), 0755) os.makedirs(os.path.join(policy_path, "User"), 0755) if not os.path.isdir(paths.netlogon): @@ -1081,12 +1082,11 @@ def provision(setup_dir, message, session_info, hostip6=hostip6, hostname=names.hostname, dnspass=dnspass, realm=names.realm, domainguid=domainguid, hostguid=hostguid) - message("Please install the zone located in %s into your DNS server" % paths.dns) create_named_conf(paths.namedconf, setup_path, realm=names.realm, dnsdomain=names.dnsdomain, private_dir=paths.private_dir, keytab_name=paths.dns_keytab) - message("See %s for example configuration statements for secure GSS-TSIG updates" % paths.namedconf) + message("See %s for an example configuration include file for BIND" % paths.namedconf) create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain, hostname=names.hostname, realm=names.realm) @@ -1394,6 +1394,7 @@ def create_named_conf(path, setup_path, realm, dnsdomain, "REALM_WC": "*." + ".".join(realm.split(".")[1:]), "DNS_KEYTAB": keytab_name, "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name), + "PRIVATE_DIR": private_dir, }) def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): -- cgit From c9c296b6bbe178502e8aded8fa5e38a0f338ee18 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 22 Jul 2008 11:09:18 +1000 Subject: Install'named.txt' to private/ as documentation. This document is much more use when subbed with all the right things. Andrew Bartlett (This used to be commit 136a85599815670c807f212d7d4003ec53a13729) --- source4/scripting/python/samba/provision.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 40b61a0ac4..4b310381ef 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -244,6 +244,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.templates = os.path.join(paths.private_dir, "templates.ldb") paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") paths.namedconf = os.path.join(paths.private_dir, "named.conf") + paths.namedtxt = os.path.join(paths.private_dir, "named.txt") paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf") paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") @@ -1084,9 +1085,13 @@ def provision(setup_dir, message, session_info, domainguid=domainguid, hostguid=hostguid) create_named_conf(paths.namedconf, setup_path, realm=names.realm, + dnsdomain=names.dnsdomain, private_dir=paths.private_dir) + + create_named_txt(paths.namedtxt, setup_path, realm=names.realm, dnsdomain=names.dnsdomain, private_dir=paths.private_dir, keytab_name=paths.dns_keytab) message("See %s for an example configuration include file for BIND" % paths.namedconf) + message("and %s for further documentation required for secure DNS updates" % paths.namedtxt) create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain, hostname=names.hostname, realm=names.realm) @@ -1376,7 +1381,7 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn, def create_named_conf(path, setup_path, realm, dnsdomain, - private_dir, keytab_name): + private_dir): """Write out a file containing zone statements suitable for inclusion in a named.conf file (including GSS-TSIG configuration). @@ -1392,9 +1397,28 @@ def create_named_conf(path, setup_path, realm, dnsdomain, "DNSDOMAIN": dnsdomain, "REALM": realm, "REALM_WC": "*." + ".".join(realm.split(".")[1:]), + "PRIVATE_DIR": private_dir + }) + +def create_named_txt(path, setup_path, realm, dnsdomain, + private_dir, keytab_name): + """Write out a file containing zone statements suitable for inclusion in a + named.conf file (including GSS-TSIG configuration). + + :param path: Path of the new named.conf file. + :param setup_path: Setup path function. + :param realm: Realm name + :param dnsdomain: DNS Domain name + :param private_dir: Path to private directory + :param keytab_name: File name of DNS keytab file + """ + + setup_file(setup_path("named.txt"), path, { + "DNSDOMAIN": dnsdomain, + "REALM": realm, "DNS_KEYTAB": keytab_name, "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name), - "PRIVATE_DIR": private_dir, + "PRIVATE_DIR": private_dir }) def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): -- cgit From 11798902dc51cd9eea3b7e8a0c94d0c0c08ed828 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 25 Jul 2008 08:45:16 +1000 Subject: Complain if we are told to use an ldap backend, without the type (This used to be commit e9c3c9ad8289ee48efa998ab6b486250dcd40b52) --- source4/scripting/python/samba/provision.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6eb47c8595..67f8cf7cc2 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -503,6 +503,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, backend_modules = ["normalise", "entryuuid", "paged_searches"] # OpenLDAP handles subtree renames, so we don't want to do any of these things tdb_modules_list = None + elif ldap_backend is not None: + raise "LDAP Backend specified, but LDAP Backend Type not specified" elif serverrole == "domain controller": backend_modules = ["repl_meta_data"] else: -- cgit From cff30c6da666abcb4ad8c587defa63883ce86c23 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 28 Jul 2008 08:04:15 +1000 Subject: Remove unused function and make sensitive directories private. (This used to be commit e23333d16397606d38e90684d2d916b5b967cde4) --- source4/scripting/python/samba/provision.py | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0119f40c7f..068fe5ad9b 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -133,26 +133,6 @@ findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2] findnss_gid = lambda names: findnss(grp.getgrnam, names)[2] -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 - try: - return Ldb(dbname, session_info=session_info, credentials=credentials, - lp=lp) - except LdbError, e: - print e - os.unlink(dbname) - return Ldb(dbname, session_info=session_info, credentials=credentials, - lp=lp) - - def read_and_sub_file(file, subst_vars): """Read a file and sub in variables found in it @@ -1195,7 +1175,7 @@ def provision_backend(setup_dir=None, message=None, paths = provision_paths_from_lp(lp, names.dnsdomain) if not os.path.isdir(paths.ldapdir): - os.makedirs(paths.ldapdir) + os.makedirs(paths.ldapdir, 0700) schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb") try: os.unlink(schemadb_path) @@ -1290,7 +1270,7 @@ def provision_backend(setup_dir=None, message=None, setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema")) if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")): - os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")) + os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700) setup_file(setup_path("cn=samba.ldif"), os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"), -- cgit From 45d60f5bd9be53ae4d4399664500709f1b2801a5 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 28 Jul 2008 20:18:17 +1000 Subject: Always print the slapd startup command (This used to be commit b1d05e7d14c65133e8ab0ff9d41a26fa7e3d41d3) --- source4/scripting/python/samba/provision.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 068fe5ad9b..8437909da1 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1290,7 +1290,8 @@ def provision_backend(setup_dir=None, message=None, server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port else: server_port_string = "" - slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string + + slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) -- cgit From 08795db6d6af69442dfbfa7d39532e898d4c0ea6 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 28 Jul 2008 20:26:14 +1000 Subject: Make it even clearer what to do next in the LDAP backend setup (This used to be commit bace931ad674b5071d53bf9c99c383f1d8957e1b) --- source4/scripting/python/samba/provision.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 8437909da1..13329e8b10 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1232,6 +1232,8 @@ def provision_backend(setup_dir=None, message=None, slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf + ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn + elif ldap_backend_type == "openldap": attrs = ["linkID", "lDAPDisplayName"] res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs) @@ -1293,6 +1295,8 @@ def provision_backend(setup_dir=None, message=None, slapdcommand="Start slapd with: slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string + ldapuser = "--username=samba-admin" + schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) @@ -1311,7 +1315,7 @@ def provision_backend(setup_dir=None, message=None, message("LDAP admin password: %s" % adminpass) message(slapdcommand) - + message("Run provision with: --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser) def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. -- cgit From e80115deb9f57d827f915b57b52961f1e2df682e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 28 Jul 2008 20:51:02 +1000 Subject: We don't use EXTENSIBLEOBJECT any more. (This used to be commit 4b137085c8b89773d4639372bbffd516a41dfc8f) --- source4/scripting/python/samba/provision.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 13329e8b10..441d662b23 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -779,7 +779,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), { "CONFIGDN": names.configdn, "ACI": aci, - "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", }) message("Modifying configuration container") setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), { @@ -791,7 +790,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), { "SCHEMADN": names.schemadn, "ACI": aci, - "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) message("Modifying schema container") @@ -1189,7 +1187,6 @@ def provision_backend(setup_dir=None, message=None, setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"), {"SCHEMADN": names.schemadn, "ACI": "#", - "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" }) setup_modify_ldif(schemadb, setup_path("provision_schema_basedn_modify.ldif"), \ -- cgit From 3573420d7d108d796e0b424c131061dc74c23033 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 1 Aug 2008 20:17:29 +0200 Subject: Fix some forgotten substitute variables in provision, add check to prevent this sort of regression in the future. (This used to be commit a461118f3b668779f907c4d77cebe1e76fa4e39f) --- source4/scripting/python/samba/provision.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0119f40c7f..33aeff2008 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1453,6 +1453,7 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): schema_data = open(setup_path("schema.ldif"), 'r').read() schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) + check_all_substituted(schema_data) prefixmap = open(setup_path("prefixMap.txt"), 'r').read() prefixmap = b64encode(prefixmap) @@ -1464,5 +1465,6 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): "DEFAULTSITE":sitename, "PREFIXMAP_B64":prefixmap }) + check_all_substituted(head_data) samdb.attach_schema_from_ldif(head_data, schema_data) -- cgit From 3b4ff07ded89703b2a58ae2c9ca6f0ea82bb5a52 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 1 Aug 2008 20:47:03 +0200 Subject: Actually fix missing substitution variables. (This used to be commit 783412ecb27d646b171993da0ac2f11a821901d3) --- source4/scripting/python/samba/provision.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6b1fd33b9f..6dd9f3b8bd 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -739,7 +739,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb.set_invocation_id(invocationid) load_schema(setup_path, samdb, names.schemadn, names.netbiosname, - names.configdn, names.sitename) + names.configdn, names.sitename, names.serverdn, + names.hostname) samdb.transaction_start() @@ -1423,7 +1424,8 @@ def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): }) -def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): +def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename, + serverdn, servername): """Load schema for the SamDB. :param samdb: Load a schema into a SamDB. @@ -1431,6 +1433,8 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): :param schemadn: DN of the schema :param netbiosname: NetBIOS name of the host. :param configdn: DN of the configuration + :param serverdn: DN of the server + :param servername: Host name of the server """ schema_data = open(setup_path("schema.ldif"), 'r').read() schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() @@ -1444,8 +1448,10 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): "SCHEMADN": schemadn, "NETBIOSNAME": netbiosname, "CONFIGDN": configdn, - "DEFAULTSITE":sitename, - "PREFIXMAP_B64":prefixmap + "DEFAULTSITE": sitename, + "PREFIXMAP_B64": prefixmap, + "SERVERDN": serverdn, + "SERVERNAME": servername, }) check_all_substituted(head_data) samdb.attach_schema_from_ldif(head_data, schema_data) -- cgit From fff006bd84fc3fd1d9fdd22e3c20110285b2c144 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 1 Aug 2008 20:47:22 +0200 Subject: Move domain DN determination out of newuser function. (This used to be commit cbac27e6faa99ebaa3e6d653017c968db836560a) --- source4/scripting/python/samba/samdb.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index c47cf4a0dc..c7d93d6aff 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -86,6 +86,14 @@ userAccountControl: %u """ % (user_dn, userAccountControl) self.modify_ldif(mod) + def domain_dn(self): + # find the DNs for the domain and the domain users group + res = self.search("", scope=ldb.SCOPE_BASE, + expression="(defaultNamingContext=*)", + attrs=["defaultNamingContext"]) + assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None) + return res[0]["defaultNamingContext"][0] + def newuser(self, username, unixname, password): """add a new user record. @@ -96,12 +104,7 @@ userAccountControl: %u # connect to the sam self.transaction_start() - # find the DNs for the domain and the domain users group - res = self.search("", scope=ldb.SCOPE_BASE, - expression="(defaultNamingContext=*)", - attrs=["defaultNamingContext"]) - assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None) - domain_dn = res[0]["defaultNamingContext"][0] + domain_dn = self.domain_dn() assert(domain_dn is not None) user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) -- 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/provision.py | 8 +++++--- source4/scripting/python/samba/samba3.py | 14 ++++++++------ source4/scripting/python/samba/samr.py | 8 +++++++- source4/scripting/python/samba/tests/dcerpc/bare.py | 1 + source4/scripting/python/samba/tests/dcerpc/registry.py | 1 + source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 2 ++ source4/scripting/python/samba/tests/provision.py | 2 +- source4/scripting/python/samba/tests/samba3.py | 1 + 8 files changed, 26 insertions(+), 11 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 6dd9f3b8bd..4f7fbfc6e6 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -53,7 +53,7 @@ class InvalidNetbiosName(Exception): super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name) -class ProvisionPaths: +class ProvisionPaths(object): def __init__(self): self.shareconf = None self.hklm = None @@ -77,7 +77,8 @@ class ProvisionPaths: self.fedoradsinf = None self.fedoradspartitions = None -class ProvisionNames: + +class ProvisionNames(object): def __init__(self): self.rootdn = None self.domaindn = None @@ -92,7 +93,8 @@ class ProvisionNames: self.sitename = None self.smbconf = None -class ProvisionResult: + +class ProvisionResult(object): def __init__(self): self.paths = None self.domaindn = None 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. diff --git a/source4/scripting/python/samba/samr.py b/source4/scripting/python/samba/samr.py index 314f78b8ad..62a7c6eb3d 100644 --- a/source4/scripting/python/samba/samr.py +++ b/source4/scripting/python/samba/samr.py @@ -97,7 +97,8 @@ def call_fn(fn, pipe, args): return result; -class SamrHandle: + +class SamrHandle(object): def __init__(self, pipe, handle): @@ -137,6 +138,7 @@ class SamrHandle: call_fn(dcerpc.dcerpc_samr_SetSecurity, self.pipe, r) + class ConnectHandle(SamrHandle): def EnumDomains(self): @@ -212,6 +214,7 @@ class ConnectHandle(SamrHandle): call_fn(dcerpc.dcerpc_samr_SetBootKeyInformation, self.pipe, r) + class DomainHandle(SamrHandle): def QueryDomainInfo(self, level = 2): @@ -517,6 +520,7 @@ class DomainHandle(SamrHandle): call_fn(dcerpc.dcerpc_samr_TestPrivateFunctionsDomain, self.pipe, r) + class UserHandle(SamrHandle): def DeleteUser(self): @@ -576,6 +580,7 @@ class UserHandle(SamrHandle): call_fn(dcerpc.dcerpc_samr_TestPrivateFunctionsUser, self.pipe, r) + class GroupHandle(SamrHandle): def QueryGroupInfo(self, level): @@ -608,6 +613,7 @@ class GroupHandle(SamrHandle): dcerpc.uint32_array_getitem(r.data_out.rids.unknown, x)) for x in range(r.data_out.rids.count)] + class AliasHandle(SamrHandle): def DeleteDomAlias(self): diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py index fae699a249..cd939b8098 100644 --- a/source4/scripting/python/samba/tests/dcerpc/bare.py +++ b/source4/scripting/python/samba/tests/dcerpc/bare.py @@ -22,6 +22,7 @@ from samba.dcerpc import ClientConnection from unittest import TestCase from samba.tests import cmdline_loadparm + class BareTestCase(TestCase): def test_bare(self): # Connect to the echo pipe diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py index 81133ff641..526b2340cc 100644 --- a/source4/scripting/python/samba/tests/dcerpc/registry.py +++ b/source4/scripting/python/samba/tests/dcerpc/registry.py @@ -21,6 +21,7 @@ from samba.dcerpc import winreg import unittest from samba.tests import RpcInterfaceTestCase + class WinregTests(RpcInterfaceTestCase): def setUp(self): self.conn = winreg.winreg("ncalrpc:", self.get_loadparm(), diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index 96bb3923a6..12638e2397 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -22,6 +22,7 @@ from samba.ndr import ndr_pack, ndr_unpack import unittest from samba.tests import RpcInterfaceTestCase + class RpcEchoTests(RpcInterfaceTestCase): def setUp(self): self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm()) @@ -56,6 +57,7 @@ class RpcEchoTests(RpcInterfaceTestCase): def test_server_name(self): self.assertEquals(None, self.conn.server_name) + class NdrEchoTests(unittest.TestCase): def test_info1_push(self): x = echo.info1() diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py index 76c10145f0..352357f694 100644 --- a/source4/scripting/python/samba/tests/provision.py +++ b/source4/scripting/python/samba/tests/provision.py @@ -87,7 +87,7 @@ class FindNssTests(unittest.TestCase): self.assertEquals("ha", findnss(x, ["bloe", "bla"])) -class Disabled: +class Disabled(object): def test_setup_templatesdb(self): raise NotImplementedError(self.test_setup_templatesdb) diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py index 175aa90497..1755cbdcf0 100644 --- a/source4/scripting/python/samba/tests/samba3.py +++ b/source4/scripting/python/samba/tests/samba3.py @@ -153,6 +153,7 @@ class WinsDatabaseTestCase(unittest.TestCase): def tearDown(self): self.winsdb.close() + class SmbpasswdTestCase(unittest.TestCase): def setUp(self): self.samdb = SmbpasswdFile(os.path.join(DATADIR, "smbpasswd")) -- cgit From 47124efe420f4f4f08494cbb2255eacdc9625c8d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 1 Aug 2008 21:12:37 +0200 Subject: Add helper object Hostconfig to make it easier to get to e.g. the SAM database. (This used to be commit be75b2a36ee49f66ada3ec3ababa82d74085d559) --- source4/scripting/python/samba/getopt.py | 4 ++++ source4/scripting/python/samba/hostconfig.py | 33 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 source4/scripting/python/samba/hostconfig.py (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py index 9ecb66e21c..c12245f6c5 100644 --- a/source4/scripting/python/samba/getopt.py +++ b/source4/scripting/python/samba/getopt.py @@ -21,6 +21,7 @@ import optparse from credentials import Credentials, AUTO_USE_KERBEROS, DONT_USE_KERBEROS, MUST_USE_KERBEROS +from hostconfig import Hostconfig __docformat__ = "restructuredText" @@ -52,6 +53,9 @@ class SambaOptions(optparse.OptionGroup): lp.load_default() return lp + def get_hostconfig(self): + return Hostconfig(self.get_loadparm()) + class VersionOptions(optparse.OptionGroup): """Command line option for printing Samba version.""" diff --git a/source4/scripting/python/samba/hostconfig.py b/source4/scripting/python/samba/hostconfig.py new file mode 100644 index 0000000000..313e3420b0 --- /dev/null +++ b/source4/scripting/python/samba/hostconfig.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij 2008 +# +# 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 . +# + +from samdb import SamDB + +class Hostconfig(object): + """Aggregate object that contains all information about the configuration + of a Samba host.""" + + def __init__(self, lp): + self.lp = lp + + def get_samdb(self, session_info, credentials): + return SamDB(url=self.lp.get("sam database"), + session_info=session_info, credentials=credentials, + lp=self.lp) + -- cgit From 47d80366bef5e62b6727a574b2300cc94a2e18f7 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 19 Aug 2008 11:43:41 +1000 Subject: Fix templates.ldb reprovision handling. This sets the attributes in a seperate transaction, and allows a forced delete of the whole file. Andrew Bartlett (This used to be commit 423db2468ba3dac89cebc59c8498c0b08c5f3d7b) --- source4/scripting/python/samba/provision.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 4f7fbfc6e6..836509a620 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -617,7 +617,17 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp): """ templates_ldb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) - templates_ldb.erase() + # Wipes the database + try: + templates_ldb.erase() + except: + os.unlink(path) + + templates_ldb.load_ldif_file_add(setup_path("provision_templates_init.ldif")) + + templates_ldb = SamDB(path, session_info=session_info, + credentials=credentials, lp=lp) + templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif")) -- cgit From 805dd85291fa55695ee7ae2b8f6d3c168d9186e8 Mon Sep 17 00:00:00 2001 From: Oliver Liebel Date: Tue, 19 Aug 2008 12:03:04 +1000 Subject: Generate Multi-Master Replication configuration for OpenLDAP This patches provision-backend and the related scripts to generate the correct configuration blobs for N-way multi-master replication using OpenLDAP. Signed-off-by: Andrew Bartlett (This used to be commit 6ed0b3f2475022288f636605492ca27fde97cd52) --- source4/scripting/python/samba/provision.py | 86 ++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 7 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 4f7fbfc6e6..8abcc2f2e3 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -76,7 +76,9 @@ class ProvisionPaths(object): self.memberofconf = None self.fedoradsinf = None self.fedoradspartitions = None - + self.olmmron = None + self.olmmrserveridsconf = None + self.olmmrsyncreplconf = None class ProvisionNames(object): def __init__(self): @@ -242,8 +244,12 @@ def provision_paths_from_lp(lp, dnsdomain): "memberof.conf") paths.fedoradsinf = os.path.join(paths.ldapdir, "fedorads.inf") - paths.fedoradspartitions = os.path.join(paths.ldapdir, - "fedorads-partitions.ldif") + paths.olmmrserveridsconf = os.path.join(paths.ldapdir, + "mmr_serverids.conf") + paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, + "mmr_syncrepl.conf") + paths.olmmron = os.path.join(paths.ldapdir, + "mmr_on.conf") paths.hklm = "hklm.ldb" paths.hkcr = "hkcr.ldb" paths.hkcu = "hkcu.ldb" @@ -331,7 +337,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole= names.hostname = hostname names.sitename = sitename names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn) - + return names @@ -1141,7 +1147,11 @@ def provision_backend(setup_dir=None, message=None, smbconf=None, targetdir=None, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, adminpass=None, root=None, serverrole=None, - ldap_backend_type=None, ldap_backend_port=None): + ldap_backend_type=None, ldap_backend_port=None, + ol_mmr_urls=None, mmr_serverids_config=None, mmr_on_config=None, + mmr_syncrepl_schema_config=None, + mmr_syncrepl_config_config=None, + mmr_syncrepl_user_config=None ): def setup_path(file): return os.path.join(setup_dir, file) @@ -1255,7 +1265,64 @@ def provision_backend(setup_dir=None, message=None, refint_config = read_and_sub_file(setup_path("refint.conf"), { "LINK_ATTRS" : refint_attributes}) - + +######################################################## +### generate serverids and ldap-urls for mmr hosts ### +######################################################## + + mmr_on_config = " " + mmr_serverids_config = " " + + if ol_mmr_urls is not None: + mmr_hosts=ol_mmr_urls + mmr_hosts=filter(None,mmr_hosts.split(' ')) + + mmr_serverids_config = "# Generated from template mmr_serverids.conf\n" + z=0 + for i in mmr_hosts: + z=z+1 + mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"), + { "SERVERID" : str(z), + "LDAPSERVER" : i }) + mmr_on_config = "MirrorMode On" + +######################################################## +### generate syncrepl-blocks for mmr hosts ### +######################################################## + + mmr_syncrepl_schema_config = " " + mmr_syncrepl_config_config = " " + mmr_syncrepl_user_config = " " + + if ol_mmr_urls is not None: + mmr_hosts=ol_mmr_urls + mmr_hosts=filter(None,mmr_hosts.split(' ')) + mmr_syncrepl_schema_config = "# Generated from template mmr_syncrepl.conf\n" + mmr_syncrepl_config_config = "# Generated from template mmr_syncrepl.conf\n" + mmr_syncrepl_user_config = "# Generated from template mmr_syncrepl.conf\n" + z=0 + for i in mmr_hosts: + z=z+1 + mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), + { "RID" : str(z), + "MMRDN": names.schemadn, + "LDAPSERVER" : i }) + + for i in mmr_hosts: + z=z+1 + mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), + { "RID" : str(z), + "MMRDN": names.configdn, + "LDAPSERVER" : i }) + + for i in mmr_hosts: + z=z+1 + mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), + { "RID" : str(z), + "MMRDN": names.domaindn, + "LDAPSERVER" : i }) + + setup_file(setup_path("slapd.conf"), paths.slapdconf, {"DNSDOMAIN": names.dnsdomain, "LDAPDIR": paths.ldapdir, @@ -1263,8 +1330,13 @@ def provision_backend(setup_dir=None, message=None, "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, "MEMBEROF_CONFIG": memberof_config, + "MIRRORMODE": mmr_on_config, + "MMR_SERVERIDS_CONFIG": mmr_serverids_config, + "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config, + "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config, + "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config, "REFINT_CONFIG": refint_config}) - setup_file(setup_path("modules.conf"), paths.modulesconf, + setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user")) -- cgit From 7ef21658fbb519859aa7d23a614e1fdbcae95693 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 19 Aug 2008 14:10:14 +1000 Subject: Fix up new OpenLDAP MMR code. This changes the MMR password from hard-coded value of 'linux', adds tests and fixes the Fedora DS backend. Currently the MMR password matches the admin password, but we can change this to be another random value if required. Also require the port to be specified on the command line, so we don't hard-code a port of 9000. Andrew Bartlett (This used to be commit 08257c6d6ce809fcd53f9b2b4d558fef616b74ce) --- source4/scripting/python/samba/provision.py | 67 +++++++++++------------------ 1 file changed, 26 insertions(+), 41 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 8abcc2f2e3..f48a49dcfa 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -243,13 +243,13 @@ def provision_paths_from_lp(lp, dnsdomain): paths.memberofconf = os.path.join(paths.ldapdir, "memberof.conf") paths.fedoradsinf = os.path.join(paths.ldapdir, - "fedorads.inf") + "fedorads.inf") + paths.fedoradspartitions = os.path.join(paths.ldapdir, + "fedorads-partitions.ldif") paths.olmmrserveridsconf = os.path.join(paths.ldapdir, - "mmr_serverids.conf") + "mmr_serverids.conf") paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, - "mmr_syncrepl.conf") - paths.olmmron = os.path.join(paths.ldapdir, - "mmr_on.conf") + "mmr_syncrepl.conf") paths.hklm = "hklm.ldb" paths.hkcr = "hkcr.ldb" paths.hkcu = "hkcu.ldb" @@ -1148,10 +1148,7 @@ def provision_backend(setup_dir=None, message=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, adminpass=None, root=None, serverrole=None, ldap_backend_type=None, ldap_backend_port=None, - ol_mmr_urls=None, mmr_serverids_config=None, mmr_on_config=None, - mmr_syncrepl_schema_config=None, - mmr_syncrepl_config_config=None, - mmr_syncrepl_user_config=None ): + ol_mmr_urls=None): def setup_path(file): return os.path.join(setup_dir, file) @@ -1266,61 +1263,48 @@ def provision_backend(setup_dir=None, message=None, refint_config = read_and_sub_file(setup_path("refint.conf"), { "LINK_ATTRS" : refint_attributes}) -######################################################## -### generate serverids and ldap-urls for mmr hosts ### -######################################################## - - mmr_on_config = " " - mmr_serverids_config = " " - +# generate serverids, ldap-urls and syncrepl-blocks for mmr hosts + mmr_on_config = "" + mmr_serverids_config = "" + mmr_syncrepl_schema_config = "" + mmr_syncrepl_config_config = "" + mmr_syncrepl_user_config = "" + if ol_mmr_urls is not None: - mmr_hosts=ol_mmr_urls - mmr_hosts=filter(None,mmr_hosts.split(' ')) + mmr_hosts=filter(None,ol_mmr_urls.split(' ')) + if (len(mmr_hosts) == 1): + mmr_hosts=filter(None,ol_mmr_urls.split(',')) + + + mmr_on_config = "MirrorMode On" - mmr_serverids_config = "# Generated from template mmr_serverids.conf\n" z=0 for i in mmr_hosts: z=z+1 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"), { "SERVERID" : str(z), "LDAPSERVER" : i }) - mmr_on_config = "MirrorMode On" - -######################################################## -### generate syncrepl-blocks for mmr hosts ### -######################################################## - mmr_syncrepl_schema_config = " " - mmr_syncrepl_config_config = " " - mmr_syncrepl_user_config = " " - - if ol_mmr_urls is not None: - mmr_hosts=ol_mmr_urls - mmr_hosts=filter(None,mmr_hosts.split(' ')) - mmr_syncrepl_schema_config = "# Generated from template mmr_syncrepl.conf\n" - mmr_syncrepl_config_config = "# Generated from template mmr_syncrepl.conf\n" - mmr_syncrepl_user_config = "# Generated from template mmr_syncrepl.conf\n" - z=0 - for i in mmr_hosts: z=z+1 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), { "RID" : str(z), "MMRDN": names.schemadn, - "LDAPSERVER" : i }) + "LDAPSERVER" : i, + "MMR_PASSWORD": adminpass}) - for i in mmr_hosts: z=z+1 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), { "RID" : str(z), "MMRDN": names.configdn, - "LDAPSERVER" : i }) + "LDAPSERVER" : i, + "MMR_PASSWORD": adminpass}) - for i in mmr_hosts: z=z+1 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), { "RID" : str(z), "MMRDN": names.domaindn, - "LDAPSERVER" : i }) + "LDAPSERVER" : i, + "MMR_PASSWORD": adminpass }) setup_file(setup_path("slapd.conf"), paths.slapdconf, @@ -1335,6 +1319,7 @@ def provision_backend(setup_dir=None, message=None, "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config, "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config, "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config, + "MMR_PASSWORD": adminpass, "REFINT_CONFIG": refint_config}) setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) -- cgit From 41493cbe680e0b8dff3b84937b3005c72c39dec6 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 20 Aug 2008 12:21:36 +1000 Subject: Update OpenLDAP MMR configuration per comments by Oliver Liebel This changes the RIDs to be , to ease later debugging. The need to specify the port on the MMR URLs is now included in the help. Andrew Bartlett (This used to be commit a5cbe8c09c6f14f95ff9ba9b8782e2100fc55695) --- source4/scripting/python/samba/provision.py | 37 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 0855efe3bb..d14ce58f04 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1281,39 +1281,38 @@ def provision_backend(setup_dir=None, message=None, mmr_syncrepl_user_config = "" if ol_mmr_urls is not None: - mmr_hosts=filter(None,ol_mmr_urls.split(' ')) - if (len(mmr_hosts) == 1): - mmr_hosts=filter(None,ol_mmr_urls.split(',')) + url_list=filter(None,ol_mmr_urls.split(' ')) + if (len(url_list) == 1): + url_list=filter(None,ol_mmr_urls.split(',')) mmr_on_config = "MirrorMode On" - - z=0 - for i in mmr_hosts: - z=z+1 + serverid=0 + for url in url_list: + serverid=serverid+1 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"), - { "SERVERID" : str(z), - "LDAPSERVER" : i }) - - z=z+1 + { "SERVERID" : str(serverid), + "LDAPSERVER" : url }) + rid=serverid*10 + rid=rid+1 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), - { "RID" : str(z), + { "RID" : str(rid), "MMRDN": names.schemadn, - "LDAPSERVER" : i, + "LDAPSERVER" : url, "MMR_PASSWORD": adminpass}) - z=z+1 + rid=rid+1 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), - { "RID" : str(z), + { "RID" : str(rid), "MMRDN": names.configdn, - "LDAPSERVER" : i, + "LDAPSERVER" : url, "MMR_PASSWORD": adminpass}) - z=z+1 + rid=rid+1 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), - { "RID" : str(z), + { "RID" : str(rid), "MMRDN": names.domaindn, - "LDAPSERVER" : i, + "LDAPSERVER" : url, "MMR_PASSWORD": adminpass }) -- cgit From 8237c0ba83e2b47bb7879ba68d3a50da887397b6 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 21 Aug 2008 12:59:16 +1000 Subject: The index handling is now configured from the schema load, not by a template. Andrew Bartlett (This used to be commit b36c6a21ad12fdc1b53efdc3f29cde7614b4fa9e) --- source4/scripting/python/samba/provision.py | 9 --------- 1 file changed, 9 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d14ce58f04..9c2a208460 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -745,12 +745,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) - if fill == FILL_DRS: - # We want to finish here, but setup the index before we do so - message("Setting up sam.ldb index") - samdb.load_ldif_file_add(setup_path("provision_index.ldif")) - return samdb - message("Pre-loading the Samba 4 and AD schema") samdb.set_domain_sid(domainsid) if serverrole == "domain controller": @@ -886,9 +880,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, domainsid=domainsid, policyguid=policyguid, setup_path=setup_path) - #We want to setup the index last, as adds are faster unindexed - message("Setting up sam.ldb index") - samdb.load_ldif_file_add(setup_path("provision_index.ldif")) except: samdb.transaction_cancel() raise -- cgit From 9817f3d785ceb67819a9def0e8030272e4ba9e14 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 30 Aug 2008 07:32:44 +1000 Subject: Add a setexpiry operation in samdb.py This makes it easy to set the expiry (or no expiry) for a samdb user (This used to be commit 25171f18a4b242b5a731f4ac1eefc51cc82efd74) --- source4/scripting/python/samba/samdb.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index c7d93d6aff..4a64c2f76d 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -27,6 +27,7 @@ import misc import ldb from samba.idmap import IDmapDB import pwd +import time __docformat__ = "restructuredText" @@ -192,3 +193,35 @@ userPassword: %s :param invocation_id: GUID of the invocation id. """ misc.dsdb_set_ntds_invocation_id(self, invocation_id) + + def setexpiry(self, user, expiry_seconds, noexpiry): + """Set the password expiry for a user + + :param expiry_seconds: expiry time from now in seconds + :param noexpiry: if set, then don't expire password + """ + self.transaction_start(); + res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE, + expression=("(samAccountName=%s)" % user), + attrs=["userAccountControl", "accountExpires"]) + assert len(res) == 1 + userAccountControl = int(res[0]["userAccountControl"][0]) + accountExpires = int(res[0]["accountExpires"][0]) + if noexpiry: + userAccountControl = userAccountControl | 0x10000 + accountExpires = 0 + else: + userAccountControl = userAccountControl & ~0x10000 + accountExpires = misc.unix2nttime(expiry_seconds + int(time.time())) + + mod = """ +dn: %s +changetype: modify +replace: userAccountControl +userAccountControl: %u +replace: accountExpires +accountExpires: %u +""" % (res[0].dn, userAccountControl, accountExpires) + # now change the database + self.modify_ldif(mod) + self.transaction_commit(); -- cgit From b76f383eefe961e8a2f42ac782031e3e09ff7192 Mon Sep 17 00:00:00 2001 From: Oliver Liebel Date: Mon, 8 Sep 2008 14:39:54 +1000 Subject: Use DIGEST-MD5 authentication for OpenLDAP replication This avoids passing rootdn passwords or replicated data in cleartext across the network. Signed-of-by: Andrew Bartlett (This used to be commit 67373c143a1d8a9f310fd116dbf81c1dd123b75f) --- source4/scripting/python/samba/provision.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 9c2a208460..f37d09d5e0 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1266,6 +1266,7 @@ def provision_backend(setup_dir=None, message=None, # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts mmr_on_config = "" + mmr_replicator_acl = "" mmr_serverids_config = "" mmr_syncrepl_schema_config = "" mmr_syncrepl_config_config = "" @@ -1278,6 +1279,7 @@ def provision_backend(setup_dir=None, message=None, mmr_on_config = "MirrorMode On" + mmr_replicator_acl = " by dn=cn=replicator,cn=samba read" serverid=0 for url in url_list: serverid=serverid+1 @@ -1315,6 +1317,7 @@ def provision_backend(setup_dir=None, message=None, "SCHEMADN": names.schemadn, "MEMBEROF_CONFIG": memberof_config, "MIRRORMODE": mmr_on_config, + "REPLICATOR_ACL": mmr_replicator_acl, "MMR_SERVERIDS_CONFIG": mmr_serverids_config, "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config, "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config, @@ -1340,6 +1343,15 @@ def provision_backend(setup_dir=None, message=None, {"LDAPADMINPASS_B64": b64encode(adminpass), "UUID": str(uuid.uuid4()), "LDAPTIME": timestring(int(time.time()))} ) + + if ol_mmr_urls is not None: + setup_file(setup_path("cn=replicator.ldif"), + os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"), + {"LDAPADMINPASS_B64": b64encode(adminpass), + "UUID": str(uuid.uuid4()), + "LDAPTIME": timestring(int(time.time()))} ) + + mapping = "schema-map-openldap-2.3" backend_schema = "backend-schema.schema" -- cgit From ef9169bfa6fcaa682ff5baf729301dd63f6bb029 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 8 Sep 2008 15:09:06 +1000 Subject: Make it clear that the MMR password can differ from the admin passsword In the future, we might simply randomly generate this, or allow the admin to specify it seperate to the admin password. However, both are highly sensitive, as they imply read access to the krbtgt. Andrew Bartlett (This used to be commit 57d19ad002c523fb9a09694e6710ab7f588d44ec) --- source4/scripting/python/samba/provision.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'source4/scripting/python/samba') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f37d09d5e0..68f61532ad 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -1273,7 +1273,10 @@ def provision_backend(setup_dir=None, message=None, mmr_syncrepl_user_config = "" if ol_mmr_urls is not None: - url_list=filter(None,ol_mmr_urls.split(' ')) + # For now, make these equal + mmr_pass = adminpass + + url_list=filter(None,ol_mmr_urls.split(' ')) if (len(url_list) == 1): url_list=filter(None,ol_mmr_urls.split(',')) @@ -1292,21 +1295,21 @@ def provision_backend(setup_dir=None, message=None, { "RID" : str(rid), "MMRDN": names.schemadn, "LDAPSERVER" : url, - "MMR_PASSWORD": adminpass}) + "MMR_PASSWORD": mmr_pass}) rid=rid+1 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), { "RID" : str(rid), "MMRDN": names.configdn, "LDAPSERVER" : url, - "MMR_PASSWORD": adminpass}) + "MMR_PASSWORD": mmr_pass}) rid=rid+1 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"), { "RID" : str(rid), "MMRDN": names.domaindn, "LDAPSERVER" : url, - "MMR_PASSWORD": adminpass }) + "MMR_PASSWORD": mmr_pass }) setup_file(setup_path("slapd.conf"), paths.slapdconf, @@ -1322,7 +1325,6 @@ def provision_backend(setup_dir=None, message=None, "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config, "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config, "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config, - "MMR_PASSWORD": adminpass, "REFINT_CONFIG": refint_config}) setup_file(setup_path("modules.conf"), paths.modulesconf, {"REALM": names.realm}) @@ -1347,7 +1349,7 @@ def provision_backend(setup_dir=None, message=None, if ol_mmr_urls is not None: setup_file(setup_path("cn=replicator.ldif"), os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"), - {"LDAPADMINPASS_B64": b64encode(adminpass), + {"MMR_PASSWORD_B64": b64encode(mmr_pass), "UUID": str(uuid.uuid4()), "LDAPTIME": timestring(int(time.time()))} ) -- cgit