From d7a46ee129c455cba95126e9c0f409522127894e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 8 Apr 2010 18:57:09 +0200 Subject: s4-python: Simplify code, improve formatting. --- source4/scripting/bin/upgradeprovision | 42 +++-- .../scripting/python/samba/netcmd/domainlevel.py | 2 +- source4/scripting/python/samba/netcmd/dsacl.py | 21 ++- source4/scripting/python/samba/provision.py | 89 ++++++---- source4/scripting/python/samba/provisionbackend.py | 190 +++++++++------------ .../scripting/python/samba/provisionexceptions.py | 38 ----- source4/scripting/python/samba/upgradehelpers.py | 48 +++--- source4/setup/provision | 13 +- 8 files changed, 208 insertions(+), 235 deletions(-) delete mode 100644 source4/scripting/python/samba/provisionexceptions.py (limited to 'source4') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 234152b002..a900728ed4 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -40,8 +40,7 @@ from ldb import SCOPE_SUBTREE, SCOPE_BASE, \ MessageElement, Message, Dn from samba import param from samba.misc import messageEltFlagToString -from samba.provision import find_setup_dir, get_domain_descriptor, get_config_descriptor, secretsdb_self_join,set_gpo_acl,getpolicypath,create_gpo_struct -from samba.provisionexceptions import ProvisioningError +from samba.provision import find_setup_dir, get_domain_descriptor, get_config_descriptor, secretsdb_self_join,set_gpo_acl,getpolicypath,create_gpo_struct, ProvisioningError from samba.schema import get_linked_attributes, Schema, get_schema_descriptor from samba.dcerpc import security from samba.ndr import ndr_unpack @@ -321,16 +320,22 @@ def handle_special_case(att, delta, new, old, ischema): def update_secrets(newpaths, paths, creds, session): """Update secrets.ldb - :param newpaths: a list of paths for different provision objects from the reference provision - :param paths: a list of paths for different provision objects from the upgraded provision + :param newpaths: a list of paths for different provision objects from the + reference provision + :param paths: a list of paths for different provision objects from the + upgraded provision :param creds: credential for the authentification :param session: session for connexion""" message(SIMPLE,"update secrets.ldb") - newsecrets_ldb = Ldb(newpaths.secrets, session_info=session, credentials=creds,lp=lp) - secrets_ldb = Ldb(paths.secrets, session_info=session, credentials=creds,lp=lp, options=["modules:samba_secrets"]) - reference = newsecrets_ldb.search(expression="dn=@MODULES",base="", scope=SCOPE_SUBTREE) - current = secrets_ldb.search(expression="dn=@MODULES",base="", scope=SCOPE_SUBTREE) + newsecrets_ldb = Ldb(newpaths.secrets, session_info=session, + credentials=creds,lp=lp) + secrets_ldb = Ldb(paths.secrets, session_info=session, + credentials=creds,lp=lp, options=["modules:samba_secrets"]) + reference = newsecrets_ldb.search(expression="dn=@MODULES",base="", + scope=SCOPE_SUBTREE) + current = secrets_ldb.search(expression="dn=@MODULES",base="", + scope=SCOPE_SUBTREE) delta = secrets_ldb.msg_diff(current[0],reference[0]) delta.dn = current[0].dn secrets_ldb.modify(delta) @@ -449,7 +454,8 @@ def handle_special_add(sam_ldb,dn,names): message(CHANGE,"Existing object %s must be replaced by %s, removing old object"%(dntoremove,str(dn))) sam_ldb.delete(res[0]["dn"]) -def check_dn_nottobecreated(hash,index,listdn): + +def check_dn_nottobecreated(hash, index, listdn): """Check if one of the DN present in the list has a creation order greater than the current. Hash is indexed by dn to be created, with each key is associated the creation order @@ -780,22 +786,22 @@ def update_basesamdb(newpaths, paths, names): shutil.copy(newpaths.samdb,paths.samdb) message(SIMPLE,"Update partitions filename if needed") - schemaldb=os.path.join(paths.private_dir,"schema.ldb") - configldb=os.path.join(paths.private_dir,"configuration.ldb") - usersldb=os.path.join(paths.private_dir,"users.ldb") - samldbdir=os.path.join(paths.private_dir,"sam.ldb.d") + schemaldb = os.path.join(paths.private_dir, "schema.ldb") + configldb = os.path.join(paths.private_dir, "configuration.ldb") + usersldb = os.path.join(paths.private_dir, "users.ldb") + samldbdir = os.path.join(paths.private_dir, "sam.ldb.d") if not os.path.isdir(samldbdir): os.mkdir(samldbdir) os.chmod(samldbdir,0700) if os.path.isfile(schemaldb): - shutil.copy(schemaldb, os.path.join(samldbdir, "%s.ldb"%str(names.schemadn).upper())) + shutil.copy(schemaldb, os.path.join(samldbdir, "%s.ldb" % str(names.schemadn).upper())) os.remove(schemaldb) if os.path.isfile(usersldb): - shutil.copy(usersldb, os.path.join(samldbdir, "%s.ldb"%str(names.rootdn).upper())) + shutil.copy(usersldb, os.path.join(samldbdir, "%s.ldb" % str(names.rootdn).upper())) os.remove(usersldb) if os.path.isfile(configldb): - shutil.copy(configldb, os.path.join(samldbdir, "%s.ldb"%str(names.configdn).upper())) + shutil.copy(configldb, os.path.join(samldbdir, "%s.ldb" % str(names.configdn).upper())) os.remove(configldb) @@ -834,7 +840,8 @@ def update_machine_account_password(paths, creds, session, names): :param session: Session for connexion :param names: List of key provision parameters""" - secrets_ldb = Ldb(paths.secrets, session_info=session, credentials=creds,lp=lp) + secrets_ldb = Ldb(paths.secrets, session_info=session, + credentials=creds,lp=lp) secrets_ldb.transaction_start() secrets_msg = secrets_ldb.search(expression=("samAccountName=%s$" % names.netbiosname), attrs=["secureChannelType"]) sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp) @@ -885,6 +892,7 @@ def update_gpo(paths,creds,session,names): set_gpo_acl(paths.sysvol, names.dnsdomain, names.domainsid, names.domaindn, samdb, lp) + def updateOEMInfo(paths, creds, session,names): sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp, options=["modules:samba_dsdb"]) diff --git a/source4/scripting/python/samba/netcmd/domainlevel.py b/source4/scripting/python/samba/netcmd/domainlevel.py index c97ed7bad6..1874191e1f 100644 --- a/source4/scripting/python/samba/netcmd/domainlevel.py +++ b/source4/scripting/python/samba/netcmd/domainlevel.py @@ -114,7 +114,7 @@ class cmd_domainlevel(Command): raise CommandError("Could not retrieve the actual domain, forest level and/or lowest DC function level!") if subcommand == "show": - self.message("Domain and forest function level for domain '" + domain_dn + "'") + self.message("Domain and forest function level for domain '%s'" % domain_dn) if level_forest < DS_DOMAIN_FUNCTION_2003: self.message("\nATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2003 (Native). This isn't supported! Please raise!") if level_domain < DS_DOMAIN_FUNCTION_2003: diff --git a/source4/scripting/python/samba/netcmd/dsacl.py b/source4/scripting/python/samba/netcmd/dsacl.py index 58fb9c611a..17982b8119 100644 --- a/source4/scripting/python/samba/netcmd/dsacl.py +++ b/source4/scripting/python/samba/netcmd/dsacl.py @@ -57,7 +57,8 @@ class cmd_ds_acl_set(Command): } takes_options = [ - Option("--host", help="LDB URL for database or target server", type=str), + Option("--host", help="LDB URL for database or target server", + type=str), Option("--car", type="choice", choices=["change-rid", "change-pdc", "change-infrastructure", @@ -74,12 +75,15 @@ class cmd_ds_acl_set(Command): help=car_help), Option("--action", type="choice", choices=["allow", "deny"], help="""Deny or allow access"""), - Option("--objectdn", help="DN of the object whose SD to modify", type="string"), - Option("--trusteedn", help="DN of the entity that gets access", type="string"), + Option("--objectdn", help="DN of the object whose SD to modify", + type="string"), + Option("--trusteedn", help="DN of the entity that gets access", + type="string"), ] def find_trustee_sid(self, samdb, trusteedn): - res = samdb.search(base=trusteedn, expression="(objectClass=*)", scope=SCOPE_BASE) + res = samdb.search(base=trusteedn, expression="(objectClass=*)", + scope=SCOPE_BASE) assert(len(res) == 1) return ndr_unpack( security.dom_sid,res[0]["objectSid"][0]) @@ -93,18 +97,20 @@ class cmd_ds_acl_set(Command): samdb.modify(m) def read_descriptor(self, samdb, object_dn): - res = samdb.search(base=object_dn, scope=SCOPE_BASE, attrs=["nTSecurityDescriptor"]) + res = samdb.search(base=object_dn, scope=SCOPE_BASE, + attrs=["nTSecurityDescriptor"]) # we should theoretically always have an SD assert(len(res) == 1) desc = res[0]["nTSecurityDescriptor"][0] return ndr_unpack(security.descriptor, desc) def get_domain_sid(self, samdb): - res = samdb.search(base=SamDB.domain_dn(samdb), expression="(objectClass=*)", scope=SCOPE_BASE) + res = samdb.search(base=SamDB.domain_dn(samdb), + expression="(objectClass=*)", scope=SCOPE_BASE) return ndr_unpack( security.dom_sid,res[0]["objectSid"][0]) - #add new ace explicitly def add_ace(self, samdb, object_dn, new_ace): + """Add new ace explicitly.""" desc = self.read_descriptor(samdb, object_dn) desc_sddl = desc.as_sddl(self.get_domain_sid(samdb)) #TODO add bindings for descriptor manipulation and get rid of this @@ -164,6 +170,7 @@ class cmd_ds_acl_set(Command): self.add_ace(samdb, objectdn, new_ace) self.print_new_acl(samdb, objectdn) + class cmd_ds_acl(SuperCommand): """DS ACLs manipulation""" diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 4bef0ed7d4..eb89ee9f3a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -2,7 +2,7 @@ # Unix SMB/CIFS implementation. # backend code for provisioning a Samba4 server -# Copyright (C) Jelmer Vernooij 2007-2008 +# Copyright (C) Jelmer Vernooij 2007-2010 # Copyright (C) Andrew Bartlett 2008-2009 # Copyright (C) Oliver Liebel 2008-2009 # @@ -53,7 +53,6 @@ from samba.schema import Schema from samba.samdb import SamDB from ms_display_specifiers import read_ms_ldif from samba.provisionbackend import LDBBackend, ExistingBackend, FDSBackend, OpenLDAPBackend -from provisionexceptions import ProvisioningError, InvalidNetbiosName __docformat__ = "restructuredText" @@ -150,9 +149,8 @@ def get_domain_descriptor(domain_sid): DEFAULTSITE = "Default-First-Site-Name" -# Exception classes - class ProvisionPaths(object): + def __init__(self): self.shareconf = None self.hklm = None @@ -172,6 +170,7 @@ class ProvisionPaths(object): class ProvisionNames(object): + def __init__(self): self.rootdn = None self.domaindn = None @@ -188,12 +187,14 @@ class ProvisionNames(object): class ProvisionResult(object): + 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. @@ -203,9 +204,9 @@ def check_install(lp, session_info, credentials): """ if lp.get("realm") == "": raise Exception("Realm empty") - ldb = Ldb(lp.get("sam database"), session_info=session_info, + samdb = Ldb(lp.get("sam database"), session_info=session_info, credentials=credentials, lp=lp) - if len(ldb.search("(cn=Administrator)")) != 1: + if len(samdb.search("(cn=Administrator)")) != 1: raise ProvisioningError("No administrator account found") @@ -825,6 +826,7 @@ def create_gpo_struct(policy_path): os.makedirs(os.path.join(policy_path, "MACHINE"), 0755) os.makedirs(os.path.join(policy_path, "USER"), 0755) + def setup_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc): policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid) create_gpo_struct(policy_path) @@ -832,6 +834,7 @@ def setup_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc): policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid_dc) create_gpo_struct(policy_path) + def setup_samdb(path, setup_path, session_info, provision_backend, lp, names, message, domainsid, domainguid, policyguid, policyguid_dc, @@ -851,7 +854,8 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, if dom_for_fun_level is None: dom_for_fun_level = DS_DOMAIN_FUNCTION_2003 if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003: - message("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This is not recommended") + message("You want to run SAMBA 4 on a domain and forest function level" + " lower than Windows 2003 (Native). This is not recommended") if dom_for_fun_level > domainControllerFunctionality: raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level which itself is higher than its actual DC function level (2008). This won't work!") @@ -864,7 +868,7 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, provision_backend=provision_backend, session_info=session_info, names=names, serverrole=serverrole, schema=schema) - if (schema == None): + if schema is None: schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn) # Load the database, but importantly, use Ldb not SamDB as we don't want to @@ -1033,7 +1037,6 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID", expression="", scope=ldb.SCOPE_BASE) assert isinstance(names.ntdsguid, str) - except: samdb.transaction_cancel() raise @@ -1066,9 +1069,11 @@ def set_gpo_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp): attrs=["cn","nTSecurityDescriptor"], expression="", scope=ldb.SCOPE_ONELEVEL) for policy in res: - acl = ndr_unpack(security.descriptor,str(policy["nTSecurityDescriptor"])).as_sddl() + acl = ndr_unpack(security.descriptor, + str(policy["nTSecurityDescriptor"])).as_sddl() policy_path = getpolicypath(sysvol,dnsdomain,str(policy["cn"])) - set_dir_acl(policy_path,dsacl2fsacl(acl,str(domainsid)),lp,str(domainsid)) + set_dir_acl(policy_path, dsacl2fsacl(acl, str(domainsid)), lp, + str(domainsid)) def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn, lp): @@ -1177,8 +1182,8 @@ def provision(setup_dir, message, session_info, data = open(smbconf, 'r').read() data = data.lstrip() if data is None or data == "": - make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, - targetdir, sid_generator, useeadb) + make_smbconf(smbconf, setup_path, hostname, domain, realm, + serverrole, targetdir, sid_generator, useeadb) else: make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, targetdir, sid_generator, useeadb) @@ -1229,7 +1234,8 @@ def provision(setup_dir, message, session_info, ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") - schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn) + schema = Schema(setup_path, domainsid, schemadn=names.schemadn, + serverdn=names.serverdn) if backend_type == "ldb": provision_backend = LDBBackend(backend_type, @@ -1275,7 +1281,7 @@ def provision(setup_dir, message, session_info, ol_mmr_urls=ol_mmr_urls, nosync=nosync) else: - raise ProvisioningError("Unknown LDAP backend type selected") + raise ValueError("Unknown LDAP backend type selected") provision_backend.init() provision_backend.start() @@ -1290,8 +1296,8 @@ def provision(setup_dir, message, session_info, message("Setting up secrets.ldb") secrets_ldb = setup_secretsdb(paths.secrets, setup_path, - session_info=session_info, - backend_credentials=provision_backend.secrets_credentials, lp=lp) + session_info=session_info, + backend_credentials=provision_backend.secrets_credentials, lp=lp) message("Setting up the registry") setup_registry(paths.hklm, setup_path, session_info, @@ -1322,15 +1328,15 @@ def provision(setup_dir, message, session_info, 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) + (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("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) - + assert paths.sysvol is not None if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0755) @@ -1342,8 +1348,9 @@ def provision(setup_dir, message, session_info, if serverrole == "domain controller": # Set up group policies (domain policy and domain controller policy) - setup_gpo(paths.sysvol,names.dnsdomain,policyguid,policyguid_dc) - setsysvolacl(samdb,paths.netlogon,paths.sysvol,wheel_gid,domainsid,names.dnsdomain,names.domaindn,lp) + setup_gpo(paths.sysvol, names.dnsdomain, policyguid, policyguid_dc) + setsysvolacl(samdb, paths.netlogon, paths.sysvol, wheel_gid, + domainsid, names.dnsdomain, names.domaindn, lp) message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) @@ -1368,11 +1375,10 @@ def provision(setup_dir, message, session_info, # Only make a zone file on the first DC, it should be replicated # with DNS replication - create_zone_file(lp, message, paths, targetdir, setup_path, dnsdomain=names.dnsdomain, - hostip=hostip, - hostip6=hostip6, hostname=names.hostname, - realm=names.realm, - domainguid=domainguid, ntdsguid=names.ntdsguid) + create_zone_file(lp, message, paths, targetdir, setup_path, + dnsdomain=names.dnsdomain, hostip=hostip, hostip6=hostip6, + hostname=names.hostname, realm=names.realm, + domainguid=domainguid, ntdsguid=names.ntdsguid) create_named_conf(paths, setup_path, realm=names.realm, dnsdomain=names.dnsdomain, private_dir=paths.private_dir) @@ -1381,12 +1387,14 @@ def provision(setup_dir, message, session_info, 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) + 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) - message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf) + message("A Kerberos configuration suitable for Samba 4 has been " + "generated at %s" % paths.krb5conf) if serverrole == "domain controller": create_dns_update_list(lp, message, paths, setup_path) @@ -1407,7 +1415,8 @@ def provision(setup_dir, message, session_info, os.chmod(dns_keytab_path, 0640) os.chown(dns_keytab_path, -1, paths.bind_gid) except OSError: - message("Failed to chown %s to bind gid %u" % (dns_keytab_path, paths.bind_gid)) + message("Failed to chown %s to bind gid %u" % (dns_keytab_path, + paths.bind_gid)) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) @@ -1443,7 +1452,6 @@ def provision(setup_dir, message, session_info, return result - def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None, realm=None, rootdn=None, domaindn=None, schemadn=None, @@ -1622,7 +1630,6 @@ def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): :param hostname: Local hostname :param realm: Realm name """ - setup_file(setup_path("krb5.conf"), path, { "DNSDOMAIN": dnsdomain, "HOSTNAME": hostname, @@ -1630,3 +1637,17 @@ def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm): }) +class ProvisioningError(Exception): + """A generic provision error.""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "ProvisioningError: " + self.value + + +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) diff --git a/source4/scripting/python/samba/provisionbackend.py b/source4/scripting/python/samba/provisionbackend.py index 479d965f27..e5d4d8e1b1 100644 --- a/source4/scripting/python/samba/provisionbackend.py +++ b/source4/scripting/python/samba/provisionbackend.py @@ -26,6 +26,7 @@ """Functions for setting up a Samba configuration (LDB and LDAP backends).""" from base64 import b64encode +import errno import ldb import os import sys @@ -40,11 +41,21 @@ from ldb import SCOPE_BASE, SCOPE_ONELEVEL, LdbError, timestring from samba import Ldb, read_and_sub_file, setup_file from samba.credentials import Credentials, DONT_USE_KERBEROS from samba.schema import Schema -from samba.provisionexceptions import ProvisioningError + + +class SlapdAlreadyRunning(Exception): + + def __init__(self, uri): + self.ldapi_uri = uri + super(SlapdAlreadyRunning, self).__init__("Another slapd Instance " + "seems already running on this host, listening to %s." % + self.ldapi_uri) + class ProvisionBackend(object): - def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, - names=None, message=None): + + def __init__(self, backend_type, paths=None, setup_path=None, lp=None, + credentials=None, names=None, message=None): """Provision a backend for samba4""" self.paths = paths self.setup_path = setup_path @@ -72,15 +83,6 @@ class ProvisionBackend(object): class LDBBackend(ProvisionBackend): - def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, - names=None, message=None): - - super(LDBBackend, self).__init__( - backend_type=backend_type, - paths=paths, setup_path=setup_path, - lp=lp, credentials=credentials, - names=names, - message=message) def init(self): self.credentials = None @@ -91,49 +93,40 @@ class LDBBackend(ProvisionBackend): class ExistingBackend(ProvisionBackend): - def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, - names=None, message=None, - ldapi_uri=None): - super(ExistingBackend, self).__init__( - backend_type=backend_type, - paths=paths, setup_path=setup_path, - lp=lp, credentials=credentials, - names=names, - message=message) + def __init__(self, backend_type, paths=None, setup_path=None, lp=None, + credentials=None, names=None, message=None, ldapi_uri=None): + + super(ExistingBackend, self).__init__(backend_type=backend_type, + paths=paths, setup_path=setup_path, lp=lp, + credentials=credentials, names=names, message=message) self.ldapi_uri = ldapi_uri def init(self): - #Check to see that this 'existing' LDAP backend in fact exists + # Check to see that this 'existing' LDAP backend in fact exists ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials) ldapi_db.search(base="", scope=SCOPE_BASE, - expression="(objectClass=OpenLDAProotDSE)") + expression="(objectClass=OpenLDAProotDSE)") - # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied - # This caused them to be set into the long-term database later in the script. + # If we have got here, then we must have a valid connection to the LDAP + # server, with valid credentials supplied This caused them to be set + # into the long-term database later in the script. self.secrets_credentials = self.credentials - self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP + self.ldap_backend_type = "openldap" # For now, assume existing backends at least emulate OpenLDAP class LDAPBackend(ProvisionBackend): - def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, - names=None, message=None, - domainsid=None, - schema=None, - hostname=None, - ldapadminpass=None, - slapd_path=None, - ldap_backend_extra_port=None, - ldap_dryrun_mode=False): - - super(LDAPBackend, self).__init__( - backend_type=backend_type, - paths=paths, setup_path=setup_path, - lp=lp, credentials=credentials, - names=names, - message=message) + + def __init__(self, backend_type, paths=None, setup_path=None, lp=None, + credentials=None, names=None, message=None, domainsid=None, + schema=None, hostname=None, ldapadminpass=None, slapd_path=None, + ldap_backend_extra_port=None, ldap_dryrun_mode=False): + + super(LDAPBackend, self).__init__(backend_type=backend_type, + paths=paths, setup_path=setup_path, lp=lp, + credentials=credentials, names=names, message=message) self.domainsid = domainsid self.schema = schema @@ -156,23 +149,26 @@ class LDAPBackend(ProvisionBackend): os.mkdir(self.ldapdir) def init(self): - # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri - # if another instance of slapd is already running + from samba.provision import ProvisioningError + # we will shortly start slapd with ldapi for final provisioning. first + # check with ldapsearch -> rootDSE via self.ldapi_uri if another + # instance of slapd is already running try: ldapi_db = Ldb(self.ldapi_uri) ldapi_db.search(base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)") try: f = open(self.slapd_pid, "r") + except IOError, err: + if err != errno.ENOENT: + raise + else: p = f.read() f.close() self.message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.") - except: - pass - - raise ProvisioningError("Warning: Another slapd Instance seems already running on this host, listening to " + self.ldapi_uri + ". Please shut it down before you continue. ") - + raise SlapdAlreadyRunning(self.ldapi_uri) except LdbError: + # XXX: We should never be catching all Ldb errors pass # Try to print helpful messages when the user has not specified the path to slapd @@ -216,13 +212,15 @@ class LDAPBackend(ProvisionBackend): pass def start(self): + from samba.provision import ProvisioningError self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'" - open(self.ldapdir + "/ldap_backend_startup.sh", 'w').write("#!/bin/sh\n" + self.slapd_command_escaped + "\n") + open(os.path.join(self.ldapdir, "ldap_backend_startup.sh"), 'w').write("#!/bin/sh\n" + self.slapd_command_escaped + "\n") # Now start the slapd, so we can provision onto it. We keep the # subprocess context around, to kill this off at the successful # end of the script - self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False) + self.slapd = subprocess.Popen(self.slapd_provision_command, + close_fds=True, shell=False) while self.slapd.poll() is None: # Wait until the socket appears @@ -253,29 +251,18 @@ class LDAPBackend(ProvisionBackend): class OpenLDAPBackend(LDAPBackend): - def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, - names=None, message=None, - domainsid=None, - schema=None, - hostname=None, - ldapadminpass=None, - slapd_path=None, - ldap_backend_extra_port=None, - ldap_dryrun_mode=False, - ol_mmr_urls=None, - nosync=False): - - super(OpenLDAPBackend, self).__init__( - backend_type=backend_type, - paths=paths, setup_path=setup_path, - lp=lp, credentials=credentials, - names=names, - message=message, - domainsid=domainsid, - schema=schema, - hostname=hostname, - ldapadminpass=ldapadminpass, - slapd_path=slapd_path, + + def __init__(self, backend_type, paths=None, setup_path=None, lp=None, + credentials=None, names=None, message=None, domainsid=None, + schema=None, hostname=None, ldapadminpass=None, slapd_path=None, + ldap_backend_extra_port=None, ldap_dryrun_mode=False, + ol_mmr_urls=None, nosync=False): + + super(OpenLDAPBackend, self).__init__( backend_type=backend_type, + paths=paths, setup_path=setup_path, lp=lp, + credentials=credentials, names=names, message=message, + domainsid=domainsid, schema=schema, hostname=hostname, + ldapadminpass=ldapadminpass, slapd_path=slapd_path, ldap_backend_extra_port=ldap_backend_extra_port, ldap_dryrun_mode=ldap_dryrun_mode) @@ -290,11 +277,8 @@ class OpenLDAPBackend(LDAPBackend): self.olcdir = os.path.join(self.ldapdir, "slapd.d") self.olcseedldif = os.path.join(self.ldapdir, "olc_seed.ldif") - self.schema = Schema( - self.setup_path, - self.domainsid, - schemadn=self.names.schemadn, - serverdn=self.names.serverdn, + self.schema = Schema(self.setup_path, self.domainsid, + schemadn=self.names.schemadn, serverdn=self.names.serverdn, files=[setup_path("schema_samba4.ldif")]) def setup_db_config(self, dbdir): @@ -307,10 +291,11 @@ class OpenLDAPBackend(LDAPBackend): if not os.path.isdir(os.path.join(dbdir, "tmp")): os.makedirs(os.path.join(dbdir, "tmp"), 0700) - setup_file(self.setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"), - {"LDAPDBDIR": dbdir}) + setup_file(self.setup_path("DB_CONFIG"), + os.path.join(dbdir, "DB_CONFIG"), {"LDAPDBDIR": dbdir}) def provision(self): + from samba.provision import ProvisioningError # Wipe the directories so we can start shutil.rmtree(os.path.join(self.ldapdir, "db"), True) @@ -350,7 +335,6 @@ class OpenLDAPBackend(LDAPBackend): mmr_syncrepl_schema_config = "" mmr_syncrepl_config_config = "" mmr_syncrepl_user_config = "" - if self.ol_mmr_urls is not None: # For now, make these equal @@ -485,7 +469,8 @@ class OpenLDAPBackend(LDAPBackend): if self.ol_mmr_urls is None: server_port_string = "ldap://0.0.0.0:%d" % self.ldap_backend_extra_port else: - server_port_string = "ldap://" + self.names.hostname + "." + self.names.dnsdomain +":%d" % self.ldap_backend_extra_port + server_port_string = "ldap://%s.%s:%d" (self.names.hostname, + self.names.dnsdomain, self.ldap_backend_extra_port) else: server_port_string = "" @@ -537,29 +522,18 @@ class OpenLDAPBackend(LDAPBackend): class FDSBackend(LDAPBackend): - def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, - names=None, message=None, - domainsid=None, - schema=None, - hostname=None, - ldapadminpass=None, - slapd_path=None, - ldap_backend_extra_port=None, - ldap_dryrun_mode=False, - root=None, - setup_ds_path=None): - - super(FDSBackend, self).__init__( - backend_type=backend_type, - paths=paths, setup_path=setup_path, - lp=lp, credentials=credentials, - names=names, - message=message, - domainsid=domainsid, - schema=schema, - hostname=hostname, - ldapadminpass=ldapadminpass, - slapd_path=slapd_path, + + def __init__(self, backend_type, paths=None, setup_path=None, lp=None, + credentials=None, names=None, message=None, domainsid=None, + schema=None, hostname=None, ldapadminpass=None, slapd_path=None, + ldap_backend_extra_port=None, ldap_dryrun_mode=False, root=None, + setup_ds_path=None): + + super(FDSBackend, self).__init__(backend_type=backend_type, + paths=paths, setup_path=setup_path, lp=lp, + credentials=credentials, names=names, message=message, + domainsid=domainsid, schema=schema, hostname=hostname, + ldapadminpass=ldapadminpass, slapd_path=slapd_path, ldap_backend_extra_port=ldap_backend_extra_port, ldap_dryrun_mode=ldap_dryrun_mode) @@ -600,6 +574,7 @@ class FDSBackend(LDAPBackend): prefixmap=["1000:1.3.6.1.4.1.7165.2.1", "1001:1.3.6.1.4.1.7165.2.2"]) def provision(self): + from samba.provision import ProvisioningError if self.ldap_backend_extra_port is not None: serverport = "ServerPort=%d" % self.ldap_backend_extra_port else: @@ -616,7 +591,8 @@ class FDSBackend(LDAPBackend): "LDAPMANAGERPASS": self.ldapadminpass, "SERVERPORT": serverport}) - setup_file(self.setup_path("fedorads-partitions.ldif"), self.partitions_ldif, + setup_file(self.setup_path("fedorads-partitions.ldif"), + self.partitions_ldif, {"CONFIGDN": self.names.configdn, "SCHEMADN": self.names.schemadn, "SAMBADN": self.sambadn, diff --git a/source4/scripting/python/samba/provisionexceptions.py b/source4/scripting/python/samba/provisionexceptions.py deleted file mode 100644 index 6159a02e95..0000000000 --- a/source4/scripting/python/samba/provisionexceptions.py +++ /dev/null @@ -1,38 +0,0 @@ -# -# Unix SMB/CIFS implementation. -# backend code for provisioning a Samba4 server - -# Copyright (C) Jelmer Vernooij 2007-2008 -# Copyright (C) Andrew Bartlett 2008-2009 -# Copyright (C) Oliver Liebel 2008-2009 -# -# 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 . -# - -class ProvisioningError(Exception): - """A generic provision error.""" - def __init__(self, value): - self.value = value - def __str__(self): - return "ProvisioningError: " + self.value - -class InvalidNetbiosName(ProvisioningError): - """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) - - diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 25d1d7fe29..3da739b139 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -31,8 +31,8 @@ from samba import Ldb from samba.dsdb import DS_DOMAIN_FUNCTION_2000 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE import ldb -from samba.provision import ProvisionNames, provision_paths_from_lp, FILL_FULL, provision -from samba.provisionexceptions import ProvisioningError +from samba.provision import (ProvisionNames, provision_paths_from_lp, + FILL_FULL, provision, ProvisioningError) from samba.dcerpc import misc, security from samba.ndr import ndr_unpack @@ -61,7 +61,8 @@ def get_paths(param, targetdir=None, smbconf=None): return paths -def find_provision_key_parameters(param, credentials, session_info, paths, smbconf): +def find_provision_key_parameters(param, credentials, session_info, paths, + smbconf): """Get key provision parameters (realm, domain, ...) from a given provision :param param: Param object @@ -82,10 +83,10 @@ def find_provision_key_parameters(param, credentials, session_info, paths, smbco names.dnsdomain = names.realm names.realm = string.upper(names.realm) # netbiosname - secrets_ldb = Ldb(paths.secrets, session_info=session_info, credentials=credentials,lp=lp, options=["modules:samba_secrets"]) + secrets_ldb = Ldb(paths.secrets, session_info=session_info, + credentials=credentials,lp=lp, options=["modules:samba_secrets"]) # Get the netbiosname first (could be obtained from smb.conf in theory) - attrs = ["sAMAccountName"] - res = secrets_ldb.search(expression="(flatname=%s)"%names.domain,base="CN=Primary Domains", scope=SCOPE_SUBTREE, attrs=attrs) + res = secrets_ldb.search(expression="(flatname=%s)"%names.domain,base="CN=Primary Domains", scope=SCOPE_SUBTREE, attrs=["sAMAccountName"]) names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","") names.smbconf = smbconf @@ -96,8 +97,7 @@ def find_provision_key_parameters(param, credentials, session_info, paths, smbco # That's a bit simplistic but it's ok as long as we have only 3 # partitions - attrs2 = ["defaultNamingContext", "schemaNamingContext","configurationNamingContext","rootDomainNamingContext"] - current = samdb.search(expression="(objectClass=*)",base="", scope=SCOPE_BASE, attrs=attrs2) + current = samdb.search(expression="(objectClass=*)",base="", scope=SCOPE_BASE, attrs=["defaultNamingContext", "schemaNamingContext","configurationNamingContext","rootDomainNamingContext"]) names.configdn = current[0]["configurationNamingContext"] configdn = str(names.configdn) @@ -108,27 +108,28 @@ def find_provision_key_parameters(param, credentials, session_info, paths, smbco names.domaindn=current[0]["defaultNamingContext"] names.rootdn=current[0]["rootDomainNamingContext"] # default site name - attrs3 = ["cn"] - res3= samdb.search(expression="(objectClass=*)",base="CN=Sites,"+configdn, scope=SCOPE_ONELEVEL, attrs=attrs3) + res3= samdb.search(expression="(objectClass=*)",base="CN=Sites,"+configdn, scope=SCOPE_ONELEVEL, attrs=["cn"]) names.sitename = str(res3[0]["cn"]) # dns hostname and server dn - attrs4 = ["dNSHostName"] res4= samdb.search(expression="(CN=%s)"%names.netbiosname,base="OU=Domain Controllers,"+basedn, \ - scope=SCOPE_ONELEVEL, attrs=attrs4) + scope=SCOPE_ONELEVEL, attrs=["dNSHostName"]) names.hostname = str(res4[0]["dNSHostName"]).replace("."+names.dnsdomain,"") server_res = samdb.search(expression="serverReference=%s"%res4[0].dn, attrs=[], base=configdn) names.serverdn = server_res[0].dn # invocation id/objectguid - res5 = samdb.search(expression="(objectClass=*)",base="CN=NTDS Settings,%s" % str(names.serverdn), scope=SCOPE_BASE, attrs=["invocationID","objectGUID"]) - names.invocation = str(ndr_unpack( misc.GUID,res5[0]["invocationId"][0])) - names.ntdsguid = str(ndr_unpack( misc.GUID,res5[0]["objectGUID"][0])) + res5 = samdb.search(expression="(objectClass=*)", + base="CN=NTDS Settings,%s" % str(names.serverdn), scope=SCOPE_BASE, + attrs=["invocationID", "objectGUID"]) + names.invocation = str(ndr_unpack(misc.GUID, res5[0]["invocationId"][0])) + names.ntdsguid = str(ndr_unpack(misc.GUID, res5[0]["objectGUID"][0])) # domain guid/sid - attrs6 = ["objectGUID", "objectSid","msDS-Behavior-Version" ] - res6 = samdb.search(expression="(objectClass=*)",base=basedn, scope=SCOPE_BASE, attrs=attrs6) + res6 = samdb.search(expression="(objectClass=*)",base=basedn, + scope=SCOPE_BASE, attrs=["objectGUID", + "objectSid","msDS-Behavior-Version" ]) names.domainguid = str(ndr_unpack( misc.GUID,res6[0]["objectGUID"][0])) names.domainsid = ndr_unpack( security.dom_sid,res6[0]["objectSid"][0]) if res6[0].get("msDS-Behavior-Version") == None or int(res6[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000: @@ -137,14 +138,12 @@ def find_provision_key_parameters(param, credentials, session_info, paths, smbco names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0]) # policy guid - attrs7 = ["cn","displayName"] res7 = samdb.search(expression="(displayName=Default Domain Policy)",base="CN=Policies,CN=System,"+basedn, \ - scope=SCOPE_ONELEVEL, attrs=attrs7) + scope=SCOPE_ONELEVEL, attrs=["cn","displayName"]) names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","") # dc policy guid - attrs8 = ["cn","displayName"] res8 = samdb.search(expression="(displayName=Default Domain Controllers Policy)",base="CN=Policies,CN=System,"+basedn, \ - scope=SCOPE_ONELEVEL, attrs=attrs8) + scope=SCOPE_ONELEVEL, attrs=["cn","displayName"]) if len(res8) == 1: names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","") else: @@ -194,9 +193,12 @@ def newprovision(names,setup_dir,creds,session,smbconf,provdir,messagefunc): def dn_sort(x,y): - """Sorts two DNs in the lexicographical order it and put higher level DN before. + """Sorts two DNs in the lexicographical order it and put higher level DN + before. + + So given the dns cn=bar,cn=foo and cn=foo the later will be return as + smaller - So given the dns cn=bar,cn=foo and cn=foo the later will be return as smaller :param x: First object to compare :param y: Second object to compare """ diff --git a/source4/setup/provision b/source4/setup/provision index bbd6298dc3..d0d35f807e 100755 --- a/source4/setup/provision +++ b/source4/setup/provision @@ -34,13 +34,12 @@ import samba.ntacls from samba.credentials import DONT_USE_KERBEROS from samba.auth import system_session import samba.getopt as options -from samba.provision import provision, FILL_FULL, FILL_NT4SYNC, FILL_DRS, find_setup_dir +from samba.provision import provision, FILL_FULL, FILL_NT4SYNC, FILL_DRS, find_setup_dir, ProvisioningError from samba.dsdb import ( DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DOMAIN_FUNCTION_2008_R2, ) -from samba.provisionexceptions import ProvisioningError # how do we make this case insensitive?? @@ -118,7 +117,7 @@ parser.add_option("--slapd-path", type="string", metavar="SLAPD-PATH", parser.add_option("--setup-ds-path", type="string", metavar="SETUP_DS-PATH", help="Path to setup-ds.pl script for Fedora DS LDAP backend [e.g.:'/usr/sbin/setup-ds.pl']. Required for Setup with Fedora DS backend.") parser.add_option("--nosync", help="Configure LDAP backend not to call fsync() (for performance in test environments)", action="store_true") -parser.add_option("--use-xattrs", type="choice", choices=["yes","no","auto"], help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities") +parser.add_option("--use-xattrs", type="choice", choices=["yes","no","auto"], help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities", default="auto") parser.add_option("--ldap-dryrun-mode", help="Configure LDAP backend, but do not run any binaries and exit early. Used only for the test environment. DO NOT USE", action="store_true") opts = parser.parse_args()[0] @@ -210,16 +209,14 @@ if opts.blank: elif opts.partitions_only: samdb_fill = FILL_DRS -if not opts.use_xattrs: - opts.use_xattrs="auto" - eadb = True if opts.use_xattrs == "yes": eadb = False elif opts.use_xattrs == "auto": - file=tempfile.NamedTemporaryFile() + file = tempfile.NamedTemporaryFile() try: - samba.ntacls.setntacl(lp,file.name,"O:S-1-5-32G:S-1-5-32","S-1-5-32","native") + samba.ntacls.setntacl(lp, file.name, + "O:S-1-5-32G:S-1-5-32", "S-1-5-32", "native") eadb = False except: if lp.get("posix:eadb") == None: -- cgit