diff options
Diffstat (limited to 'source4/scripting/python')
| -rwxr-xr-x | source4/scripting/python/samba/upgradehelpers.py | 220 | 
1 files changed, 220 insertions, 0 deletions
diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py new file mode 100755 index 0000000000..58da4dbb6d --- /dev/null +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -0,0 +1,220 @@ +#!/usr/bin/python +# +# Helpers for provision stuff +# Copyright (C) Matthieu Patou <mat@matws.net> 2009-2010 +# +# Based on provision a Samba4 server by +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008 +# Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 <http://www.gnu.org/licenses/>. + + +import os +import sys +import string +import re +# Find right directory when running from source tree + +import samba +from samba import Ldb, DS_DOMAIN_FUNCTION_2000 +from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError +import ldb +from samba.provision import  ProvisionNames,provision_paths_from_lp,FILL_FULL,provision +from samba.provisionexceptions import ProvisioningError +from samba.dcerpc import misc, security +from samba.ndr import ndr_pack, ndr_unpack + +# Get Paths for important objects (ldb, keytabs ...) +def get_paths(param,targetdir=None,smbconf=None): +	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") +	if smbconf is None: +			smbconf = param.default_path() + +	if not os.path.exists(smbconf): +		raise ProvisioningError("Unable to find smb.conf ...") + +	lp = param.LoadParm() +	lp.load(smbconf) +	paths = provision_paths_from_lp(lp,lp.get("realm")) +	return paths + + +# This function guesses (fetches) informations needed to make a fresh provision +# from the current provision +# It includes: realm, workgroup, partitions, netbiosname, domain guid, ... +def find_provision_key_parameters(param,credentials,session_info,paths,smbconf): +	lp = param.LoadParm() +	lp.load(paths.smbconf) +	names = ProvisionNames() +	# NT domain, kerberos realm, root dn, domain dn, domain dns name +	names.domain = string.upper(lp.get("workgroup")) +	names.realm = lp.get("realm") +	basedn = "DC=" + names.realm.replace(".",",DC=") +	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"]) +	# 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) +	names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","") + +	names.smbconf = smbconf +	# It's important here to let ldb load with the old module or it's quite +	# certain that the LDB won't load ... +	samdb = Ldb(paths.samdb, session_info=session_info, +		    credentials=credentials, lp=lp, options=["modules:samba_dsdb"]) + +	# 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) + +	names.configdn = current[0]["configurationNamingContext"] +	configdn = str(names.configdn) +	names.schemadn = current[0]["schemaNamingContext"] +	if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb, current[0]["defaultNamingContext"][0]))): +		raise ProvisioningError(("basedn in %s (%s) and from %s (%s) is not the same ..." % (paths.samdb, str(current[0]["defaultNamingContext"][0]), paths.smbconf, basedn))) + +	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) +	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) +	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])) + +	# domain guid/sid +	attrs6 = ["objectGUID", "objectSid","msDS-Behavior-Version" ] +	res6 = samdb.search(expression="(objectClass=*)",base=basedn, scope=SCOPE_BASE, attrs=attrs6) +	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: +		names.domainlevel = DS_DOMAIN_FUNCTION_2000 +	else: +		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) +	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=attrs7) +	if len(res8) == 1: +		names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","") +	else: +		names.policyid_dc = None + +	return names + + +# Create a fresh new reference provision +# This provision will be the reference for knowing what has changed in the +# since the latest upgrade in the current provision +def newprovision(names,setup_dir,creds,session,smbconf,provdir,messagefunc): +	if os.path.isdir(provdir): +		rmall(provdir) +	logstd=os.path.join(provdir,"log.std") +	os.chdir(os.path.join(setup_dir,"..")) +	os.mkdir(provdir) +	os.close(2) +	sys.stderr = open("%s/provision.log"%provdir, "w") +	messagefunc("Reference provision stored in %s"%provdir) +	messagefunc("STDERR message of provision will be logged in %s/provision.log"%provdir) +	sys.stderr = open("/dev/stdout", "w") +	provision(setup_dir, messagefunc, +		session, creds, smbconf=smbconf, targetdir=provdir, +		samdb_fill=FILL_FULL, realm=names.realm, domain=names.domain, +		domainguid=names.domainguid, domainsid=str(names.domainsid),ntdsguid=names.ntdsguid, +		policyguid=names.policyid,policyguid_dc=names.policyid_dc,hostname=names.netbiosname, +		hostip=None, hostip6=None, +		invocationid=names.invocation, adminpass=None, +		krbtgtpass=None, machinepass=None, +		dnspass=None, root=None, nobody=None, +		wheel=None, users=None, +		serverrole="domain controller", +		ldap_backend_extra_port=None, +		backend_type=None, +		ldapadminpass=None, +		ol_mmr_urls=None, +		slapd_path=None, +		setup_ds_path=None, +		nosync=None, +		dom_for_fun_level=names.domainlevel, +		ldap_dryrun_mode=None,useeadb=True) + +# This function sorts two DNs in the lexicographical order and put higher level +# DN before. +# So given the dns cn=bar,cn=foo and cn=foo the later will be return as smaller +# (-1) as it has less level +def dn_sort(x,y): +	p = re.compile(r'(?<!\\),') +	tab1 = p.split(str(x)) +	tab2 = p.split(str(y)) +	min = 0 +	if (len(tab1) > len(tab2)): +		min = len(tab2) +	elif (len(tab1) < len(tab2)): +		min = len(tab1) +	else: +		min = len(tab1) +	len1=len(tab1)-1 +	len2=len(tab2)-1 +	space = " " +	# Note: python range go up to upper limit but do not include it +	for i in range(0,min): +		ret=cmp(tab1[len1-i],tab2[len2-i]) +		if(ret != 0): +			return ret +		else: +			if(i==min-1): +				assert len1!=len2,"PB PB PB"+space.join(tab1)+" / "+space.join(tab2) +				if(len1>len2): +					return 1 +				else: +					return -1 +	return ret + + +def rmall(topdir): +	for root, dirs, files in os.walk(topdir, topdown=False): +		for name in files: +			os.remove(os.path.join(root, name)) +		for name in dirs: +			os.rmdir(os.path.join(root, name)) +	os.rmdir(topdir) + + +  | 
