diff options
Diffstat (limited to 'source4/scripting')
-rwxr-xr-x | source4/scripting/bin/reorgldb.py | 60 | ||||
-rwxr-xr-x | source4/scripting/bin/setup_dns.sh | 1 | ||||
-rwxr-xr-x | source4/scripting/bin/w32err_code.py | 361 | ||||
-rw-r--r-- | source4/scripting/devel/drs/fsmo.ldif.template | 75 | ||||
-rw-r--r-- | source4/scripting/devel/drs/named.conf.ad.template | 6 | ||||
-rwxr-xr-x | source4/scripting/devel/drs/revampire_ad.sh | 23 | ||||
-rwxr-xr-x | source4/scripting/devel/drs/unvampire_ad.sh | 12 | ||||
-rwxr-xr-x | source4/scripting/devel/drs/vampire_ad.sh | 17 | ||||
-rw-r--r-- | source4/scripting/devel/drs/vars | 11 | ||||
-rw-r--r-- | source4/scripting/python/samba/__init__.py | 4 | ||||
-rw-r--r-- | source4/scripting/python/samba/provision.py | 194 | ||||
-rw-r--r-- | source4/scripting/python/samba/tests/samdb.py | 6 |
12 files changed, 650 insertions, 120 deletions
diff --git a/source4/scripting/bin/reorgldb.py b/source4/scripting/bin/reorgldb.py deleted file mode 100755 index 571363fdc7..0000000000 --- a/source4/scripting/bin/reorgldb.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/python -# -# Copyright (C) Matthieu Patou <mat@matws.net> 2009 -# This script realize an offline reorganisation of an LDB -# file it helps to reduce (sometime drastically) the -# size of LDB files. -import sys -import optparse -import os -sys.path.insert(0, "bin/python") - -import samba -from samba.credentials import DONT_USE_KERBEROS -from samba.auth import system_session -from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted -from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError -import ldb -import samba.getopt as options -from samba.samdb import SamDB -from samba import param -from samba.provision import ProvisionPaths, ProvisionNames,provision_paths_from_lp, Schema - -parser = optparse.OptionParser("provision [options]") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -parser.add_option("--database", type="string", metavar="FILE", - help="LDB to reorganize") -opts = parser.parse_args()[0] -lp = sambaopts.get_loadparm() -smbconf = lp.configfile - -if not opts.database: - print "Parameter database is mandatory" - sys.exit(1) -creds = credopts.get_credentials(lp) -creds.set_kerberos_state(DONT_USE_KERBEROS) -session = system_session() -empty = ldb.Message() -newname="%s.new"%(opts.database) -if os.path.exists(newname): - os.remove(newname) -old_ldb = Ldb(opts.database, session_info=session, credentials=creds,lp=lp) -new_ldb = Ldb(newname,session_info=session, credentials=creds,lp=lp) - -new_ldb.transaction_start() -res = old_ldb.search(expression="(dn=*)",base="", scope=SCOPE_SUBTREE) -for i in range(0,len(res)): - if str(res[i].dn) == "@BASEINFO": - continue - if str(res[i].dn).startswith("@INDEX:"): - continue - delta = new_ldb.msg_diff(empty,res[i]) - delta.dn = res[i].dn - delta.remove("distinguishedName") - new_ldb.add(delta) - -new_ldb.transaction_commit() diff --git a/source4/scripting/bin/setup_dns.sh b/source4/scripting/bin/setup_dns.sh index f296de2b8e..f20ad145c1 100755 --- a/source4/scripting/bin/setup_dns.sh +++ b/source4/scripting/bin/setup_dns.sh @@ -33,5 +33,6 @@ scripting/bin/nsupdate-gss --realm=$DOMAIN --noverify --ntype="CNAME" $OBJECTGUI exit 1 } echo "Checking" +rndc flush host $HOSTNAME.$DOMAIN host $OBJECTGUID._msdcs.$DOMAIN diff --git a/source4/scripting/bin/w32err_code.py b/source4/scripting/bin/w32err_code.py new file mode 100755 index 0000000000..cad6f6ecc9 --- /dev/null +++ b/source4/scripting/bin/w32err_code.py @@ -0,0 +1,361 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009 +# +# 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 generete werror.h/doserr.c files from WSPP HTML""" + +import re +import os +import sys +import urllib +import pprint +from xml.dom import minidom +from optparse import OptionParser, OptionGroup + +_wspp_werror_url = 'http://msdn.microsoft.com/en-us/library/cc231199%28PROT.10%29.aspx' + +class WerrorHtmlParser(object): + """ + Parses HTML from WSPP documentation generating dictionary of + dictionaries with following keys: + - "err_hex" - hex number (as string) + - "err_name" - error name + - "err_desc" - error long description + For the key of returned dictionary err_hex is used, + i.e. "hex-error-code-str" => {error dictionary object} + """ + + ERROR_PREFIX = ['ERROR_', 'NERR_', 'FRS_', 'RPC_', 'EPT_', 'OR_', 'WAIT_TIMEOUT'] + ERROR_REPLACE = ['ERROR_'] + + def __init__(self, opt): + self.opt = opt + self._errors_skipped = [] + pass + + def _is_error_code_name(self, err_name): + for pref in self.ERROR_PREFIX: + if err_name.startswith(pref): + return True + return False + + def _make_werr_name(self, err_name): + err_name = err_name.upper() + for pref in self.ERROR_REPLACE: + if err_name.startswith(pref): + return err_name.replace(pref, 'WERR_', 1) + return 'WERR_' + err_name + + def parse_url(self, url): + errors = {} + html = self._load_url(url) + + # let minidom to parse the tree, should be: + # table -> tr -> td + # p -> [hex code, br, error code] + # p -> [description] + table_node = minidom.parseString(html) + for row_node in table_node.getElementsByTagName("tr"): + # verify we got right number of td elements + td_nodes = row_node.getElementsByTagName('td') + if len(td_nodes) != 2: + continue + # now get the real data + p_nodes = row_node.getElementsByTagName('p') + if len(p_nodes) != 2: continue + if len(p_nodes[0].childNodes) != 3: continue + if len(p_nodes[1].childNodes) != 1: continue + err_hex = str(p_nodes[0].childNodes[0].nodeValue) + err_name = str(p_nodes[0].childNodes[2].nodeValue) + err_desc = p_nodes[1].childNodes[0].nodeValue.encode('utf-8') + err_desc = err_desc.replace('"', '\\"').replace("\'", "\\'") + # do some checking + if not err_hex.startswith('0x'): continue + if not self._is_error_code_name(err_name): + self._errors_skipped.append("%s - %s - %d" % (err_name, err_hex, int(err_hex, 16))) + continue + # create entry + err_name = self._make_werr_name(err_name) + err_def = {'err_hex': err_hex, + 'err_name': err_name, + 'err_desc': err_desc, + 'code': int(err_hex, 16)} + errors[err_def['code']] = err_def + + # print skipped errors + if self.opt.print_skipped and len(self._errors_skipped): + print "\nErrors skipped during HTML parsing:" + pprint.pprint(self._errors_skipped) + print "\n" + + return errors + + def _load_url(self, url): + html_str = "" + try: + fp = urllib.urlopen(url) + for line in fp: + html_str += line.strip() + fp.close() + except IOError, e: + print "error loading url: " + e.strerror + pass + + # currently ERROR codes are rendered as table + # locate table chunk with ERROR_SUCCESS + html = [x for x in html_str.split('<table ') if "ERROR_SUCCESS" in x] + html = '<table ' + html[0] + pos = html.find('</table>') + if pos == -1: + return ''; + html = html[:pos] + '</table>' + + # html clean up + html = re.sub(r'<a[^>]*>(.*?)</a>', r'\1', html) + + return html + + +class WerrorGenerator(object): + """ + provides methods to generate parts of werror.h and doserr.c files + """ + + FNAME_WERRORS = 'w32errors.lst' + FNAME_WERROR_DEFS = 'werror_defs.h' + FNAME_DOSERR_DEFS = 'doserr_defs.c' + FNAME_DOSERR_DESC = 'doserr_desc.c' + + def __init__(self, opt): + self.opt = opt + self._out_dir = opt.out_dir + pass + + def _open_out_file(self, fname): + fname = os.path.join(self._out_dir, fname) + return open(fname, "w") + + def _gen_werrors_list(self, errors): + """uses 'errors' dictionary to display list of Win32 Errors""" + + fp = self._open_out_file(self.FNAME_WERRORS) + for err_code in sorted(errors.keys()): + err_name = errors[err_code]['err_name'] + fp.write(err_name) + fp.write("\n") + fp.close() + + def _gen_werror_defs(self, errors): + """uses 'errors' dictionary to generate werror.h file""" + + fp = self._open_out_file(self.FNAME_WERROR_DEFS) + for err_code in sorted(errors.keys()): + err_name = errors[err_code]['err_name'] + err_hex = errors[err_code]['err_hex'] + fp.write('#define %s\tW_ERROR(%s)' % (err_name, err_hex)) + fp.write("\n") + fp.close() + + def _gen_doserr_defs(self, errors): + """uses 'errors' dictionary to generate defines in doserr.c file""" + + fp = self._open_out_file(self.FNAME_DOSERR_DEFS) + for err_code in sorted(errors.keys()): + err_name = errors[err_code]['err_name'] + fp.write('\t{ "%s", %s },' % (err_name, err_name)) + fp.write("\n") + fp.close() + + def _gen_doserr_descriptions(self, errors): + """uses 'errors' dictionary to generate descriptions in doserr.c file""" + + fp = self._open_out_file(self.FNAME_DOSERR_DESC) + for err_code in sorted(errors.keys()): + err_name = errors[err_code]['err_name'] + fp.write('\t{ %s, "%s" },' % (err_name, errors[err_code]['err_desc'])) + fp.write("\n") + fp.close() + + def _lookup_error_by_name(self, err_name, defined_errors): + for err in defined_errors.itervalues(): + if err['err_name'] == err_name: + return err + return None + + def _filter_errors(self, errors, defined_errors): + """ + returns tuple (new_erros, diff_code_errors, diff_name_errors) + new_errors - dictionary of errors not in defined_errors + diff_code_errors - list of errors found in defined_errors + but with different value + diff_name_errors - list of errors found with same code in + defined_errors, but with different name + Most critical is diff_code_errors list to be empty! + """ + new_errors = {} + diff_code_errors = [] + diff_name_errors = [] + for err_def in errors.itervalues(): + add_error = True + # try get defined error by code + if defined_errors.has_key(err_def['code']): + old_err = defined_errors[err_def['code']] + if err_def['err_name'] != old_err['err_name']: + warning = {'msg': 'New and Old errors has different error names', + 'err_new': err_def, + 'err_old': old_err} + diff_name_errors.append(warning) + + # sanity check for errors with same name but different values + old_err = self._lookup_error_by_name(err_def['err_name'], defined_errors) + if old_err: + if err_def['code'] != old_err['code']: + warning = {'msg': 'New and Old error defs has different error value', + 'err_new': err_def, + 'err_old': old_err} + diff_code_errors.append(warning) + # exclude error already defined with same name + add_error = False + # do add the error in new_errors if everything is fine + if add_error: + new_errors[err_def['code']] = err_def + pass + return (new_errors, diff_code_errors, diff_name_errors) + + def generate(self, errors): + # load already defined error codes + werr_parser = WerrorParser(self.opt) + (defined_errors, + no_value_errors) = werr_parser.load_err_codes(self.opt.werror_file) + if not defined_errors: + print "\nUnable to load existing errors file: %s" % self.opt.werror_file + sys.exit(1) + if self.opt.verbose and len(no_value_errors): + print "\nWarning: there are errors defines using macro value:" + pprint.pprint(no_value_errors) + print "" + # filter generated error codes + (new_errors, + diff_code_errors, + diff_name_errors) = self._filter_errors(errors, defined_errors) + if diff_code_errors: + print("\nFound %d errors with same names but different error values! Aborting." + % len(diff_code_errors)) + pprint.pprint(diff_code_errors) + sys.exit(2) + + if diff_name_errors: + print("\nFound %d errors with same values but different names (should be normal)" + % len(diff_name_errors)) + pprint.pprint(diff_name_errors) + + # finally generate output files + self._gen_werror_defs(new_errors) + self._gen_doserr_defs(new_errors) + self._gen_werrors_list(errors) + self._gen_doserr_descriptions(errors) + pass + +class WerrorParser(object): + """ + Parses errors defined in werror.h file + """ + + def __init__(self, opt): + self.opt = opt + pass + + def _parse_werror_line(self, line): + m = re.match('#define[ \t]*(.*?)[ \t]*W_ERROR\((.*?)\)', line) + if not m or (len(m.groups()) != 2): + return None + if len(m.group(1)) == 0: + return None + if str(m.group(2)).startswith('0x'): + err_code = int(m.group(2), 16) + elif m.group(2).isdigit(): + err_code = int(m.group(2)) + else: + self.err_no_values.append(line) + return None + return {'err_name': str(m.group(1)), + 'err_hex': "0x%08X" % err_code, + 'code': err_code} + pass + + def load_err_codes(self, fname): + """ + Returns tuple of: + dictionary of "hex_err_code" => {code, name} + "hex_err_code" is string + "code" is int value for the error + list of errors that was ignored for some reason + """ + # reset internal variables + self.err_no_values = [] + err_codes = {} + fp = open(fname) + for line in fp.readlines(): + err_def = self._parse_werror_line(line) + if err_def: + err_codes[err_def['code']] = err_def + fp.close(); + return (err_codes, self.err_no_values) + + + +def _generate_files(opt): + parser = WerrorHtmlParser(opt) + errors = parser.parse_url(opt.url) + + out = WerrorGenerator(opt) + out.generate(errors) + pass + + +if __name__ == '__main__': + _cur_dir = os.path.abspath(os.path.dirname(__file__)) + opt_parser = OptionParser(usage="usage: %prog [options]", version="%prog 0.3") + opt_group = OptionGroup(opt_parser, "Main options") + opt_group.add_option("--url", dest="url", + default=_wspp_werror_url, + help="url for w32 error codes html - may be local file") + opt_group.add_option("--out", dest="out_dir", + default=_cur_dir, + help="output dir for generated files") + opt_group.add_option("--werror", dest="werror_file", + default=os.path.join(_cur_dir, 'werror.h'), + help="path to werror.h file") + opt_group.add_option("--print_skipped", + action="store_true", dest="print_skipped", default=False, + help="print errors skipped during HTML parsing") + opt_group.add_option("-q", "--quiet", + action="store_false", dest="verbose", default=True, + help="don't print warnings to stdout") + + opt_parser.add_option_group(opt_group) + + (options, args) = opt_parser.parse_args() + + # add some options to be used internally + options.err_defs_file = os.path.join(options.out_dir, WerrorGenerator.FNAME_WERROR_DEFS) + options.dos_defs_file = os.path.join(options.out_dir, WerrorGenerator.FNAME_DOSERR_DEFS) + options.dos_desc_file = os.path.join(options.out_dir, WerrorGenerator.FNAME_DOSERR_DESC) + + # check options + _generate_files(options) diff --git a/source4/scripting/devel/drs/fsmo.ldif.template b/source4/scripting/devel/drs/fsmo.ldif.template new file mode 100644 index 0000000000..d5b373a04e --- /dev/null +++ b/source4/scripting/devel/drs/fsmo.ldif.template @@ -0,0 +1,75 @@ +dn: CN=RID Manager$,CN=System,BASEDN +changetype: modify +replace: fSMORoleOwner +fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,C + N=Sites,CN=Configuration,BASEDN +- + +dn: BASEDN +changetype: modify +replace: fSMORoleOwner +fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,C + N=Sites,CN=Configuration,BASEDN +- + +dn: CN=Infrastructure,BASEDN +changetype: modify +replace: fSMORoleOwner +fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,C + N=Sites,CN=Configuration,BASEDN +- + +dn: CN=Partitions,CN=Configuration,BASEDN +changetype: modify +replace: fSMORoleOwner +fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN +- + +dn: CN=Schema,CN=Configuration,BASEDN +changetype: modify +replace: fSMORoleOwner +fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN +- + +dn: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN +changetype: modify +replace: options +options: 1 +- + +dn: CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN +changetype: modify +replace: dNSHostName +dNSHostName: MACHINE.DNSDOMAIN +- + +dn: CN=NTDS Site Settings,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN +changetype: modify +replace: interSiteTopologyGenerator +interSiteTopologyGenerator: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN +- + +dn: CN=MACHINE,OU=Domain Controllers,BASEDN +changetype: modify +replace: servicePrincipalName +servicePrincipalName: GC/MACHINE.DNSDOMAIN/DNSDOMAIN +servicePrincipalName: HOST/MACHINE/NETBIOSDOMAIN +servicePrincipalName: ldap/MACHINE/NETBIOSDOMAIN +servicePrincipalName: ldap/MACHINE.DNSDOMAIN/ForestDnsZones.DNSDOMAIN +servicePrincipalName: ldap/MACHINE.DNSDOMAIN/DomainDnsZones.DNSDOMAIN +servicePrincipalName: DNS/MACHINE.DNSDOMAIN +servicePrincipalName: RestrictedKrbHost/MACHINE.DNSDOMAIN +servicePrincipalName: RestrictedKrbHost/MACHINE +servicePrincipalName: HOST/MACHINE.DNSDOMAIN/NETBIOSDOMAIN +servicePrincipalName: HOST/MACHINE +servicePrincipalName: HOST/MACHINE.DNSDOMAIN +servicePrincipalName: HOST/MACHINE.DNSDOMAIN/DNSDOMAIN +servicePrincipalName: ldap/MACHINE.DNSDOMAIN/NETBIOSDOMAIN +servicePrincipalName: ldap/MACHINE +servicePrincipalName: ldap/MACHINE.DNSDOMAIN +servicePrincipalName: ldap/MACHINE.DNSDOMAIN/DNSDOMAIN +servicePrincipalName: E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN +servicePrincipalName: ldap/NTDSGUID._msdcs.DNSDOMAIN +servicePrincipalName: Dfsr-12F9A27C-BF97-4787-9364-D31B6C55EB04/MACHINE.DNSDOMAIN +servicePrincipalName: NtFrs-88f5d2bd-b646-11d2-a6d3-00c04fc9b232/MACHINE.DNSDOMAIN +- diff --git a/source4/scripting/devel/drs/named.conf.ad.template b/source4/scripting/devel/drs/named.conf.ad.template new file mode 100644 index 0000000000..071c98ccf8 --- /dev/null +++ b/source4/scripting/devel/drs/named.conf.ad.template @@ -0,0 +1,6 @@ +zone "DNSDOMAIN" IN { + type forward; + forwarders { + SERVERIP; + }; +}; diff --git a/source4/scripting/devel/drs/revampire_ad.sh b/source4/scripting/devel/drs/revampire_ad.sh new file mode 100755 index 0000000000..522601c87e --- /dev/null +++ b/source4/scripting/devel/drs/revampire_ad.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -x + +. `dirname $0`/vars + +`dirname $0`/vampire_ad.sh || exit 1 + +ntds_guid=$(sudo bin/ldbsearch -H $PREFIX/private/sam.ldb -b "CN=NTDS Settings,CN=$machine,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,$dn" objectGUID|grep ^objectGUID| awk '{print $2}') + +cp $PREFIX/private/$DNSDOMAIN.zone{.template,} +sed -i "s/NTDSGUID/$ntds_guid/g" $PREFIX/private/$DNSDOMAIN.zone +cp $PREFIX/private/named.conf{.local,} +sudo rndc reconfig +fsmotmp=`mktemp fsmo.ldif.XXXXXXXXX` +cp `dirname $0`/fsmo.ldif.template $fsmotmp +sed -i "s/NTDSGUID/$ntds_guid/g" $fsmotmp +sed -i "s/MACHINE/$machine/g" $fsmotmp +sed -i "s/DNSDOMAIN/$DNSDOMAIN/g" $fsmotmp +sed -i "s/BASEDN/$dn/g" $fsmotmp +sed -i "s/NETBIOSDOMAIN/$workgroup/g" $fsmotmp +sudo bin/ldbmodify -H $PREFIX/private/sam.ldb $fsmotmp +rm $fsmotmp diff --git a/source4/scripting/devel/drs/unvampire_ad.sh b/source4/scripting/devel/drs/unvampire_ad.sh new file mode 100755 index 0000000000..e4b9dccf1a --- /dev/null +++ b/source4/scripting/devel/drs/unvampire_ad.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -x + +. `dirname $0`/vars + + +bin/ldbdel -H ldap://$server.$DNSDOMAIN -U$workgroup/administrator%$pass "CN=$machine,CN=Computers,$dn" +bin/ldbdel -H ldap://$server.$DNSDOMAIN -U$workgroup/administrator%$pass "CN=$machine,OU=Domain Controllers,$dn" +bin/ldbdel -H ldap://$server.$DNSDOMAIN -U$workgroup/administrator%$pass "CN=NTDS Settings,CN=$machine,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,$dn" +bin/ldbdel -H ldap://$server.$DNSDOMAIN -U$workgroup/administrator%$pass "CN=$machine,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,$dn" +rm -f $PREFIX/private/*.ldb diff --git a/source4/scripting/devel/drs/vampire_ad.sh b/source4/scripting/devel/drs/vampire_ad.sh new file mode 100755 index 0000000000..baba02d5ac --- /dev/null +++ b/source4/scripting/devel/drs/vampire_ad.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -x + +. `dirname $0`/vars + +namedtmp=`mktemp named.conf.ad.XXXXXXXXX` +cp `dirname $0`/named.conf.ad.template $namedtmp +sed -i "s/DNSDOMAIN/$DNSDOMAIN/g" $namedtmp +sed -i "s/SERVERIP/$server_ip/g" $namedtmp +chmod a+r $namedtmp +mv -f $namedtmp $PREFIX/private/named.conf +sudo rndc reconfig +`dirname $0`/unvampire_ad.sh +sudo bin/net vampire $DNSDOMAIN -Uadministrator%$pass -s $PREFIX/etc/smb.conf -d2 || exit 1 +PRIVATEDIR=$PREFIX/private sudo -E scripting/bin/setup_dns.sh $machine $DNSDOMAIN $machine_ip || exit 1 +sudo rndc flush diff --git a/source4/scripting/devel/drs/vars b/source4/scripting/devel/drs/vars new file mode 100644 index 0000000000..e1fe53c61a --- /dev/null +++ b/source4/scripting/devel/drs/vars @@ -0,0 +1,11 @@ +DNSDOMAIN=ad.samba.example.com +PREFIX="/data/samba/samba4/prefix.ad" +export PYTHONPATH=$PYTHONPATH:$PREFIX/lib/python2.6/site-packages +pass="penguin" +machine="ruth" +machine_ip="192.168.122.1" +workgroup=adruth +dn="DC=ad,DC=samba,DC=example,DC=com" +server=win2008-1 +server_ip=192.168.122.53 + diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 82df4960cf..57cefdd137 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -234,14 +234,14 @@ class Ldb(ldb.Ldb): """ self.add_ldif(open(ldif_path, 'r').read()) - def add_ldif(self, ldif): + def add_ldif(self, ldif,controls=None): """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) + self.add(msg,controls) def modify_ldif(self, ldif): """Modify database based on a LDIF string. diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 64491c2b18..d7fadf3b7e 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -44,7 +44,7 @@ from credentials import Credentials, DONT_USE_KERBEROS from auth import system_session, admin_session from samba import version, Ldb, substitute_var, valid_netbios_name from samba import check_all_substituted -from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008, DS_DC_FUNCTION_2008_R2 +from samba import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008 from samba.samdb import SamDB from samba.idmap import IDmapDB from samba.dcerpc import security @@ -144,6 +144,11 @@ class ProvisionPaths(object): self.fedoradsinf = None self.fedoradspartitions = None self.fedoradssasl = None + self.fedoradspam = None + self.fedoradsrefint = None + self.fedoradslinkedattributes = None + self.fedoradsindex = None + self.fedoradssamba = None self.olmmron = None self.olmmrserveridsconf = None self.olmmrsyncreplconf = None @@ -210,6 +215,8 @@ class Schema(object): prefixmap = open(setup_path("prefixMap.txt"), 'r').read() prefixmap = b64encode(prefixmap) + + # We don't actually add this ldif, just parse it prefixmap_ldif = "dn: cn=schema\nprefixMap:: %s\n\n" % prefixmap self.ldb.set_schema_from_ldif(prefixmap_ldif, self.schema_data) @@ -288,17 +295,17 @@ def read_and_sub_file(file, subst_vars): return data -def setup_add_ldif(ldb, ldif_path, subst_vars=None): +def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]): """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. + :param nocontrols: Optional list of controls, can be None for no controls """ assert isinstance(ldif_path, str) - data = read_and_sub_file(ldif_path, subst_vars) - ldb.add_ldif(data) + ldb.add_ldif(data,controls) def setup_modify_ldif(ldb, ldif_path, subst_vars=None): @@ -332,7 +339,7 @@ def setup_ldb(ldb, ldif_path, subst_vars): ldb.transaction_commit() -def setup_file(template, fname, subst_vars): +def setup_file(template, fname, subst_vars=None): """Setup a file in the private dir. :param template: Path of the template file. @@ -362,6 +369,7 @@ def provision_paths_from_lp(lp, dnsdomain): 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.privilege = os.path.join(paths.private_dir, "privilege.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") @@ -386,8 +394,16 @@ def provision_paths_from_lp(lp, dnsdomain): "fedorads-partitions.ldif") paths.fedoradssasl = os.path.join(paths.ldapdir, "fedorads-sasl.ldif") + paths.fedoradspam = os.path.join(paths.ldapdir, + "fedorads-pam.ldif") + paths.fedoradsrefint = os.path.join(paths.ldapdir, + "fedorads-refint.ldif") + paths.fedoradslinkedattributes = os.path.join(paths.ldapdir, + "fedorads-linked-attributes.ldif") + paths.fedoradsindex = os.path.join(paths.ldapdir, + "fedorads-index.ldif") paths.fedoradssamba = os.path.join(paths.ldapdir, - "fedorads-samba.ldif") + "fedorads-samba.ldif") paths.olmmrserveridsconf = os.path.join(paths.ldapdir, "mmr_serverids.conf") paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, @@ -427,7 +443,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, hostname = hostname.lower() if dnsdomain is None: - dnsdomain = lp.get("realm") + dnsdomain = lp.get("realm").lower() if serverrole is None: serverrole = lp.get("server role") @@ -439,8 +455,6 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, raise Exception("realm '%s' in %s must match chosen realm '%s'" % (lp.get("realm"), lp.configfile, realm)) - dnsdomain = dnsdomain.lower() - if serverrole == "domain controller": if domain is None: domain = lp.get("workgroup") @@ -452,20 +466,21 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, else: domain = netbiosname if domaindn is None: - domaindn = "CN=" + netbiosname + domaindn = "DC=" + netbiosname assert domain is not None domain = domain.upper() + if not valid_netbios_name(domain): raise InvalidNetbiosName(domain) - if netbiosname.upper() == realm.upper(): + if netbiosname.upper() == realm: raise Exception("realm %s must not be equal to netbios domain name %s", realm, netbiosname) - if hostname.upper() == realm.upper(): + if hostname.upper() == realm: raise Exception("realm %s must not be equal to hostname %s", realm, hostname) - if domain.upper() == realm.upper(): + if domain.upper() == realm: raise Exception("realm %s must not be equal to domain name %s", realm, domain) if rootdn is None: @@ -614,6 +629,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, # - each partition has its own module list then modules_list = ["resolve_oids", "rootdse", + "lazy_commit", "acl", "paged_results", "ranged_results", @@ -628,7 +644,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "samldb", "password_hash", "operational", - "kludge_acl"] + "kludge_acl", + "instancetype"] tdb_modules_list = [ "subtree_rename", "subtree_delete", @@ -648,7 +665,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, if ldap_backend.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", "extended_dn_out_dereference"] + tdb_modules_list = ["extended_dn_out_dereference"] elif ldap_backend.ldap_backend_type == "openldap": backend_modules = ["entryuuid", "paged_searches"] # OpenLDAP handles subtree renames, so we don't want to do any of these things @@ -676,9 +693,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "CONFIGDN_LDB": configdn_ldb, "DOMAINDN": names.domaindn, "DOMAINDN_LDB": domaindn_ldb, - "SCHEMADN_MOD": "schema_fsmo,instancetype", - "CONFIGDN_MOD": "naming_fsmo,instancetype", - "DOMAINDN_MOD": "pdc_fsmo,instancetype", + "SCHEMADN_MOD": "schema_fsmo", + "CONFIGDN_MOD": "naming_fsmo", + "DOMAINDN_MOD": "pdc_fsmo", "MODULES_LIST": ",".join(modules_list), "TDB_MODULES_LIST": tdb_modules_list_as_string, "MODULES_LIST2": ",".join(modules_list2), @@ -814,6 +831,23 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): return secrets_ldb +def setup_privileges(path, setup_path, session_info, lp): + """Setup the privileges database. + + :param path: Path to the privileges database. + :param setup_path: Get the path to a setup file. + :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) + privilege_ldb = Ldb(path, session_info=session_info, lp=lp) + privilege_ldb.erase() + privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif")) + + def setup_registry(path, setup_path, session_info, lp): """Setup the registry. @@ -874,9 +908,14 @@ def setup_samdb_rootdse(samdb, setup_path, names): def setup_self_join(samdb, names, machinepass, dnspass, domainsid, invocationid, setup_path, - policyguid, policyguid_dc, domainControllerFunctionality): + policyguid, policyguid_dc, domainControllerFunctionality, + ntdsguid): """Join a host to its own domain.""" assert isinstance(invocationid, str) + if ntdsguid is not None: + ntdsguid_line = "objectGUID: %s\n"%ntdsguid + else: + ntdsguid_line = "" setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, @@ -892,6 +931,7 @@ def setup_self_join(samdb, names, "DOMAIN": names.domain, "DNSDOMAIN": names.dnsdomain, "SAMBA_VERSION_STRING": version, + "NTDSGUID": ntdsguid_line, "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)}) setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { @@ -925,23 +965,34 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, names, message, domainsid, domainguid, policyguid, policyguid_dc, fill, adminpass, krbtgtpass, - machinepass, invocationid, dnspass, - serverrole, schema=None, ldap_backend=None): + machinepass, invocationid, dnspass, ntdsguid, + serverrole, dom_for_fun_level=None, + schema=None, ldap_backend=None): """Setup a complete SAM Database. :note: This will wipe the main SAM database file! """ - # Do NOT change these default values without discussion with the team and reslease manager. - domainFunctionality = DS_DOMAIN_FUNCTION_2008 - forestFunctionality = DS_DOMAIN_FUNCTION_2008 + # ATTENTION: Do NOT change these default values without discussion with the + # team and/or release manager. They have a big impact on the whole program! domainControllerFunctionality = DS_DC_FUNCTION_2008 + if dom_for_fun_level is None: + dom_for_fun_level = DS_DOMAIN_FUNCTION_2003 + if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003: + raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This isn't supported!") + + 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!") + + domainFunctionality = dom_for_fun_level + forestFunctionality = dom_for_fun_level + # Also wipes the database setup_samdb_partitions(path, setup_path, message=message, lp=lp, credentials=credentials, session_info=session_info, - names=names, - ldap_backend=ldap_backend, serverrole=serverrole) + names=names, ldap_backend=ldap_backend, + serverrole=serverrole) if (schema == None): schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn, @@ -989,28 +1040,22 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb.set_invocation_id(invocationid) message("Adding DomainDN: %s" % names.domaindn) - if serverrole == "domain controller": - domain_oc = "domainDNS" - else: - domain_oc = "samba4LocalDomain" #impersonate domain admin admin_session_info = admin_session(lp, str(domainsid)) samdb.set_session_info(admin_session_info) - + if domainguid is not None: + domainguid_line = "objectGUID: %s\n-" % domainguid + else: + domainguid_line = "" setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { "DOMAINDN": names.domaindn, - "DOMAIN_OC": domain_oc + "DOMAINGUID": domainguid_line }) - message("Modifying DomainDN: " + names.domaindn + "") - if domainguid is not None: - domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid - else: - domainguid_mod = "" setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), { - "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks + "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks "DOMAINSID": str(domainsid), "SCHEMADN": names.schemadn, "NETBIOSNAME": names.netbiosname, @@ -1019,7 +1064,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "SERVERDN": names.serverdn, "POLICYGUID": policyguid, "DOMAINDN": names.domaindn, - "DOMAINGUID_MOD": domainguid_mod, "DOMAIN_FUNCTIONALITY": str(domainFunctionality), "SAMBA_VERSION_STRING": version }) @@ -1038,10 +1082,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, # The LDIF here was created when the Schema object was constructed message("Setting up sam.ldb schema") - samdb.add_ldif(schema.schema_dn_add) + samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"]) samdb.modify_ldif(schema.schema_dn_modify) samdb.write_prefixes_from_schema() - samdb.add_ldif(schema.schema_data) + samdb.add_ldif(schema.schema_data, controls=["relax:0"]) setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"), {"SCHEMADN": names.schemadn}) @@ -1078,7 +1122,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "DOMAINDN": names.domaindn}) message("Setting up sam.ldb data") setup_add_ldif(samdb, setup_path("provision.ldif"), { - "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks + "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks "DOMAINDN": names.domaindn, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": names.sitename, @@ -1105,7 +1149,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, domainsid=domainsid, policyguid=policyguid, policyguid_dc=policyguid_dc, setup_path=setup_path, - domainControllerFunctionality=domainControllerFunctionality) + domainControllerFunctionality=domainControllerFunctionality, + ntdsguid=ntdsguid) ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn) names.ntdsguid = samdb.searchone(basedn=ntds_dn, @@ -1134,9 +1179,10 @@ def provision(setup_dir, message, session_info, domainsid=None, adminpass=None, ldapadminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, policyguid_dc=None, invocationid=None, - machinepass=None, + machinepass=None, ntdsguid=None, dnspass=None, root=None, nobody=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, + wheel=None, backup=None, aci=None, serverrole=None, + dom_for_fun_level=None, ldap_backend_extra_port=None, ldap_backend_type=None, sitename=None, ol_mmr_urls=None, ol_olc=None, @@ -1155,7 +1201,6 @@ def provision(setup_dir, message, session_info, else: domainsid = security.dom_sid(domainsid) - # create/adapt the group policy GUIDs if policyguid is None: policyguid = str(uuid.uuid4()) @@ -1274,6 +1319,9 @@ def provision(setup_dir, message, session_info, setup_registry(paths.hklm, setup_path, session_info, lp=lp) + message("Setting up the privileges database") + setup_privileges(paths.privilege, setup_path, session_info, lp=lp) + message("Setting up idmap db") idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, lp=lp) @@ -1288,8 +1336,10 @@ def provision(setup_dir, message, session_info, fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass, invocationid=invocationid, - machinepass=machinepass, dnspass=dnspass, - serverrole=serverrole, ldap_backend=provision_backend) + machinepass=machinepass, dnspass=dnspass, + ntdsguid=ntdsguid, serverrole=serverrole, + dom_for_fun_level=dom_for_fun_level, + ldap_backend=provision_backend) if serverrole == "domain controller": if paths.netlogon is None: @@ -1352,9 +1402,9 @@ def provision(setup_dir, message, session_info, assert isinstance(domainguid, str) create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain, - domaindn=names.domaindn, hostip=hostip, + hostip=hostip, hostip6=hostip6, hostname=names.hostname, - dnspass=dnspass, realm=names.realm, + realm=names.realm, domainguid=domainguid, ntdsguid=names.ntdsguid) create_named_conf(paths.namedconf, setup_path, realm=names.realm, @@ -1897,6 +1947,44 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None, {"SAMBADN": names.sambadn, }) + setup_file(setup_path("fedorads-pam.ldif"), paths.fedoradspam) + + lnkattr = get_linked_attributes(names.schemadn,schema.ldb) + + refint_config = data = open(setup_path("fedorads-refint-delete.ldif"), 'r').read() + memberof_config = "" + index_config = "" + argnum = 3 + + for attr in lnkattr.keys(): + if lnkattr[attr] is not None: + refint_config += read_and_sub_file(setup_path("fedorads-refint-add.ldif"), + { "ARG_NUMBER" : str(argnum) , + "LINK_ATTR" : attr }) + memberof_config += read_and_sub_file(setup_path("fedorads-linked-attributes.ldif"), + { "MEMBER_ATTR" : attr , + "MEMBEROF_ATTR" : lnkattr[attr] }) + index_config += read_and_sub_file(setup_path("fedorads-index.ldif"), + { "ATTR" : attr }) + argnum += 1 + + open(paths.fedoradsrefint, 'w').write(refint_config) + open(paths.fedoradslinkedattributes, 'w').write(memberof_config) + + attrs = ["lDAPDisplayName"] + res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs) + + for i in range (0, len(res)): + attr = res[i]["lDAPDisplayName"][0] + + if attr == "objectGUID": + attr = "nsUniqueId" + + index_config += read_and_sub_file(setup_path("fedorads-index.ldif"), + { "ATTR" : attr }) + + open(paths.fedoradsindex, 'w').write(index_config) + setup_file(setup_path("fedorads-samba.ldif"), paths.fedoradssamba, {"SAMBADN": names.sambadn, "LDAPADMINPASS": ldapadminpass @@ -1957,8 +2045,8 @@ def create_phpldapadmin_config(path, setup_path, ldapi_uri): {"S4_LDAPI_URI": ldapi_uri}) -def create_zone_file(path, setup_path, dnsdomain, domaindn, - hostip, hostip6, hostname, dnspass, realm, domainguid, +def create_zone_file(path, setup_path, dnsdomain, + hostip, hostip6, hostname, realm, domainguid, ntdsguid): """Write out a DNS zone file, from the info in the current database. @@ -1969,7 +2057,6 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn, :param hostip: Local IPv4 IP :param hostip6: Local IPv6 IP :param hostname: Local hostname - :param dnspass: Password for DNS :param realm: Realm name :param domainguid: GUID of the domain. :param ntdsguid: GUID of the hosts nTDSDSA record. @@ -1991,7 +2078,6 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn, hostip_host_line = "" setup_file(setup_path("provision.zone"), path, { - "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": hostname, "DNSDOMAIN": dnsdomain, "REALM": realm, diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 8c7bb0ae98..d56f75b314 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, setup_templatesdb, make_smbconf, find_setup_dir +from samba.provision import setup_samdb, guess_names, make_smbconf, find_setup_dir from samba.samdb import SamDB from samba.tests import TestCaseInTempDir from samba.dcerpc import security @@ -71,8 +71,6 @@ class SamDBTestCase(TestCaseInTempDir): serverrole=serverrole, domaindn=self.domaindn, configdn=configdn, schemadn=schemadn) - setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"), - self.setup_path, session_info=session_info, lp=self.lp) self.samdb = setup_samdb(path, self.setup_path, session_info, creds, self.lp, names, lambda x: None, domainsid, @@ -82,7 +80,7 @@ class SamDBTestCase(TestCaseInTempDir): "secret", "domain controller") def tearDown(self): - for f in ['templates.ldb', 'schema.ldb', 'configuration.ldb', + for f in ['schema.ldb', 'configuration.ldb', 'users.ldb', 'samdb.ldb', 'smb.conf']: os.remove(os.path.join(self.tempdir, f)) super(SamDBTestCase, self).tearDown() |