diff options
author | Matthieu Patou <mat@matws.net> | 2010-01-31 22:06:01 +0300 |
---|---|---|
committer | Jelmer Vernooij <jelmer@samba.org> | 2010-03-01 03:20:36 +0100 |
commit | 3bd16415d29d074c7a8f9bf949a35b7e8f8b61a2 (patch) | |
tree | 424c192b0773de0b9ed7e1b4a15e79937b8efcb3 /source4/scripting/python | |
parent | 2238260aa3f85cdb0057dae437f454c8c54d08f7 (diff) | |
download | samba-3bd16415d29d074c7a8f9bf949a35b7e8f8b61a2.tar.gz samba-3bd16415d29d074c7a8f9bf949a35b7e8f8b61a2.tar.bz2 samba-3bd16415d29d074c7a8f9bf949a35b7e8f8b61a2.zip |
upgradeprovision: split the big script to put reusable functions appart
Signed-off-by: Jelmer Vernooij <jelmer@samba.org>
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) + + + |