s4-provision Add an invalid names check for 'domain == netbiosname'
[nivanova/samba-autobuild/.git] / source4 / scripting / python / samba / provision / __init__.py
1
2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
4
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
7 # Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
8 #
9 # Based on the original in EJS:
10 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 #
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 3 of the License, or
15 # (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 #
25
26 """Functions for setting up a Samba configuration."""
27
28 __docformat__ = "restructuredText"
29
30 from base64 import b64encode
31 import os
32 import re
33 import pwd
34 import grp
35 import logging
36 import time
37 import uuid
38 import socket
39 import urllib
40 import shutil
41
42 import ldb
43
44 from samba.auth import system_session, admin_session
45 import samba
46 from samba import (
47     Ldb,
48     check_all_substituted,
49     in_source_tree,
50     read_and_sub_file,
51     setup_file,
52     substitute_var,
53     valid_netbios_name,
54     version,
55     )
56 from samba.dcerpc import security
57 from samba.dcerpc.misc import (
58     SEC_CHAN_BDC,
59     SEC_CHAN_WKSTA,
60     )
61 from samba.dsdb import (
62     DS_DOMAIN_FUNCTION_2003,
63     DS_DOMAIN_FUNCTION_2008_R2,
64     ENC_ALL_TYPES,
65     )
66 from samba.idmap import IDmapDB
67 from samba.ms_display_specifiers import read_ms_ldif
68 from samba.ntacls import setntacl, dsacl2fsacl
69 from samba.ndr import ndr_pack, ndr_unpack
70 from samba.provision.backend import (
71     ExistingBackend,
72     FDSBackend,
73     LDBBackend,
74     OpenLDAPBackend,
75     )
76 import samba.param
77 import samba.registry
78 from samba.schema import Schema
79 from samba.samdb import SamDB
80
81 VALID_NETBIOS_CHARS = " !#$%&'()-.@^_{}~"
82 DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
83 DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04fB984F9"
84 DEFAULTSITE = "Default-First-Site-Name"
85 LAST_PROVISION_USN_ATTRIBUTE = "lastProvisionUSN"
86
87
88 def find_setup_dir():
89     """Find the setup directory used by provision."""
90     if in_source_tree():
91         # In source tree
92         dirname = os.path.dirname(__file__)
93         return os.path.normpath(os.path.join(dirname, "../../../../setup"))
94     else:
95         import sys
96         for prefix in [sys.prefix,
97                 os.path.join(os.path.dirname(__file__), "../../../../..")]:
98             for suffix in ["share/setup", "share/samba/setup", "setup"]:
99                 ret = os.path.normpath(os.path.join(prefix, suffix))
100                 if os.path.isdir(ret):
101                     return ret
102         raise Exception("Unable to find setup directory.")
103
104 # Descriptors of naming contexts and other important objects
105
106 # "get_schema_descriptor" is located in "schema.py"
107
108 def get_sites_descriptor(domain_sid):
109     sddl = "O:EAG:EAD:AI(A;;RPLCLORC;;;AU)" \
110            "(A;;RPWPCRCCLCLORCWOWDSW;;;EA)" \
111            "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
112            "(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
113            "(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
114            "S:AI(AU;CISA;CCDCSDDT;;;WD)" \
115            "(OU;CIIOSA;CR;;f0f8ffab-1191-11d0-a060-00aa006c33ed;WD)" \
116            "(OU;CIIOSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \
117            "(OU;CIIOSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \
118            "(OU;CIIOSA;WP;3e10944c-c354-11d0-aff8-0000f80367c1;b7b13124-b82e-11d0-afee-0000f80367c1;WD)"
119     sec = security.descriptor.from_sddl(sddl, domain_sid)
120     return ndr_pack(sec)
121
122
123 def get_config_descriptor(domain_sid):
124     sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
125            "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
126            "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
127            "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
128            "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
129            "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
130            "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
131            "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
132            "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
133            "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
134            "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
135            "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
136            "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
137            "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
138            "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
139     sec = security.descriptor.from_sddl(sddl, domain_sid)
140     return ndr_pack(sec)
141
142
143 def get_domain_descriptor(domain_sid):
144     sddl= "O:BAG:BAD:AI(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
145         "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
146     "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
147     "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
148     "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
149     "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
150     "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
151     "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
152     "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
153     "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
154     "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
155     "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;DD)" \
156     "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
157     "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
158     "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
159     "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
160     "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
161     "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
162     "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
163     "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
164     "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
165     "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;IF)" \
166     "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
167     "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
168     "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
169     "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
170     "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
171     "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
172     "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
173     "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
174     "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
175     "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
176     "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
177     "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
178     "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
179     "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
180     "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
181     "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
182     "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
183     "(A;;RPRC;;;RU)" \
184     "(A;CI;LC;;;RU)" \
185     "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
186     "(A;;RP;;;WD)" \
187     "(A;;RPLCLORC;;;ED)" \
188     "(A;;RPLCLORC;;;AU)" \
189     "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
190     "S:AI(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
191     "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
192     "(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPWOWD;;;WD)"
193     sec = security.descriptor.from_sddl(sddl, domain_sid)
194     return ndr_pack(sec)
195
196
197 class ProvisionPaths(object):
198
199     def __init__(self):
200         self.shareconf = None
201         self.hklm = None
202         self.hkcu = None
203         self.hkcr = None
204         self.hku = None
205         self.hkpd = None
206         self.hkpt = None
207         self.samdb = None
208         self.idmapdb = None
209         self.secrets = None
210         self.keytab = None
211         self.dns_keytab = None
212         self.dns = None
213         self.winsdb = None
214         self.private_dir = None
215
216
217 class ProvisionNames(object):
218
219     def __init__(self):
220         self.rootdn = None
221         self.domaindn = None
222         self.configdn = None
223         self.schemadn = None
224         self.ldapmanagerdn = None
225         self.dnsdomain = None
226         self.realm = None
227         self.netbiosname = None
228         self.domain = None
229         self.hostname = None
230         self.sitename = None
231         self.smbconf = None
232
233
234 def update_provision_usn(samdb, low, high, replace=False):
235     """Update the field provisionUSN in sam.ldb
236
237     This field is used to track range of USN modified by provision and
238     upgradeprovision.
239     This value is used afterward by next provision to figure out if
240     the field have been modified since last provision.
241
242     :param samdb: An LDB object connect to sam.ldb
243     :param low: The lowest USN modified by this upgrade
244     :param high: The highest USN modified by this upgrade
245     :param replace: A boolean indicating if the range should replace any
246                     existing one or appended (default)
247     """
248
249     tab = []
250     if not replace:
251         entry = samdb.search(expression="(&(dn=@PROVISION)(%s=*))" %
252                                 LAST_PROVISION_USN_ATTRIBUTE, base="",
253                                 scope=ldb.SCOPE_SUBTREE,
254                                 attrs=[LAST_PROVISION_USN_ATTRIBUTE, "dn"])
255         for e in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
256             tab.append(str(e))
257
258     tab.append("%s-%s" % (low, high))
259     delta = ldb.Message()
260     delta.dn = ldb.Dn(samdb, "@PROVISION")
261     delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
262         ldb.FLAG_MOD_REPLACE, LAST_PROVISION_USN_ATTRIBUTE)
263     samdb.modify(delta)
264
265
266 def set_provision_usn(samdb, low, high):
267     """Set the field provisionUSN in sam.ldb
268     This field is used to track range of USN modified by provision and
269     upgradeprovision.
270     This value is used afterward by next provision to figure out if
271     the field have been modified since last provision.
272
273     :param samdb: An LDB object connect to sam.ldb
274     :param low: The lowest USN modified by this upgrade
275     :param high: The highest USN modified by this upgrade"""
276     tab = []
277     tab.append("%s-%s" % (low, high))
278     delta = ldb.Message()
279     delta.dn = ldb.Dn(samdb, "@PROVISION")
280     delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
281         ldb.FLAG_MOD_ADD, LAST_PROVISION_USN_ATTRIBUTE)
282     samdb.add(delta)
283
284
285 def get_max_usn(samdb,basedn):
286     """ This function return the biggest USN present in the provision
287
288     :param samdb: A LDB object pointing to the sam.ldb
289     :param basedn: A string containing the base DN of the provision
290                     (ie. DC=foo, DC=bar)
291     :return: The biggest USN in the provision"""
292
293     res = samdb.search(expression="objectClass=*",base=basedn,
294                          scope=ldb.SCOPE_SUBTREE,attrs=["uSNChanged"],
295                          controls=["search_options:1:2",
296                                    "server_sort:1:1:uSNChanged",
297                                    "paged_results:1:1"])
298     return res[0]["uSNChanged"]
299
300
301 def get_last_provision_usn(sam):
302     """Get the lastest USN modified by a provision or an upgradeprovision
303
304     :param sam: An LDB object pointing to the sam.ldb
305     :return: an integer corresponding to the highest USN modified by
306         (upgrade)provision, 0 is this value is unknown
307     """
308     entry = sam.search(expression="(&(dn=@PROVISION)(%s=*))" %
309                         LAST_PROVISION_USN_ATTRIBUTE,
310                         base="", scope=ldb.SCOPE_SUBTREE,
311                         attrs=[LAST_PROVISION_USN_ATTRIBUTE])
312     if len(entry):
313         range = []
314         idx = 0
315         p = re.compile(r'-')
316         for r in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
317             tab = p.split(str(r))
318             range.append(tab[0])
319             range.append(tab[1])
320             idx = idx + 1
321         return range
322     else:
323         return None
324
325
326 class ProvisionResult(object):
327
328     def __init__(self):
329         self.paths = None
330         self.domaindn = None
331         self.lp = None
332         self.samdb = None
333
334
335 def check_install(lp, session_info, credentials):
336     """Check whether the current install seems ok.
337
338     :param lp: Loadparm context
339     :param session_info: Session information
340     :param credentials: Credentials
341     """
342     if lp.get("realm") == "":
343         raise Exception("Realm empty")
344     samdb = Ldb(lp.get("sam database"), session_info=session_info,
345             credentials=credentials, lp=lp)
346     if len(samdb.search("(cn=Administrator)")) != 1:
347         raise ProvisioningError("No administrator account found")
348
349
350 def findnss(nssfn, names):
351     """Find a user or group from a list of possibilities.
352
353     :param nssfn: NSS Function to try (should raise KeyError if not found)
354     :param names: Names to check.
355     :return: Value return by first names list.
356     """
357     for name in names:
358         try:
359             return nssfn(name)
360         except KeyError:
361             pass
362     raise KeyError("Unable to find user/group in %r" % names)
363
364
365 findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
366 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
367
368
369 def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
370     """Setup a ldb in the private dir.
371
372     :param ldb: LDB file to import data into
373     :param ldif_path: Path of the LDIF file to load
374     :param subst_vars: Optional variables to subsitute in LDIF.
375     :param nocontrols: Optional list of controls, can be None for no controls
376     """
377     assert isinstance(ldif_path, str)
378     data = read_and_sub_file(ldif_path, subst_vars)
379     ldb.add_ldif(data, controls)
380
381
382 def setup_modify_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
383     """Modify a ldb in the private dir.
384
385     :param ldb: LDB object.
386     :param ldif_path: LDIF file path.
387     :param subst_vars: Optional dictionary with substitution variables.
388     """
389     data = read_and_sub_file(ldif_path, subst_vars)
390     ldb.modify_ldif(data, controls)
391
392
393 def setup_ldb(ldb, ldif_path, subst_vars):
394     """Import a LDIF a file into a LDB handle, optionally substituting
395     variables.
396
397     :note: Either all LDIF data will be added or none (using transactions).
398
399     :param ldb: LDB file to import into.
400     :param ldif_path: Path to the LDIF file.
401     :param subst_vars: Dictionary with substitution variables.
402     """
403     assert ldb is not None
404     ldb.transaction_start()
405     try:
406         setup_add_ldif(ldb, ldif_path, subst_vars)
407     except Exception:
408         ldb.transaction_cancel()
409         raise
410     else:
411         ldb.transaction_commit()
412
413
414 def provision_paths_from_lp(lp, dnsdomain):
415     """Set the default paths for provisioning.
416
417     :param lp: Loadparm context.
418     :param dnsdomain: DNS Domain name
419     """
420     paths = ProvisionPaths()
421     paths.private_dir = lp.get("private dir")
422
423     # This is stored without path prefix for the "privateKeytab" attribute in
424     # "secrets_dns.ldif".
425     paths.dns_keytab = "dns.keytab"
426     paths.keytab = "secrets.keytab"
427
428     paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
429     paths.samdb = os.path.join(paths.private_dir,
430         lp.get("sam database") or "samdb.ldb")
431     paths.idmapdb = os.path.join(paths.private_dir,
432         lp.get("idmap database") or "idmap.ldb")
433     paths.secrets = os.path.join(paths.private_dir,
434         lp.get("secrets database") or "secrets.ldb")
435     paths.privilege = os.path.join(paths.private_dir, "privilege.ldb")
436     paths.dns = os.path.join(paths.private_dir, "dns", dnsdomain + ".zone")
437     paths.dns_update_list = os.path.join(paths.private_dir, "dns_update_list")
438     paths.spn_update_list = os.path.join(paths.private_dir, "spn_update_list")
439     paths.namedconf = os.path.join(paths.private_dir, "named.conf")
440     paths.namedconf_update = os.path.join(paths.private_dir, "named.conf.update")
441     paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
442     paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
443     paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
444     paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
445     paths.phpldapadminconfig = os.path.join(paths.private_dir,
446                                             "phpldapadmin-config.php")
447     paths.hklm = "hklm.ldb"
448     paths.hkcr = "hkcr.ldb"
449     paths.hkcu = "hkcu.ldb"
450     paths.hku = "hku.ldb"
451     paths.hkpd = "hkpd.ldb"
452     paths.hkpt = "hkpt.ldb"
453     paths.sysvol = lp.get("path", "sysvol")
454     paths.netlogon = lp.get("path", "netlogon")
455     paths.smbconf = lp.configfile
456     return paths
457
458
459 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
460                 serverrole=None, rootdn=None, domaindn=None, configdn=None,
461                 schemadn=None, serverdn=None, sitename=None):
462     """Guess configuration settings to use."""
463
464     if hostname is None:
465         hostname = socket.gethostname().split(".")[0]
466
467     netbiosname = lp.get("netbios name")
468     if netbiosname is None:
469         netbiosname = hostname
470         # remove forbidden chars
471         newnbname = ""
472         for x in netbiosname:
473             if x.isalnum() or x in VALID_NETBIOS_CHARS:
474                 newnbname = "%s%c" % (newnbname, x)
475         # force the length to be <16
476         netbiosname = newnbname[0:15]
477     assert netbiosname is not None
478     netbiosname = netbiosname.upper()
479     if not valid_netbios_name(netbiosname):
480         raise InvalidNetbiosName(netbiosname)
481
482     if dnsdomain is None:
483         dnsdomain = lp.get("realm")
484         if dnsdomain is None or dnsdomain == "":
485             raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp.configfile)
486
487     dnsdomain = dnsdomain.lower()
488
489     if serverrole is None:
490         serverrole = lp.get("server role")
491         if serverrole is None:
492             raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp.configfile)
493
494     serverrole = serverrole.lower()
495
496     realm = dnsdomain.upper()
497
498     if lp.get("realm") == "":
499         raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s.  Please remove the smb.conf file and let provision generate it" % lp.configfile)
500
501     if lp.get("realm").upper() != realm:
502         raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'!  Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), realm, lp.configfile))
503
504     if lp.get("server role").lower() != serverrole:
505         raise ProvisioningError("guess_names: 'server role=%s' in %s must match chosen server role '%s'!  Please remove the smb.conf file and let provision generate it" % (lp.get("server role").upper(), serverrole, lp.configfile))
506
507     if serverrole == "domain controller":
508         if domain is None:
509             # This will, for better or worse, default to 'WORKGROUP'
510             domain = lp.get("workgroup")
511         domain = domain.upper()
512
513         if lp.get("workgroup").upper() != domain:
514             raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'!  Please remove the %s file and let provision generate it" % (lp.get("workgroup").upper(), domain, lp.configfile))
515
516         if domaindn is None:
517             domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
518
519         if domain == netbiosname:
520             raise ProvisioningError("guess_names: Domain '%s' must not be equal to short host name '%s'!" % (domain, netbiosname))
521     else:
522         domain = netbiosname
523         if domaindn is None:
524             domaindn = "DC=" + netbiosname
525
526     if not valid_netbios_name(domain):
527         raise InvalidNetbiosName(domain)
528
529     if hostname.upper() == realm:
530         raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm, hostname))
531     if netbiosname.upper() == realm:
532         raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!" % (realm, netbiosname))
533     if domain == realm:
534         raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm, domain))
535
536     if rootdn is None:
537        rootdn = domaindn
538
539     if configdn is None:
540         configdn = "CN=Configuration," + rootdn
541     if schemadn is None:
542         schemadn = "CN=Schema," + configdn
543
544     if sitename is None:
545         sitename=DEFAULTSITE
546
547     names = ProvisionNames()
548     names.rootdn = rootdn
549     names.domaindn = domaindn
550     names.configdn = configdn
551     names.schemadn = schemadn
552     names.ldapmanagerdn = "CN=Manager," + rootdn
553     names.dnsdomain = dnsdomain
554     names.domain = domain
555     names.realm = realm
556     names.netbiosname = netbiosname
557     names.hostname = hostname
558     names.sitename = sitename
559     names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (
560         netbiosname, sitename, configdn)
561
562     return names
563
564
565 def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
566                  targetdir, sid_generator="internal", eadb=False, lp=None):
567     """Create a new smb.conf file based on a couple of basic settings.
568     """
569     assert smbconf is not None
570     if hostname is None:
571         hostname = socket.gethostname().split(".")[0]
572         netbiosname = hostname.upper()
573         # remove forbidden chars
574         newnbname = ""
575         for x in netbiosname:
576             if x.isalnum() or x in VALID_NETBIOS_CHARS:
577                 newnbname = "%s%c" % (newnbname, x)
578         #force the length to be <16
579         netbiosname = newnbname[0:15]
580     else:
581         netbiosname = hostname.upper()
582
583     if serverrole is None:
584         serverrole = "standalone"
585
586     assert serverrole in ("domain controller", "member server", "standalone")
587     if serverrole == "domain controller":
588         smbconfsuffix = "dc"
589     elif serverrole == "member server":
590         smbconfsuffix = "member"
591     elif serverrole == "standalone":
592         smbconfsuffix = "standalone"
593
594     if sid_generator is None:
595         sid_generator = "internal"
596
597     assert domain is not None
598     domain = domain.upper()
599
600     assert realm is not None
601     realm = realm.upper()
602
603     if lp is None:
604         lp = samba.param.LoadParm()
605     #Load non-existant file
606     if os.path.exists(smbconf):
607         lp.load(smbconf)
608     if eadb and not lp.get("posix:eadb"):
609         if targetdir is not None:
610             privdir = os.path.join(targetdir, "private")
611         else:
612             privdir = lp.get("private dir")
613         lp.set("posix:eadb", os.path.abspath(os.path.join(privdir, "eadb.tdb")))
614
615     if targetdir is not None:
616         privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
617         lockdir_line = "lock dir = " + os.path.abspath(targetdir)
618
619         lp.set("lock dir", os.path.abspath(targetdir))
620     else:
621         privatedir_line = ""
622         lockdir_line = ""
623
624     if sid_generator == "internal":
625         sid_generator_line = ""
626     else:
627         sid_generator_line = "sid generator = " + sid_generator
628
629     used_setup_dir = setup_path("")
630     default_setup_dir = lp.get("setup directory")
631     setupdir_line = ""
632     if used_setup_dir != default_setup_dir:
633         setupdir_line = "setup directory = %s" % used_setup_dir
634         lp.set("setup directory", used_setup_dir)
635
636     sysvol = os.path.join(lp.get("lock dir"), "sysvol")
637     netlogon = os.path.join(sysvol, realm.lower(), "scripts")
638
639     setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
640                smbconf, {
641             "NETBIOS_NAME": netbiosname,
642             "DOMAIN": domain,
643             "REALM": realm,
644             "SERVERROLE": serverrole,
645             "NETLOGONPATH": netlogon,
646             "SYSVOLPATH": sysvol,
647             "SETUPDIRECTORY_LINE": setupdir_line,
648             "SIDGENERATOR_LINE": sid_generator_line,
649             "PRIVATEDIR_LINE": privatedir_line,
650             "LOCKDIR_LINE": lockdir_line
651             })
652
653     # reload the smb.conf
654     lp.load(smbconf)
655
656     # and dump it without any values that are the default
657     # this ensures that any smb.conf parameters that were set
658     # on the provision/join command line are set in the resulting smb.conf
659     f = open(smbconf, mode='w')
660     lp.dump(f, False)
661     f.close()
662
663
664
665 def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
666                         users_gid, wheel_gid):
667     """setup reasonable name mappings for sam names to unix names.
668
669     :param samdb: SamDB object.
670     :param idmap: IDmap db object.
671     :param sid: The domain sid.
672     :param domaindn: The domain DN.
673     :param root_uid: uid of the UNIX root user.
674     :param nobody_uid: uid of the UNIX nobody user.
675     :param users_gid: gid of the UNIX users group.
676     :param wheel_gid: gid of the UNIX wheel group.
677     """
678     idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
679     idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
680
681     idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
682     idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
683
684
685 def setup_samdb_partitions(samdb_path, setup_path, logger, lp, session_info,
686                            provision_backend, names, schema, serverrole,
687                            erase=False):
688     """Setup the partitions for the SAM database.
689
690     Alternatively, provision() may call this, and then populate the database.
691
692     :note: This will wipe the Sam Database!
693
694     :note: This function always removes the local SAM LDB file. The erase
695         parameter controls whether to erase the existing data, which
696         may not be stored locally but in LDAP.
697
698     """
699     assert session_info is not None
700
701     # We use options=["modules:"] to stop the modules loading - we
702     # just want to wipe and re-initialise the database, not start it up
703
704     try:
705         os.unlink(samdb_path)
706     except OSError:
707         pass
708
709     samdb = Ldb(url=samdb_path, session_info=session_info,
710                 lp=lp, options=["modules:"])
711
712     ldap_backend_line = "# No LDAP backend"
713     if provision_backend.type is not "ldb":
714         ldap_backend_line = "ldapBackend: %s" % provision_backend.ldap_uri
715
716     samdb.transaction_start()
717     try:
718         logger.info("Setting up sam.ldb partitions and settings")
719         setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
720                 "SCHEMADN": ldb.Dn(schema.ldb, names.schemadn).get_casefold(),
721                 "CONFIGDN": ldb.Dn(schema.ldb, names.configdn).get_casefold(),
722                 "DOMAINDN": ldb.Dn(schema.ldb, names.domaindn).get_casefold(),
723                 "LDAP_BACKEND_LINE": ldap_backend_line,
724         })
725
726
727         setup_add_ldif(samdb, setup_path("provision_init.ldif"), {
728                 "BACKEND_TYPE": provision_backend.type,
729                 "SERVER_ROLE": serverrole
730                 })
731
732         logger.info("Setting up sam.ldb rootDSE")
733         setup_samdb_rootdse(samdb, setup_path, names)
734     except Exception:
735         samdb.transaction_cancel()
736         raise
737     else:
738         samdb.transaction_commit()
739
740
741 def secretsdb_self_join(secretsdb, domain,
742                         netbiosname, machinepass, domainsid=None,
743                         realm=None, dnsdomain=None,
744                         keytab_path=None,
745                         key_version_number=1,
746                         secure_channel_type=SEC_CHAN_WKSTA):
747     """Add domain join-specific bits to a secrets database.
748
749     :param secretsdb: Ldb Handle to the secrets database
750     :param machinepass: Machine password
751     """
752     attrs = ["whenChanged",
753            "secret",
754            "priorSecret",
755            "priorChanged",
756            "krb5Keytab",
757            "privateKeytab"]
758
759     if realm is not None:
760         if dnsdomain is None:
761             dnsdomain = realm.lower()
762         dnsname = '%s.%s' % (netbiosname.lower(), dnsdomain.lower())
763     else:
764         dnsname = None
765     shortname = netbiosname.lower()
766
767     # We don't need to set msg["flatname"] here, because rdn_name will handle
768     # it, and it causes problems for modifies anyway
769     msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain))
770     msg["secureChannelType"] = [str(secure_channel_type)]
771     msg["objectClass"] = ["top", "primaryDomain"]
772     if dnsname is not None:
773         msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
774         msg["realm"] = [realm]
775         msg["saltPrincipal"] = ["host/%s@%s" % (dnsname, realm.upper())]
776         msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
777         msg["privateKeytab"] = ["secrets.keytab"]
778
779     msg["secret"] = [machinepass]
780     msg["samAccountName"] = ["%s$" % netbiosname]
781     msg["secureChannelType"] = [str(secure_channel_type)]
782     if domainsid is not None:
783         msg["objectSid"] = [ndr_pack(domainsid)]
784
785     # This complex expression tries to ensure that we don't have more
786     # than one record for this SID, realm or netbios domain at a time,
787     # but we don't delete the old record that we are about to modify,
788     # because that would delete the keytab and previous password.
789     res = secretsdb.search(base="cn=Primary Domains", attrs=attrs,
790         expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(dn=%s)))" % (domain, realm, str(domainsid), str(msg.dn))),
791         scope=ldb.SCOPE_ONELEVEL)
792
793     for del_msg in res:
794         secretsdb.delete(del_msg.dn)
795
796     res = secretsdb.search(base=msg.dn, attrs=attrs, scope=ldb.SCOPE_BASE)
797
798     if len(res) == 1:
799         msg["priorSecret"] = [res[0]["secret"][0]]
800         msg["priorWhenChanged"] = [res[0]["whenChanged"][0]]
801
802         try:
803             msg["privateKeytab"] = [res[0]["privateKeytab"][0]]
804         except KeyError:
805             pass
806
807         try:
808             msg["krb5Keytab"] = [res[0]["krb5Keytab"][0]]
809         except KeyError:
810             pass
811
812         for el in msg:
813             if el != 'dn':
814                 msg[el].set_flags(ldb.FLAG_MOD_REPLACE)
815         secretsdb.modify(msg)
816         secretsdb.rename(res[0].dn, msg.dn)
817     else:
818         spn = [ 'HOST/%s' % shortname ]
819         if secure_channel_type == SEC_CHAN_BDC and dnsname is not None:
820             # we are a domain controller then we add servicePrincipalName
821             # entries for the keytab code to update.
822             spn.extend([ 'HOST/%s' % dnsname ])
823         msg["servicePrincipalName"] = spn
824
825         secretsdb.add(msg)
826
827
828 def secretsdb_setup_dns(secretsdb, setup_path, names, private_dir, realm,
829                         dnsdomain, dns_keytab_path, dnspass):
830     """Add DNS specific bits to a secrets database.
831
832     :param secretsdb: Ldb Handle to the secrets database
833     :param setup_path: Setup path function
834     :param machinepass: Machine password
835     """
836     try:
837         os.unlink(os.path.join(private_dir, dns_keytab_path))
838     except OSError:
839         pass
840
841     setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
842             "REALM": realm,
843             "DNSDOMAIN": dnsdomain,
844             "DNS_KEYTAB": dns_keytab_path,
845             "DNSPASS_B64": b64encode(dnspass),
846             "HOSTNAME": names.hostname,
847             "DNSNAME" : '%s.%s' % (
848                 names.netbiosname.lower(), names.dnsdomain.lower())
849             })
850
851
852 def setup_secretsdb(paths, setup_path, session_info, backend_credentials, lp):
853     """Setup the secrets database.
854
855    :note: This function does not handle exceptions and transaction on purpose,
856        it's up to the caller to do this job.
857
858     :param path: Path to the secrets database.
859     :param setup_path: Get the path to a setup file.
860     :param session_info: Session info.
861     :param credentials: Credentials
862     :param lp: Loadparm context
863     :return: LDB handle for the created secrets database
864     """
865     if os.path.exists(paths.secrets):
866         os.unlink(paths.secrets)
867
868     keytab_path = os.path.join(paths.private_dir, paths.keytab)
869     if os.path.exists(keytab_path):
870         os.unlink(keytab_path)
871
872     dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
873     if os.path.exists(dns_keytab_path):
874         os.unlink(dns_keytab_path)
875
876     path = paths.secrets
877
878     secrets_ldb = Ldb(path, session_info=session_info,
879                       lp=lp)
880     secrets_ldb.erase()
881     secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
882     secrets_ldb = Ldb(path, session_info=session_info,
883                       lp=lp)
884     secrets_ldb.transaction_start()
885     try:
886         secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
887
888         if (backend_credentials is not None and
889             backend_credentials.authentication_requested()):
890             if backend_credentials.get_bind_dn() is not None:
891                 setup_add_ldif(secrets_ldb,
892                     setup_path("secrets_simple_ldap.ldif"), {
893                         "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
894                         "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
895                         })
896             else:
897                 setup_add_ldif(secrets_ldb,
898                     setup_path("secrets_sasl_ldap.ldif"), {
899                         "LDAPADMINUSER": backend_credentials.get_username(),
900                         "LDAPADMINREALM": backend_credentials.get_realm(),
901                         "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
902                         })
903
904         return secrets_ldb
905     except Exception:
906         secrets_ldb.transaction_cancel()
907         raise
908
909
910 def setup_privileges(path, setup_path, session_info, lp):
911     """Setup the privileges database.
912
913     :param path: Path to the privileges database.
914     :param setup_path: Get the path to a setup file.
915     :param session_info: Session info.
916     :param credentials: Credentials
917     :param lp: Loadparm context
918     :return: LDB handle for the created secrets database
919     """
920     if os.path.exists(path):
921         os.unlink(path)
922     privilege_ldb = Ldb(path, session_info=session_info, lp=lp)
923     privilege_ldb.erase()
924     privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
925
926
927 def setup_registry(path, setup_path, session_info, lp):
928     """Setup the registry.
929
930     :param path: Path to the registry database
931     :param setup_path: Function that returns the path to a setup.
932     :param session_info: Session information
933     :param credentials: Credentials
934     :param lp: Loadparm context
935     """
936     reg = samba.registry.Registry()
937     hive = samba.registry.open_ldb(path, session_info=session_info, lp_ctx=lp)
938     reg.mount_hive(hive, samba.registry.HKEY_LOCAL_MACHINE)
939     provision_reg = setup_path("provision.reg")
940     assert os.path.exists(provision_reg)
941     reg.diff_apply(provision_reg)
942
943
944 def setup_idmapdb(path, setup_path, session_info, lp):
945     """Setup the idmap database.
946
947     :param path: path to the idmap database
948     :param setup_path: Function that returns a path to a setup file
949     :param session_info: Session information
950     :param credentials: Credentials
951     :param lp: Loadparm context
952     """
953     if os.path.exists(path):
954         os.unlink(path)
955
956     idmap_ldb = IDmapDB(path, session_info=session_info, lp=lp)
957     idmap_ldb.erase()
958     idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
959     return idmap_ldb
960
961
962 def setup_samdb_rootdse(samdb, setup_path, names):
963     """Setup the SamDB rootdse.
964
965     :param samdb: Sam Database handle
966     :param setup_path: Obtain setup path
967     """
968     setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
969         "SCHEMADN": names.schemadn,
970         "DOMAINDN": names.domaindn,
971         "ROOTDN": names.rootdn,
972         "CONFIGDN": names.configdn,
973         "SERVERDN": names.serverdn,
974         })
975
976
977 def setup_self_join(samdb, names, machinepass, dnspass,
978                     domainsid, next_rid, invocationid, setup_path,
979                     policyguid, policyguid_dc, domainControllerFunctionality,
980                     ntdsguid):
981     """Join a host to its own domain."""
982     assert isinstance(invocationid, str)
983     if ntdsguid is not None:
984         ntdsguid_line = "objectGUID: %s\n"%ntdsguid
985     else:
986         ntdsguid_line = ""
987     setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
988               "CONFIGDN": names.configdn,
989               "SCHEMADN": names.schemadn,
990               "DOMAINDN": names.domaindn,
991               "SERVERDN": names.serverdn,
992               "INVOCATIONID": invocationid,
993               "NETBIOSNAME": names.netbiosname,
994               "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
995               "MACHINEPASS_B64": b64encode(machinepass.encode('utf-16-le')),
996               "DOMAINSID": str(domainsid),
997               "DCRID": str(next_rid),
998               "SAMBA_VERSION_STRING": version,
999               "NTDSGUID": ntdsguid_line,
1000               "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
1001                   domainControllerFunctionality)})
1002
1003     setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
1004               "POLICYGUID": policyguid,
1005               "POLICYGUID_DC": policyguid_dc,
1006               "DNSDOMAIN": names.dnsdomain,
1007               "DOMAINDN": names.domaindn})
1008
1009     # add the NTDSGUID based SPNs
1010     ntds_dn = "CN=NTDS Settings,%s" % names.serverdn
1011     names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
1012                                      expression="", scope=ldb.SCOPE_BASE)
1013     assert isinstance(names.ntdsguid, str)
1014
1015     # Setup fSMORoleOwner entries to point at the newly created DC entry
1016     setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
1017               "DOMAINDN": names.domaindn,
1018               "CONFIGDN": names.configdn,
1019               "SCHEMADN": names.schemadn,
1020               "DEFAULTSITE": names.sitename,
1021               "SERVERDN": names.serverdn,
1022               "NETBIOSNAME": names.netbiosname,
1023               "RIDALLOCATIONSTART": str(next_rid + 100),
1024               "RIDALLOCATIONEND": str(next_rid + 100 + 499),
1025               })
1026
1027     # This is partially Samba4 specific and should be replaced by the correct
1028     # DNS AD-style setup
1029     setup_add_ldif(samdb, setup_path("provision_dns_add.ldif"), {
1030               "DNSDOMAIN": names.dnsdomain,
1031               "DOMAINDN": names.domaindn,
1032               "DNSPASS_B64": b64encode(dnspass.encode('utf-16-le')),
1033               "HOSTNAME" : names.hostname,
1034               "DNSNAME" : '%s.%s' % (
1035                   names.netbiosname.lower(), names.dnsdomain.lower())
1036               })
1037
1038
1039 def getpolicypath(sysvolpath, dnsdomain, guid):
1040     """Return the physical path of policy given its guid.
1041
1042     :param sysvolpath: Path to the sysvol folder
1043     :param dnsdomain: DNS name of the AD domain
1044     :param guid: The GUID of the policy
1045     :return: A string with the complete path to the policy folder
1046     """
1047
1048     if guid[0] != "{":
1049         guid = "{%s}" % guid
1050     policy_path = os.path.join(sysvolpath, dnsdomain, "Policies", guid)
1051     return policy_path
1052
1053
1054 def create_gpo_struct(policy_path):
1055     if not os.path.exists(policy_path):
1056         os.makedirs(policy_path, 0775)
1057     open(os.path.join(policy_path, "GPT.INI"), 'w').write(
1058                       "[General]\r\nVersion=0")
1059     p = os.path.join(policy_path, "MACHINE")
1060     if not os.path.exists(p):
1061         os.makedirs(p, 0775)
1062     p = os.path.join(policy_path, "USER")
1063     if not os.path.exists(p):
1064         os.makedirs(p, 0775)
1065
1066
1067 def create_default_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc):
1068     """Create the default GPO for a domain
1069
1070     :param sysvolpath: Physical path for the sysvol folder
1071     :param dnsdomain: DNS domain name of the AD domain
1072     :param policyguid: GUID of the default domain policy
1073     :param policyguid_dc: GUID of the default domain controler policy
1074     """
1075     policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid)
1076     create_gpo_struct(policy_path)
1077
1078     policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid_dc)
1079     create_gpo_struct(policy_path)
1080
1081
1082 def setup_samdb(path, setup_path, session_info, provision_backend, lp, names,
1083         logger, domainsid, domainguid, policyguid, policyguid_dc, fill,
1084         adminpass, krbtgtpass, machinepass, invocationid, dnspass, ntdsguid,
1085         serverrole, am_rodc=False, dom_for_fun_level=None, schema=None,
1086         next_rid=1000):
1087     """Setup a complete SAM Database.
1088
1089     :note: This will wipe the main SAM database file!
1090     """
1091
1092     # Provision does not make much sense values larger than 1000000000
1093     # as the upper range of the rIDAvailablePool is 1073741823 and
1094     # we don't want to create a domain that cannot allocate rids.
1095     if next_rid < 1000 or next_rid > 1000000000:
1096         error = "You want to run SAMBA 4 with a next_rid of %u, " % (next_rid)
1097         error += "the valid range is %u-%u. The default is %u." % (
1098             1000, 1000000000, 1000)
1099         raise ProvisioningError(error)
1100
1101     # ATTENTION: Do NOT change these default values without discussion with the
1102     # team and/or release manager. They have a big impact on the whole program!
1103     domainControllerFunctionality = DS_DOMAIN_FUNCTION_2008_R2
1104
1105     if dom_for_fun_level is None:
1106         dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
1107
1108     if dom_for_fun_level > domainControllerFunctionality:
1109         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_R2). This won't work!")
1110
1111     domainFunctionality = dom_for_fun_level
1112     forestFunctionality = dom_for_fun_level
1113
1114     # Also wipes the database
1115     setup_samdb_partitions(path, setup_path, logger=logger, lp=lp,
1116         provision_backend=provision_backend, session_info=session_info,
1117         names=names, serverrole=serverrole, schema=schema)
1118
1119     if schema is None:
1120         schema = Schema(setup_path, domainsid, schemadn=names.schemadn)
1121
1122     # Load the database, but don's load the global schema and don't connect
1123     # quite yet
1124     samdb = SamDB(session_info=session_info, url=None, auto_connect=False,
1125                   credentials=provision_backend.credentials, lp=lp,
1126                   global_schema=False, am_rodc=am_rodc)
1127
1128     logger.info("Pre-loading the Samba 4 and AD schema")
1129
1130     # Load the schema from the one we computed earlier
1131     samdb.set_schema(schema)
1132
1133     # Set the NTDS settings DN manually - in order to have it already around
1134     # before the provisioned tree exists and we connect
1135     samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
1136
1137     # And now we can connect to the DB - the schema won't be loaded from the
1138     # DB
1139     samdb.connect(path)
1140
1141     if fill == FILL_DRS:
1142         return samdb
1143
1144     samdb.transaction_start()
1145     try:
1146         # Set the domain functionality levels onto the database.
1147         # Various module (the password_hash module in particular) need
1148         # to know what level of AD we are emulating.
1149
1150         # These will be fixed into the database via the database
1151         # modifictions below, but we need them set from the start.
1152         samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
1153         samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
1154         samdb.set_opaque_integer("domainControllerFunctionality",
1155             domainControllerFunctionality)
1156
1157         samdb.set_domain_sid(str(domainsid))
1158         samdb.set_invocation_id(invocationid)
1159
1160         logger.info("Adding DomainDN: %s" % names.domaindn)
1161
1162         # impersonate domain admin
1163         admin_session_info = admin_session(lp, str(domainsid))
1164         samdb.set_session_info(admin_session_info)
1165         if domainguid is not None:
1166             domainguid_line = "objectGUID: %s\n-" % domainguid
1167         else:
1168             domainguid_line = ""
1169
1170         descr = b64encode(get_domain_descriptor(domainsid))
1171         setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
1172                 "DOMAINDN": names.domaindn,
1173                 "DOMAINSID": str(domainsid),
1174                 "DESCRIPTOR": descr,
1175                 "DOMAINGUID": domainguid_line
1176                 })
1177
1178         setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
1179             "DOMAINDN": names.domaindn,
1180             "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
1181             "NEXTRID": str(next_rid),
1182             "DEFAULTSITE": names.sitename,
1183             "CONFIGDN": names.configdn,
1184             "POLICYGUID": policyguid,
1185             "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
1186             "SAMBA_VERSION_STRING": version
1187             })
1188
1189         logger.info("Adding configuration container")
1190         descr = b64encode(get_config_descriptor(domainsid))
1191         setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
1192             "CONFIGDN": names.configdn,
1193             "DESCRIPTOR": descr,
1194             })
1195
1196         # The LDIF here was created when the Schema object was constructed
1197         logger.info("Setting up sam.ldb schema")
1198         samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"])
1199         samdb.modify_ldif(schema.schema_dn_modify)
1200         samdb.write_prefixes_from_schema()
1201         samdb.add_ldif(schema.schema_data, controls=["relax:0"])
1202         setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
1203                        {"SCHEMADN": names.schemadn})
1204
1205         logger.info("Reopening sam.ldb with new schema")
1206     except Exception:
1207         samdb.transaction_cancel()
1208         raise
1209     else:
1210         samdb.transaction_commit()
1211
1212     samdb = SamDB(session_info=admin_session_info, auto_connect=False,
1213                 credentials=provision_backend.credentials, lp=lp,
1214                 global_schema=False, am_rodc=am_rodc)
1215
1216     # Set the NTDS settings DN manually - in order to have it already around
1217     # before the provisioned tree exists and we connect
1218     samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
1219     samdb.connect(path)
1220
1221     samdb.transaction_start()
1222     try:
1223         samdb.invocation_id = invocationid
1224
1225         logger.info("Setting up sam.ldb configuration data")
1226         descr = b64encode(get_sites_descriptor(domainsid))
1227         setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
1228             "CONFIGDN": names.configdn,
1229             "NETBIOSNAME": names.netbiosname,
1230             "DEFAULTSITE": names.sitename,
1231             "DNSDOMAIN": names.dnsdomain,
1232             "DOMAIN": names.domain,
1233             "SCHEMADN": names.schemadn,
1234             "DOMAINDN": names.domaindn,
1235             "SERVERDN": names.serverdn,
1236             "FOREST_FUNCTIONALITY": str(forestFunctionality),
1237             "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
1238             "SITES_DESCRIPTOR": descr
1239             })
1240
1241         logger.info("Setting up display specifiers")
1242         display_specifiers_ldif = read_ms_ldif(
1243             setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1244         display_specifiers_ldif = substitute_var(display_specifiers_ldif,
1245             {"CONFIGDN": names.configdn})
1246         check_all_substituted(display_specifiers_ldif)
1247         samdb.add_ldif(display_specifiers_ldif)
1248
1249         logger.info("Adding users container")
1250         setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
1251                 "DOMAINDN": names.domaindn})
1252         logger.info("Modifying users container")
1253         setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
1254                 "DOMAINDN": names.domaindn})
1255         logger.info("Adding computers container")
1256         setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
1257                 "DOMAINDN": names.domaindn})
1258         logger.info("Modifying computers container")
1259         setup_modify_ldif(samdb,
1260             setup_path("provision_computers_modify.ldif"), {
1261                 "DOMAINDN": names.domaindn})
1262         logger.info("Setting up sam.ldb data")
1263         setup_add_ldif(samdb, setup_path("provision.ldif"), {
1264             "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
1265             "DOMAINDN": names.domaindn,
1266             "NETBIOSNAME": names.netbiosname,
1267             "DEFAULTSITE": names.sitename,
1268             "CONFIGDN": names.configdn,
1269             "SERVERDN": names.serverdn,
1270             "RIDAVAILABLESTART": str(next_rid + 600),
1271             "POLICYGUID_DC": policyguid_dc
1272             })
1273
1274         setup_modify_ldif(samdb,
1275             setup_path("provision_basedn_references.ldif"), {
1276                 "DOMAINDN": names.domaindn})
1277
1278         setup_modify_ldif(samdb,
1279             setup_path("provision_configuration_references.ldif"), {
1280                 "CONFIGDN": names.configdn,
1281                 "SCHEMADN": names.schemadn})
1282         if fill == FILL_FULL:
1283             logger.info("Setting up sam.ldb users and groups")
1284             setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
1285                 "DOMAINDN": names.domaindn,
1286                 "DOMAINSID": str(domainsid),
1287                 "CONFIGDN": names.configdn,
1288                 "ADMINPASS_B64": b64encode(adminpass.encode('utf-16-le')),
1289                 "KRBTGTPASS_B64": b64encode(krbtgtpass.encode('utf-16-le'))
1290                 })
1291
1292             logger.info("Setting up self join")
1293             setup_self_join(samdb, names=names, invocationid=invocationid,
1294                 dnspass=dnspass,
1295                 machinepass=machinepass,
1296                 domainsid=domainsid,
1297                 next_rid=next_rid,
1298                 policyguid=policyguid,
1299                 policyguid_dc=policyguid_dc,
1300                 setup_path=setup_path,
1301                 domainControllerFunctionality=domainControllerFunctionality,
1302                 ntdsguid=ntdsguid)
1303
1304             ntds_dn = "CN=NTDS Settings,%s" % names.serverdn
1305             names.ntdsguid = samdb.searchone(basedn=ntds_dn,
1306                 attribute="objectGUID", expression="", scope=ldb.SCOPE_BASE)
1307             assert isinstance(names.ntdsguid, str)
1308     except Exception:
1309         samdb.transaction_cancel()
1310         raise
1311     else:
1312         samdb.transaction_commit()
1313         return samdb
1314
1315
1316 FILL_FULL = "FULL"
1317 FILL_NT4SYNC = "NT4SYNC"
1318 FILL_DRS = "DRS"
1319 SYSVOL_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
1320 POLICIES_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001301bf;;;PA)"
1321
1322
1323 def set_dir_acl(path, acl, lp, domsid):
1324     setntacl(lp, path, acl, domsid)
1325     for root, dirs, files in os.walk(path, topdown=False):
1326         for name in files:
1327             setntacl(lp, os.path.join(root, name), acl, domsid)
1328         for name in dirs:
1329             setntacl(lp, os.path.join(root, name), acl, domsid)
1330
1331
1332 def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp):
1333     """Set ACL on the sysvol/<dnsname>/Policies folder and the policy
1334     folders beneath.
1335
1336     :param sysvol: Physical path for the sysvol folder
1337     :param dnsdomain: The DNS name of the domain
1338     :param domainsid: The SID of the domain
1339     :param domaindn: The DN of the domain (ie. DC=...)
1340     :param samdb: An LDB object on the SAM db
1341     :param lp: an LP object
1342     """
1343
1344     # Set ACL for GPO root folder
1345     root_policy_path = os.path.join(sysvol, dnsdomain, "Policies")
1346     setntacl(lp, root_policy_path, POLICIES_ACL, str(domainsid))
1347
1348     res = samdb.search(base="CN=Policies,CN=System,%s"%(domaindn),
1349                         attrs=["cn", "nTSecurityDescriptor"],
1350                         expression="", scope=ldb.SCOPE_ONELEVEL)
1351
1352     for policy in res:
1353         acl = ndr_unpack(security.descriptor,
1354                          str(policy["nTSecurityDescriptor"])).as_sddl()
1355         policy_path = getpolicypath(sysvol, dnsdomain, str(policy["cn"]))
1356         set_dir_acl(policy_path, dsacl2fsacl(acl, str(domainsid)), lp,
1357                     str(domainsid))
1358
1359
1360 def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn,
1361     lp):
1362     """Set the ACL for the sysvol share and the subfolders
1363
1364     :param samdb: An LDB object on the SAM db
1365     :param netlogon: Physical path for the netlogon folder
1366     :param sysvol: Physical path for the sysvol folder
1367     :param gid: The GID of the "Domain adminstrators" group
1368     :param domainsid: The SID of the domain
1369     :param dnsdomain: The DNS name of the domain
1370     :param domaindn: The DN of the domain (ie. DC=...)
1371     """
1372
1373     try:
1374         os.chown(sysvol, -1, gid)
1375     except OSError:
1376         canchown = False
1377     else:
1378         canchown = True
1379
1380     # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
1381     setntacl(lp,sysvol, SYSVOL_ACL, str(domainsid))
1382     for root, dirs, files in os.walk(sysvol, topdown=False):
1383         for name in files:
1384             if canchown:
1385                 os.chown(os.path.join(root, name), -1, gid)
1386             setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
1387         for name in dirs:
1388             if canchown:
1389                 os.chown(os.path.join(root, name), -1, gid)
1390             setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
1391
1392     # Set acls on Policy folder and policies folders
1393     set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp)
1394
1395
1396 def provision(setup_dir, logger, session_info, credentials, smbconf=None,
1397         targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None,
1398         domaindn=None, schemadn=None, configdn=None, serverdn=None,
1399         domain=None, hostname=None, hostip=None, hostip6=None, domainsid=None,
1400         next_rid=1000, adminpass=None, ldapadminpass=None, krbtgtpass=None,
1401         domainguid=None, policyguid=None, policyguid_dc=None,
1402         invocationid=None, machinepass=None, ntdsguid=None, dnspass=None,
1403         root=None, nobody=None, users=None, wheel=None, backup=None, aci=None,
1404         serverrole=None, dom_for_fun_level=None, ldap_backend_extra_port=None,
1405         ldap_backend_forced_uri=None, backend_type=None, sitename=None,
1406         ol_mmr_urls=None, ol_olc=None, setup_ds_path=None, slapd_path=None,
1407         nosync=False, ldap_dryrun_mode=False, useeadb=False, am_rodc=False,
1408         lp=None):
1409     """Provision samba4
1410
1411     :note: caution, this wipes all existing data!
1412     """
1413
1414     def setup_path(file):
1415         return os.path.join(setup_dir, file)
1416
1417     if domainsid is None:
1418         domainsid = security.random_sid()
1419     else:
1420         domainsid = security.dom_sid(domainsid)
1421
1422     # create/adapt the group policy GUIDs
1423     # Default GUID for default policy are described at
1424     # "How Core Group Policy Works"
1425     # http://technet.microsoft.com/en-us/library/cc784268%28WS.10%29.aspx
1426     if policyguid is None:
1427         policyguid = DEFAULT_POLICY_GUID
1428     policyguid = policyguid.upper()
1429     if policyguid_dc is None:
1430         policyguid_dc = DEFAULT_DC_POLICY_GUID
1431     policyguid_dc = policyguid_dc.upper()
1432
1433     if adminpass is None:
1434         adminpass = samba.generate_random_password(12, 32)
1435     if krbtgtpass is None:
1436         krbtgtpass = samba.generate_random_password(128, 255)
1437     if machinepass is None:
1438         machinepass  = samba.generate_random_password(128, 255)
1439     if dnspass is None:
1440         dnspass = samba.generate_random_password(128, 255)
1441     if ldapadminpass is None:
1442         # Make a new, random password between Samba and it's LDAP server
1443         ldapadminpass=samba.generate_random_password(128, 255)
1444
1445     if backend_type is None:
1446         backend_type = "ldb"
1447
1448     sid_generator = "internal"
1449     if backend_type == "fedora-ds":
1450         sid_generator = "backend"
1451
1452     root_uid = findnss_uid([root or "root"])
1453     nobody_uid = findnss_uid([nobody or "nobody"])
1454     users_gid = findnss_gid([users or "users", 'users', 'other', 'staff'])
1455     if wheel is None:
1456         wheel_gid = findnss_gid(["wheel", "adm"])
1457     else:
1458         wheel_gid = findnss_gid([wheel])
1459     try:
1460         bind_gid = findnss_gid(["bind", "named"])
1461     except KeyError:
1462         bind_gid = None
1463
1464     if targetdir is not None:
1465         smbconf = os.path.join(targetdir, "etc", "smb.conf")
1466     elif smbconf is None:
1467         smbconf = samba.param.default_path()
1468     if not os.path.exists(os.path.dirname(smbconf)):
1469         os.makedirs(os.path.dirname(smbconf))
1470
1471     # only install a new smb.conf if there isn't one there already
1472     if os.path.exists(smbconf):
1473         # if Samba Team members can't figure out the weird errors
1474         # loading an empty smb.conf gives, then we need to be smarter.
1475         # Pretend it just didn't exist --abartlet
1476         data = open(smbconf, 'r').read()
1477         data = data.lstrip()
1478         if data is None or data == "":
1479             make_smbconf(smbconf, setup_path, hostname, domain, realm,
1480                          serverrole, targetdir, sid_generator, useeadb,
1481                          lp=lp)
1482     else:
1483         make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
1484                      targetdir, sid_generator, useeadb, lp=lp)
1485
1486     if lp is None:
1487         lp = samba.param.LoadParm()
1488     lp.load(smbconf)
1489     names = guess_names(lp=lp, hostname=hostname, domain=domain,
1490         dnsdomain=realm, serverrole=serverrole, domaindn=domaindn,
1491         configdn=configdn, schemadn=schemadn, serverdn=serverdn,
1492         sitename=sitename)
1493     paths = provision_paths_from_lp(lp, names.dnsdomain)
1494
1495     paths.bind_gid = bind_gid
1496
1497     if hostip is None:
1498         logger.info("Looking up IPv4 addresses")
1499         hostips = samba.interface_ips(lp, False)
1500         if len(hostips) == 0:
1501             logger.warning("No external IPv4 address has been found. Using loopback.")
1502             hostip = '127.0.0.1'
1503         else:
1504             hostip = hostips[0]
1505             if len(hostips) > 1:
1506                 logger.warning("More than one IPv4 address found. Using %s.",
1507                     hostip)
1508
1509     if serverrole is None:
1510         serverrole = lp.get("server role")
1511
1512     assert serverrole in ("domain controller", "member server", "standalone")
1513     if invocationid is None:
1514         invocationid = str(uuid.uuid4())
1515
1516     if not os.path.exists(paths.private_dir):
1517         os.mkdir(paths.private_dir)
1518     if not os.path.exists(os.path.join(paths.private_dir, "tls")):
1519         os.mkdir(os.path.join(paths.private_dir, "tls"))
1520
1521     ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
1522
1523     schema = Schema(setup_path, domainsid, invocationid=invocationid,
1524         schemadn=names.schemadn)
1525
1526     if backend_type == "ldb":
1527         provision_backend = LDBBackend(backend_type, paths=paths,
1528             setup_path=setup_path, lp=lp, credentials=credentials,
1529             names=names, logger=logger)
1530     elif backend_type == "existing":
1531         provision_backend = ExistingBackend(backend_type, paths=paths,
1532             setup_path=setup_path, lp=lp, credentials=credentials,
1533             names=names, logger=logger,
1534             ldap_backend_forced_uri=ldap_backend_forced_uri)
1535     elif backend_type == "fedora-ds":
1536         provision_backend = FDSBackend(backend_type, paths=paths,
1537             setup_path=setup_path, lp=lp, credentials=credentials,
1538             names=names, logger=logger, domainsid=domainsid,
1539             schema=schema, hostname=hostname, ldapadminpass=ldapadminpass,
1540             slapd_path=slapd_path,
1541             ldap_backend_extra_port=ldap_backend_extra_port,
1542             ldap_dryrun_mode=ldap_dryrun_mode, root=root,
1543             setup_ds_path=setup_ds_path,
1544             ldap_backend_forced_uri=ldap_backend_forced_uri)
1545     elif backend_type == "openldap":
1546         provision_backend = OpenLDAPBackend(backend_type, paths=paths,
1547             setup_path=setup_path, lp=lp, credentials=credentials,
1548             names=names, logger=logger, domainsid=domainsid,
1549             schema=schema, hostname=hostname, ldapadminpass=ldapadminpass,
1550             slapd_path=slapd_path,
1551             ldap_backend_extra_port=ldap_backend_extra_port,
1552             ldap_dryrun_mode=ldap_dryrun_mode, ol_mmr_urls=ol_mmr_urls,
1553             nosync=nosync,
1554             ldap_backend_forced_uri=ldap_backend_forced_uri)
1555     else:
1556         raise ValueError("Unknown LDAP backend type selected")
1557
1558     provision_backend.init()
1559     provision_backend.start()
1560
1561     # only install a new shares config db if there is none
1562     if not os.path.exists(paths.shareconf):
1563         logger.info("Setting up share.ldb")
1564         share_ldb = Ldb(paths.shareconf, session_info=session_info,
1565                         lp=lp)
1566         share_ldb.load_ldif_file_add(setup_path("share.ldif"))
1567
1568     logger.info("Setting up secrets.ldb")
1569     secrets_ldb = setup_secretsdb(paths, setup_path,
1570         session_info=session_info,
1571         backend_credentials=provision_backend.secrets_credentials, lp=lp)
1572
1573     try:
1574         logger.info("Setting up the registry")
1575         setup_registry(paths.hklm, setup_path, session_info,
1576                        lp=lp)
1577
1578         logger.info("Setting up the privileges database")
1579         setup_privileges(paths.privilege, setup_path, session_info, lp=lp)
1580
1581         logger.info("Setting up idmap db")
1582         idmap = setup_idmapdb(paths.idmapdb, setup_path,
1583             session_info=session_info, lp=lp)
1584
1585         logger.info("Setting up SAM db")
1586         samdb = setup_samdb(paths.samdb, setup_path, session_info,
1587             provision_backend, lp, names, logger=logger,
1588             domainsid=domainsid, schema=schema, domainguid=domainguid,
1589             policyguid=policyguid, policyguid_dc=policyguid_dc,
1590             fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass,
1591             invocationid=invocationid, machinepass=machinepass,
1592             dnspass=dnspass, ntdsguid=ntdsguid, serverrole=serverrole,
1593             dom_for_fun_level=dom_for_fun_level, am_rodc=am_rodc,
1594             next_rid=next_rid)
1595
1596         if serverrole == "domain controller":
1597             if paths.netlogon is None:
1598                 logger.info("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1599                 logger.info("Please either remove %s or see the template at %s" %
1600                         (paths.smbconf, setup_path("provision.smb.conf.dc")))
1601                 assert paths.netlogon is not None
1602
1603             if paths.sysvol is None:
1604                 logger.info("Existing smb.conf does not have a [sysvol] share, but you"
1605                         " are configuring a DC.")
1606                 logger.info("Please either remove %s or see the template at %s" %
1607                         (paths.smbconf, setup_path("provision.smb.conf.dc")))
1608                 assert paths.sysvol is not None
1609
1610             if not os.path.isdir(paths.netlogon):
1611                 os.makedirs(paths.netlogon, 0755)
1612
1613         if samdb_fill == FILL_FULL:
1614             setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
1615                                 root_uid=root_uid, nobody_uid=nobody_uid,
1616                                 users_gid=users_gid, wheel_gid=wheel_gid)
1617
1618             if serverrole == "domain controller":
1619                 # Set up group policies (domain policy and domain controller
1620                 # policy)
1621                 create_default_gpo(paths.sysvol, names.dnsdomain, policyguid,
1622                     policyguid_dc)
1623                 setsysvolacl(samdb, paths.netlogon, paths.sysvol, wheel_gid,
1624                     domainsid, names.dnsdomain, names.domaindn, lp)
1625
1626             logger.info("Setting up sam.ldb rootDSE marking as synchronized")
1627             setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
1628
1629             secretsdb_self_join(secrets_ldb, domain=names.domain,
1630                 realm=names.realm, dnsdomain=names.dnsdomain,
1631                 netbiosname=names.netbiosname, domainsid=domainsid,
1632                 machinepass=machinepass, secure_channel_type=SEC_CHAN_BDC)
1633
1634             # Now set up the right msDS-SupportedEncryptionTypes into the DB
1635             # In future, this might be determined from some configuration
1636             kerberos_enctypes = str(ENC_ALL_TYPES)
1637
1638             try:
1639                 msg = ldb.Message(ldb.Dn(samdb,
1640                     samdb.searchone("distinguishedName",
1641                         expression="samAccountName=%s$" % names.netbiosname,
1642                         scope=ldb.SCOPE_SUBTREE)))
1643                 msg["msDS-SupportedEncryptionTypes"] = ldb.MessageElement(
1644                     elements=kerberos_enctypes, flags=ldb.FLAG_MOD_REPLACE,
1645                     name="msDS-SupportedEncryptionTypes")
1646                 samdb.modify(msg)
1647             except ldb.LdbError, (enum, estr):
1648                 if enum != ldb.ERR_NO_SUCH_ATTRIBUTE:
1649                     # It might be that this attribute does not exist in this schema
1650                     raise
1651
1652             if serverrole == "domain controller":
1653                 secretsdb_setup_dns(secrets_ldb, setup_path, names,
1654                     paths.private_dir, realm=names.realm,
1655                     dnsdomain=names.dnsdomain,
1656                     dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
1657
1658                 domainguid = samdb.searchone(basedn=domaindn,
1659                     attribute="objectGUID")
1660                 assert isinstance(domainguid, str)
1661
1662                 # Only make a zone file on the first DC, it should be
1663                 # replicated with DNS replication
1664                 create_zone_file(lp, logger, paths, targetdir, setup_path,
1665                     dnsdomain=names.dnsdomain, hostip=hostip, hostip6=hostip6,
1666                     hostname=names.hostname, realm=names.realm,
1667                     domainguid=domainguid, ntdsguid=names.ntdsguid)
1668
1669                 create_named_conf(paths, setup_path, realm=names.realm,
1670                     dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
1671
1672                 create_named_txt(paths.namedtxt, setup_path,
1673                     realm=names.realm, dnsdomain=names.dnsdomain,
1674                     private_dir=paths.private_dir,
1675                     keytab_name=paths.dns_keytab)
1676                 logger.info("See %s for an example configuration include file for BIND", paths.namedconf)
1677                 logger.info("and %s for further documentation required for secure DNS "
1678                         "updates", paths.namedtxt)
1679
1680             lastProvisionUSNs = get_last_provision_usn(samdb)
1681             maxUSN = get_max_usn(samdb, str(names.rootdn))
1682             if lastProvisionUSNs is not None:
1683                 update_provision_usn(samdb, 0, maxUSN, 1)
1684             else:
1685                 set_provision_usn(samdb, 0, maxUSN)
1686
1687         create_krb5_conf(paths.krb5conf, setup_path,
1688                          dnsdomain=names.dnsdomain, hostname=names.hostname,
1689                          realm=names.realm)
1690         logger.info("A Kerberos configuration suitable for Samba 4 has been "
1691                     "generated at %s", paths.krb5conf)
1692
1693         if serverrole == "domain controller":
1694             create_dns_update_list(lp, logger, paths, setup_path)
1695
1696         provision_backend.post_setup()
1697         provision_backend.shutdown()
1698
1699         create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
1700                                    ldapi_url)
1701     except Exception:
1702         secrets_ldb.transaction_cancel()
1703         raise
1704
1705     # Now commit the secrets.ldb to disk
1706     secrets_ldb.transaction_commit()
1707
1708     # the commit creates the dns.keytab, now chown it
1709     dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
1710     if os.path.isfile(dns_keytab_path) and paths.bind_gid is not None:
1711         try:
1712             os.chmod(dns_keytab_path, 0640)
1713             os.chown(dns_keytab_path, -1, paths.bind_gid)
1714         except OSError:
1715             if not os.environ.has_key('SAMBA_SELFTEST'):
1716                 logger.info("Failed to chown %s to bind gid %u",
1717                             dns_keytab_path, paths.bind_gid)
1718
1719
1720     logger.info("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php",
1721             paths.phpldapadminconfig)
1722
1723     logger.info("Once the above files are installed, your Samba4 server will be ready to use")
1724     logger.info("Server Role:           %s" % serverrole)
1725     logger.info("Hostname:              %s" % names.hostname)
1726     logger.info("NetBIOS Domain:        %s" % names.domain)
1727     logger.info("DNS Domain:            %s" % names.dnsdomain)
1728     logger.info("DOMAIN SID:            %s" % str(domainsid))
1729     if samdb_fill == FILL_FULL:
1730         logger.info("Admin password:        %s" % adminpass)
1731     if provision_backend.type is not "ldb":
1732         if provision_backend.credentials.get_bind_dn() is not None:
1733             logger.info("LDAP Backend Admin DN: %s" %
1734                 provision_backend.credentials.get_bind_dn())
1735         else:
1736             logger.info("LDAP Admin User:       %s" %
1737                 provision_backend.credentials.get_username())
1738
1739         logger.info("LDAP Admin Password:   %s" %
1740             provision_backend.credentials.get_password())
1741
1742         if provision_backend.slapd_command_escaped is not None:
1743             # now display slapd_command_file.txt to show how slapd must be
1744             # started next time
1745             logger.info("Use later the following commandline to start slapd, then Samba:")
1746             logger.info(provision_backend.slapd_command_escaped)
1747             logger.info("This slapd-Commandline is also stored under: %s/ldap_backend_startup.sh",
1748                     provision_backend.ldapdir)
1749
1750     result = ProvisionResult()
1751     result.domaindn = domaindn
1752     result.paths = paths
1753     result.lp = lp
1754     result.samdb = samdb
1755     return result
1756
1757
1758 def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None,
1759         realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None,
1760         serverdn=None, domain=None, hostname=None, domainsid=None,
1761         adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None,
1762         policyguid_dc=None, invocationid=None, machinepass=None, dnspass=None,
1763         root=None, nobody=None, users=None, wheel=None, backup=None,
1764         serverrole=None, ldap_backend=None, ldap_backend_type=None,
1765         sitename=None, debuglevel=1):
1766
1767     logger = logging.getLogger("provision")
1768     samba.set_debug_level(debuglevel)
1769
1770     res = provision(setup_dir, logger, system_session(), None,
1771         smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
1772         realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
1773         configdn=configdn, serverdn=serverdn, domain=domain,
1774         hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
1775         machinepass=machinepass, serverrole="domain controller",
1776         sitename=sitename)
1777     res.lp.set("debuglevel", str(debuglevel))
1778     return res
1779
1780
1781 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
1782     """Create a PHP LDAP admin configuration file.
1783
1784     :param path: Path to write the configuration to.
1785     :param setup_path: Function to generate setup paths.
1786     """
1787     setup_file(setup_path("phpldapadmin-config.php"), path,
1788             {"S4_LDAPI_URI": ldapi_uri})
1789
1790
1791 def create_zone_file(lp, logger, paths, targetdir, setup_path, dnsdomain,
1792                      hostip, hostip6, hostname, realm, domainguid,
1793                      ntdsguid):
1794     """Write out a DNS zone file, from the info in the current database.
1795
1796     :param paths: paths object
1797     :param setup_path: Setup path function.
1798     :param dnsdomain: DNS Domain name
1799     :param domaindn: DN of the Domain
1800     :param hostip: Local IPv4 IP
1801     :param hostip6: Local IPv6 IP
1802     :param hostname: Local hostname
1803     :param realm: Realm name
1804     :param domainguid: GUID of the domain.
1805     :param ntdsguid: GUID of the hosts nTDSDSA record.
1806     """
1807     assert isinstance(domainguid, str)
1808
1809     if hostip6 is not None:
1810         hostip6_base_line = "            IN AAAA    " + hostip6
1811         hostip6_host_line = hostname + "        IN AAAA    " + hostip6
1812         gc_msdcs_ip6_line = "gc._msdcs               IN AAAA    " + hostip6
1813     else:
1814         hostip6_base_line = ""
1815         hostip6_host_line = ""
1816         gc_msdcs_ip6_line = ""
1817
1818     if hostip is not None:
1819         hostip_base_line = "            IN A    " + hostip
1820         hostip_host_line = hostname + "        IN A    " + hostip
1821         gc_msdcs_ip_line = "gc._msdcs               IN A    " + hostip
1822     else:
1823         hostip_base_line = ""
1824         hostip_host_line = ""
1825         gc_msdcs_ip_line = ""
1826
1827     dns_dir = os.path.dirname(paths.dns)
1828
1829     try:
1830         shutil.rmtree(dns_dir, True)
1831     except OSError:
1832         pass
1833
1834     os.mkdir(dns_dir, 0775)
1835
1836     # we need to freeze the zone while we update the contents
1837     if targetdir is None:
1838         rndc = ' '.join(lp.get("rndc command"))
1839         os.system(rndc + " freeze " + lp.get("realm"))
1840
1841     setup_file(setup_path("provision.zone"), paths.dns, {
1842             "HOSTNAME": hostname,
1843             "DNSDOMAIN": dnsdomain,
1844             "REALM": realm,
1845             "HOSTIP_BASE_LINE": hostip_base_line,
1846             "HOSTIP_HOST_LINE": hostip_host_line,
1847             "DOMAINGUID": domainguid,
1848             "DATESTRING": time.strftime("%Y%m%d%H"),
1849             "DEFAULTSITE": DEFAULTSITE,
1850             "NTDSGUID": ntdsguid,
1851             "HOSTIP6_BASE_LINE": hostip6_base_line,
1852             "HOSTIP6_HOST_LINE": hostip6_host_line,
1853             "GC_MSDCS_IP_LINE": gc_msdcs_ip_line,
1854             "GC_MSDCS_IP6_LINE": gc_msdcs_ip6_line,
1855         })
1856
1857     # note that we use no variable substitution on this file
1858     # the substitution is done at runtime by samba_dnsupdate
1859     setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
1860
1861     # and the SPN update list
1862     setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
1863
1864     if paths.bind_gid is not None:
1865         try:
1866             os.chown(dns_dir, -1, paths.bind_gid)
1867             os.chown(paths.dns, -1, paths.bind_gid)
1868             # chmod needed to cope with umask
1869             os.chmod(dns_dir, 0775)
1870             os.chmod(paths.dns, 0664)
1871         except OSError:
1872             if not os.environ.has_key('SAMBA_SELFTEST'):
1873                 logger.error("Failed to chown %s to bind gid %u" % (
1874                     dns_dir, paths.bind_gid))
1875
1876     if targetdir is None:
1877         os.system(rndc + " unfreeze " + lp.get("realm"))
1878
1879
1880 def create_dns_update_list(lp, logger, paths, setup_path):
1881     """Write out a dns_update_list file"""
1882     # note that we use no variable substitution on this file
1883     # the substitution is done at runtime by samba_dnsupdate
1884     setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
1885     setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
1886
1887
1888 def create_named_conf(paths, setup_path, realm, dnsdomain,
1889                       private_dir):
1890     """Write out a file containing zone statements suitable for inclusion in a
1891     named.conf file (including GSS-TSIG configuration).
1892
1893     :param paths: all paths
1894     :param setup_path: Setup path function.
1895     :param realm: Realm name
1896     :param dnsdomain: DNS Domain name
1897     :param private_dir: Path to private directory
1898     :param keytab_name: File name of DNS keytab file
1899     """
1900
1901     setup_file(setup_path("named.conf"), paths.namedconf, {
1902             "DNSDOMAIN": dnsdomain,
1903             "REALM": realm,
1904             "ZONE_FILE": paths.dns,
1905             "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
1906             "NAMED_CONF": paths.namedconf,
1907             "NAMED_CONF_UPDATE": paths.namedconf_update
1908             })
1909
1910     setup_file(setup_path("named.conf.update"), paths.namedconf_update)
1911
1912
1913 def create_named_txt(path, setup_path, realm, dnsdomain, private_dir,
1914     keytab_name):
1915     """Write out a file containing zone statements suitable for inclusion in a
1916     named.conf file (including GSS-TSIG configuration).
1917
1918     :param path: Path of the new named.conf file.
1919     :param setup_path: Setup path function.
1920     :param realm: Realm name
1921     :param dnsdomain: DNS Domain name
1922     :param private_dir: Path to private directory
1923     :param keytab_name: File name of DNS keytab file
1924     """
1925     setup_file(setup_path("named.txt"), path, {
1926             "DNSDOMAIN": dnsdomain,
1927             "REALM": realm,
1928             "DNS_KEYTAB": keytab_name,
1929             "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
1930             "PRIVATE_DIR": private_dir
1931         })
1932
1933
1934 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
1935     """Write out a file containing zone statements suitable for inclusion in a
1936     named.conf file (including GSS-TSIG configuration).
1937
1938     :param path: Path of the new named.conf file.
1939     :param setup_path: Setup path function.
1940     :param dnsdomain: DNS Domain name
1941     :param hostname: Local hostname
1942     :param realm: Realm name
1943     """
1944     setup_file(setup_path("krb5.conf"), path, {
1945             "DNSDOMAIN": dnsdomain,
1946             "HOSTNAME": hostname,
1947             "REALM": realm,
1948         })
1949
1950
1951 class ProvisioningError(Exception):
1952     """A generic provision error."""
1953
1954     def __init__(self, value):
1955         self.value = value
1956
1957     def __str__(self):
1958         return "ProvisioningError: " + self.value
1959
1960
1961 class InvalidNetbiosName(Exception):
1962     """A specified name was not a valid NetBIOS name."""
1963     def __init__(self, name):
1964         super(InvalidNetbiosName, self).__init__(
1965             "The name '%r' is not a valid NetBIOS name" % name)