2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
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
9 # Based on the original in EJS:
10 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
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.
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.
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/>.
26 """Functions for setting up a Samba configuration."""
28 __docformat__
= "restructuredText"
30 from base64
import b64encode
45 from samba
.auth
import system_session
, admin_session
47 from samba
.dsdb
import DS_DOMAIN_FUNCTION_2000
50 check_all_substituted
,
56 from samba
.dcerpc
import security
, misc
57 from samba
.dcerpc
.misc
import (
61 from samba
.dsdb
import (
62 DS_DOMAIN_FUNCTION_2003
,
63 DS_DOMAIN_FUNCTION_2008_R2
,
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 (
76 from samba
.provision
.descriptor
import (
77 get_config_descriptor
,
80 from samba
.provision
.common
import (
86 from samba
.provision
.sambadns
import (
88 create_dns_update_list
93 from samba
.schema
import Schema
94 from samba
.samdb
import SamDB
95 from samba
.dbchecker
import dbcheck
98 VALID_NETBIOS_CHARS
= " !#$%&'()-.@^_{}~"
99 DEFAULT_POLICY_GUID
= "31B2F340-016D-11D2-945F-00C04FB984F9"
100 DEFAULT_DC_POLICY_GUID
= "6AC1786C-016F-11D2-945F-00C04fB984F9"
101 DEFAULTSITE
= "Default-First-Site-Name"
102 LAST_PROVISION_USN_ATTRIBUTE
= "lastProvisionUSN"
105 class ProvisionPaths(object):
108 self
.shareconf
= None
119 self
.dns_keytab
= None
122 self
.private_dir
= None
125 class ProvisionNames(object):
132 self
.ldapmanagerdn
= None
133 self
.dnsdomain
= None
135 self
.netbiosname
= None
141 def find_provision_key_parameters(samdb
, secretsdb
, idmapdb
, paths
, smbconf
, lp
):
142 """Get key provision parameters (realm, domain, ...) from a given provision
144 :param samdb: An LDB object connected to the sam.ldb file
145 :param secretsdb: An LDB object connected to the secrets.ldb file
146 :param idmapdb: An LDB object connected to the idmap.ldb file
147 :param paths: A list of path to provision object
148 :param smbconf: Path to the smb.conf file
149 :param lp: A LoadParm object
150 :return: A list of key provision parameters
152 names
= ProvisionNames()
153 names
.adminpass
= None
155 # NT domain, kerberos realm, root dn, domain dn, domain dns name
156 names
.domain
= string
.upper(lp
.get("workgroup"))
157 names
.realm
= lp
.get("realm")
158 names
.dnsdomain
= names
.realm
.lower()
159 basedn
= samba
.dn_from_dns_name(names
.dnsdomain
)
160 names
.realm
= string
.upper(names
.realm
)
162 # Get the netbiosname first (could be obtained from smb.conf in theory)
163 res
= secretsdb
.search(expression
="(flatname=%s)" %
164 names
.domain
,base
="CN=Primary Domains",
165 scope
=ldb
.SCOPE_SUBTREE
, attrs
=["sAMAccountName"])
166 names
.netbiosname
= str(res
[0]["sAMAccountName"]).replace("$","")
168 names
.smbconf
= smbconf
170 # That's a bit simplistic but it's ok as long as we have only 3
172 current
= samdb
.search(expression
="(objectClass=*)",
173 base
="", scope
=ldb
.SCOPE_BASE
,
174 attrs
=["defaultNamingContext", "schemaNamingContext",
175 "configurationNamingContext","rootDomainNamingContext"])
177 names
.configdn
= current
[0]["configurationNamingContext"]
178 configdn
= str(names
.configdn
)
179 names
.schemadn
= current
[0]["schemaNamingContext"]
180 if not (ldb
.Dn(samdb
, basedn
) == (ldb
.Dn(samdb
,
181 current
[0]["defaultNamingContext"][0]))):
182 raise ProvisioningError(("basedn in %s (%s) and from %s (%s)"
183 "is not the same ..." % (paths
.samdb
,
184 str(current
[0]["defaultNamingContext"][0]),
185 paths
.smbconf
, basedn
)))
187 names
.domaindn
=current
[0]["defaultNamingContext"]
188 names
.rootdn
=current
[0]["rootDomainNamingContext"]
190 res3
= samdb
.search(expression
="(objectClass=site)",
191 base
="CN=Sites," + configdn
, scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn"])
192 names
.sitename
= str(res3
[0]["cn"])
194 # dns hostname and server dn
195 res4
= samdb
.search(expression
="(CN=%s)" % names
.netbiosname
,
196 base
="OU=Domain Controllers,%s" % basedn
,
197 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["dNSHostName"])
198 names
.hostname
= str(res4
[0]["dNSHostName"]).replace("." + names
.dnsdomain
,"")
200 server_res
= samdb
.search(expression
="serverReference=%s" % res4
[0].dn
,
201 attrs
=[], base
=configdn
)
202 names
.serverdn
= server_res
[0].dn
204 # invocation id/objectguid
205 res5
= samdb
.search(expression
="(objectClass=*)",
206 base
="CN=NTDS Settings,%s" % str(names
.serverdn
), scope
=ldb
.SCOPE_BASE
,
207 attrs
=["invocationID", "objectGUID"])
208 names
.invocation
= str(ndr_unpack(misc
.GUID
, res5
[0]["invocationId"][0]))
209 names
.ntdsguid
= str(ndr_unpack(misc
.GUID
, res5
[0]["objectGUID"][0]))
212 res6
= samdb
.search(expression
="(objectClass=*)", base
=basedn
,
213 scope
=ldb
.SCOPE_BASE
, attrs
=["objectGUID",
214 "objectSid","msDS-Behavior-Version" ])
215 names
.domainguid
= str(ndr_unpack(misc
.GUID
, res6
[0]["objectGUID"][0]))
216 names
.domainsid
= ndr_unpack( security
.dom_sid
, res6
[0]["objectSid"][0])
217 if res6
[0].get("msDS-Behavior-Version") is None or \
218 int(res6
[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000
:
219 names
.domainlevel
= DS_DOMAIN_FUNCTION_2000
221 names
.domainlevel
= int(res6
[0]["msDS-Behavior-Version"][0])
224 res7
= samdb
.search(expression
="(displayName=Default Domain Policy)",
225 base
="CN=Policies,CN=System," + basedn
,
226 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn","displayName"])
227 names
.policyid
= str(res7
[0]["cn"]).replace("{","").replace("}","")
229 res8
= samdb
.search(expression
="(displayName=Default Domain Controllers"
231 base
="CN=Policies,CN=System," + basedn
,
232 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn","displayName"])
234 names
.policyid_dc
= str(res8
[0]["cn"]).replace("{","").replace("}","")
236 names
.policyid_dc
= None
237 res9
= idmapdb
.search(expression
="(cn=%s)" %
238 (security
.SID_BUILTIN_ADMINISTRATORS
),
241 names
.wheel_gid
= res9
[0]["xidNumber"]
243 raise ProvisioningError("Unable to find uid/gid for Domain Admins rid")
246 def update_provision_usn(samdb
, low
, high
, id, replace
=False):
247 """Update the field provisionUSN in sam.ldb
249 This field is used to track range of USN modified by provision and
251 This value is used afterward by next provision to figure out if
252 the field have been modified since last provision.
254 :param samdb: An LDB object connect to sam.ldb
255 :param low: The lowest USN modified by this upgrade
256 :param high: The highest USN modified by this upgrade
257 :param id: The invocation id of the samba's dc
258 :param replace: A boolean indicating if the range should replace any
259 existing one or appended (default)
264 entry
= samdb
.search(base
="@PROVISION",
265 scope
=ldb
.SCOPE_BASE
,
266 attrs
=[LAST_PROVISION_USN_ATTRIBUTE
, "dn"])
267 for e
in entry
[0][LAST_PROVISION_USN_ATTRIBUTE
]:
268 if not re
.search(';', e
):
269 e
= "%s;%s" % (e
, id)
272 tab
.append("%s-%s;%s" % (low
, high
, id))
273 delta
= ldb
.Message()
274 delta
.dn
= ldb
.Dn(samdb
, "@PROVISION")
275 delta
[LAST_PROVISION_USN_ATTRIBUTE
] = ldb
.MessageElement(tab
,
276 ldb
.FLAG_MOD_REPLACE
, LAST_PROVISION_USN_ATTRIBUTE
)
277 entry
= samdb
.search(expression
='provisionnerID=*',
278 base
="@PROVISION", scope
=ldb
.SCOPE_BASE
,
279 attrs
=["provisionnerID"])
280 if len(entry
) == 0 or len(entry
[0]) == 0:
281 delta
["provisionnerID"] = ldb
.MessageElement(id, ldb
.FLAG_MOD_ADD
, "provisionnerID")
285 def set_provision_usn(samdb
, low
, high
, id):
286 """Set the field provisionUSN in sam.ldb
287 This field is used to track range of USN modified by provision and
289 This value is used afterward by next provision to figure out if
290 the field have been modified since last provision.
292 :param samdb: An LDB object connect to sam.ldb
293 :param low: The lowest USN modified by this upgrade
294 :param high: The highest USN modified by this upgrade
295 :param id: The invocationId of the provision"""
298 tab
.append("%s-%s;%s" % (low
, high
, id))
300 delta
= ldb
.Message()
301 delta
.dn
= ldb
.Dn(samdb
, "@PROVISION")
302 delta
[LAST_PROVISION_USN_ATTRIBUTE
] = ldb
.MessageElement(tab
,
303 ldb
.FLAG_MOD_ADD
, LAST_PROVISION_USN_ATTRIBUTE
)
307 def get_max_usn(samdb
,basedn
):
308 """ This function return the biggest USN present in the provision
310 :param samdb: A LDB object pointing to the sam.ldb
311 :param basedn: A string containing the base DN of the provision
313 :return: The biggest USN in the provision"""
315 res
= samdb
.search(expression
="objectClass=*",base
=basedn
,
316 scope
=ldb
.SCOPE_SUBTREE
,attrs
=["uSNChanged"],
317 controls
=["search_options:1:2",
318 "server_sort:1:1:uSNChanged",
319 "paged_results:1:1"])
320 return res
[0]["uSNChanged"]
323 def get_last_provision_usn(sam
):
324 """Get USNs ranges modified by a provision or an upgradeprovision
326 :param sam: An LDB object pointing to the sam.ldb
327 :return: a dictionnary which keys are invocation id and values are an array
328 of integer representing the different ranges
331 entry
= sam
.search(expression
="%s=*" % LAST_PROVISION_USN_ATTRIBUTE
,
332 base
="@PROVISION", scope
=ldb
.SCOPE_BASE
,
333 attrs
=[LAST_PROVISION_USN_ATTRIBUTE
, "provisionnerID"])
334 except ldb
.LdbError
, (ecode
, emsg
):
335 if ecode
== ldb
.ERR_NO_SUCH_OBJECT
:
342 if entry
[0].get("provisionnerID"):
343 for e
in entry
[0]["provisionnerID"]:
345 for r
in entry
[0][LAST_PROVISION_USN_ATTRIBUTE
]:
346 tab1
= str(r
).split(';')
351 if (len(myids
) > 0 and id not in myids
):
353 tab2
= p
.split(tab1
[0])
354 if range.get(id) == None:
356 range[id].append(tab2
[0])
357 range[id].append(tab2
[1])
363 class ProvisionResult(object):
374 def check_install(lp
, session_info
, credentials
):
375 """Check whether the current install seems ok.
377 :param lp: Loadparm context
378 :param session_info: Session information
379 :param credentials: Credentials
381 if lp
.get("realm") == "":
382 raise Exception("Realm empty")
383 samdb
= Ldb(lp
.samdb_url(), session_info
=session_info
,
384 credentials
=credentials
, lp
=lp
)
385 if len(samdb
.search("(cn=Administrator)")) != 1:
386 raise ProvisioningError("No administrator account found")
389 def findnss(nssfn
, names
):
390 """Find a user or group from a list of possibilities.
392 :param nssfn: NSS Function to try (should raise KeyError if not found)
393 :param names: Names to check.
394 :return: Value return by first names list.
401 raise KeyError("Unable to find user/group in %r" % names
)
404 findnss_uid
= lambda names
: findnss(pwd
.getpwnam
, names
)[2]
405 findnss_gid
= lambda names
: findnss(grp
.getgrnam
, names
)[2]
408 def provision_paths_from_lp(lp
, dnsdomain
):
409 """Set the default paths for provisioning.
411 :param lp: Loadparm context.
412 :param dnsdomain: DNS Domain name
414 paths
= ProvisionPaths()
415 paths
.private_dir
= lp
.get("private dir")
417 # This is stored without path prefix for the "privateKeytab" attribute in
418 # "secrets_dns.ldif".
419 paths
.dns_keytab
= "dns.keytab"
420 paths
.keytab
= "secrets.keytab"
422 paths
.shareconf
= os
.path
.join(paths
.private_dir
, "share.ldb")
423 paths
.samdb
= os
.path
.join(paths
.private_dir
, "sam.ldb")
424 paths
.idmapdb
= os
.path
.join(paths
.private_dir
, "idmap.ldb")
425 paths
.secrets
= os
.path
.join(paths
.private_dir
, "secrets.ldb")
426 paths
.privilege
= os
.path
.join(paths
.private_dir
, "privilege.ldb")
427 paths
.dns
= os
.path
.join(paths
.private_dir
, "dns", dnsdomain
+ ".zone")
428 paths
.dns_update_list
= os
.path
.join(paths
.private_dir
, "dns_update_list")
429 paths
.spn_update_list
= os
.path
.join(paths
.private_dir
, "spn_update_list")
430 paths
.namedconf
= os
.path
.join(paths
.private_dir
, "named.conf")
431 paths
.namedconf_update
= os
.path
.join(paths
.private_dir
, "named.conf.update")
432 paths
.namedtxt
= os
.path
.join(paths
.private_dir
, "named.txt")
433 paths
.krb5conf
= os
.path
.join(paths
.private_dir
, "krb5.conf")
434 paths
.winsdb
= os
.path
.join(paths
.private_dir
, "wins.ldb")
435 paths
.s4_ldapi_path
= os
.path
.join(paths
.private_dir
, "ldapi")
436 paths
.phpldapadminconfig
= os
.path
.join(paths
.private_dir
,
437 "phpldapadmin-config.php")
438 paths
.hklm
= "hklm.ldb"
439 paths
.hkcr
= "hkcr.ldb"
440 paths
.hkcu
= "hkcu.ldb"
441 paths
.hku
= "hku.ldb"
442 paths
.hkpd
= "hkpd.ldb"
443 paths
.hkpt
= "hkpt.ldb"
444 paths
.sysvol
= lp
.get("path", "sysvol")
445 paths
.netlogon
= lp
.get("path", "netlogon")
446 paths
.smbconf
= lp
.configfile
450 def guess_names(lp
=None, hostname
=None, domain
=None, dnsdomain
=None,
451 serverrole
=None, rootdn
=None, domaindn
=None, configdn
=None,
452 schemadn
=None, serverdn
=None, sitename
=None):
453 """Guess configuration settings to use."""
456 hostname
= socket
.gethostname().split(".")[0]
458 netbiosname
= lp
.get("netbios name")
459 if netbiosname
is None:
460 netbiosname
= hostname
461 # remove forbidden chars
463 for x
in netbiosname
:
464 if x
.isalnum() or x
in VALID_NETBIOS_CHARS
:
465 newnbname
= "%s%c" % (newnbname
, x
)
466 # force the length to be <16
467 netbiosname
= newnbname
[0:15]
468 assert netbiosname
is not None
469 netbiosname
= netbiosname
.upper()
470 if not valid_netbios_name(netbiosname
):
471 raise InvalidNetbiosName(netbiosname
)
473 if dnsdomain
is None:
474 dnsdomain
= lp
.get("realm")
475 if dnsdomain
is None or dnsdomain
== "":
476 raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp
.configfile
)
478 dnsdomain
= dnsdomain
.lower()
480 if serverrole
is None:
481 serverrole
= lp
.get("server role")
482 if serverrole
is None:
483 raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp
.configfile
)
485 serverrole
= serverrole
.lower()
487 realm
= dnsdomain
.upper()
489 if lp
.get("realm") == "":
490 raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s. Please remove the smb.conf file and let provision generate it" % lp
.configfile
)
492 if lp
.get("realm").upper() != realm
:
493 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
))
495 if lp
.get("server role").lower() != serverrole
:
496 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"), serverrole
, lp
.configfile
))
498 if serverrole
== "domain controller":
500 # This will, for better or worse, default to 'WORKGROUP'
501 domain
= lp
.get("workgroup")
502 domain
= domain
.upper()
504 if lp
.get("workgroup").upper() != domain
:
505 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
))
508 domaindn
= samba
.dn_from_dns_name(dnsdomain
)
510 if domain
== netbiosname
:
511 raise ProvisioningError("guess_names: Domain '%s' must not be equal to short host name '%s'!" % (domain
, netbiosname
))
515 domaindn
= "DC=" + netbiosname
517 if not valid_netbios_name(domain
):
518 raise InvalidNetbiosName(domain
)
520 if hostname
.upper() == realm
:
521 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm
, hostname
))
522 if netbiosname
.upper() == realm
:
523 raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!" % (realm
, netbiosname
))
525 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm
, domain
))
531 configdn
= "CN=Configuration," + rootdn
533 schemadn
= "CN=Schema," + configdn
538 names
= ProvisionNames()
539 names
.rootdn
= rootdn
540 names
.domaindn
= domaindn
541 names
.configdn
= configdn
542 names
.schemadn
= schemadn
543 names
.ldapmanagerdn
= "CN=Manager," + rootdn
544 names
.dnsdomain
= dnsdomain
545 names
.domain
= domain
547 names
.netbiosname
= netbiosname
548 names
.hostname
= hostname
549 names
.sitename
= sitename
550 names
.serverdn
= "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (
551 netbiosname
, sitename
, configdn
)
556 def make_smbconf(smbconf
, hostname
, domain
, realm
, serverrole
,
557 targetdir
, sid_generator
="internal", eadb
=False, lp
=None):
558 """Create a new smb.conf file based on a couple of basic settings.
560 assert smbconf
is not None
562 hostname
= socket
.gethostname().split(".")[0]
563 netbiosname
= hostname
.upper()
564 # remove forbidden chars
566 for x
in netbiosname
:
567 if x
.isalnum() or x
in VALID_NETBIOS_CHARS
:
568 newnbname
= "%s%c" % (newnbname
, x
)
569 #force the length to be <16
570 netbiosname
= newnbname
[0:15]
572 netbiosname
= hostname
.upper()
574 if serverrole
is None:
575 serverrole
= "standalone"
577 assert serverrole
in ("domain controller", "member server", "standalone")
578 if serverrole
== "domain controller":
580 elif serverrole
== "member server":
581 smbconfsuffix
= "member"
582 elif serverrole
== "standalone":
583 smbconfsuffix
= "standalone"
585 if sid_generator
is None:
586 sid_generator
= "internal"
588 assert domain
is not None
589 domain
= domain
.upper()
591 assert realm
is not None
592 realm
= realm
.upper()
595 lp
= samba
.param
.LoadParm()
596 #Load non-existant file
597 if os
.path
.exists(smbconf
):
599 if eadb
and not lp
.get("posix:eadb"):
600 if targetdir
is not None:
601 privdir
= os
.path
.join(targetdir
, "private")
603 privdir
= lp
.get("private dir")
604 lp
.set("posix:eadb", os
.path
.abspath(os
.path
.join(privdir
, "eadb.tdb")))
606 if targetdir
is not None:
607 privatedir_line
= "private dir = " + os
.path
.abspath(os
.path
.join(targetdir
, "private"))
608 lockdir_line
= "lock dir = " + os
.path
.abspath(targetdir
)
609 statedir_line
= "state directory = " + os
.path
.abspath(targetdir
)
610 cachedir_line
= "cache directory = " + os
.path
.abspath(targetdir
)
612 lp
.set("lock dir", os
.path
.abspath(targetdir
))
613 lp
.set("state directory", os
.path
.abspath(targetdir
))
614 lp
.set("cache directory", os
.path
.abspath(targetdir
))
621 sysvol
= os
.path
.join(lp
.get("state directory"), "sysvol")
622 netlogon
= os
.path
.join(sysvol
, realm
.lower(), "scripts")
624 setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix
),
626 "NETBIOS_NAME": netbiosname
,
629 "SERVERROLE": serverrole
,
630 "NETLOGONPATH": netlogon
,
631 "SYSVOLPATH": sysvol
,
632 "PRIVATEDIR_LINE": privatedir_line
,
633 "LOCKDIR_LINE": lockdir_line
,
634 "STATEDIR_LINE": statedir_line
,
635 "CACHEDIR_LINE": cachedir_line
638 # reload the smb.conf
641 # and dump it without any values that are the default
642 # this ensures that any smb.conf parameters that were set
643 # on the provision/join command line are set in the resulting smb.conf
644 f
= open(smbconf
, mode
='w')
650 def setup_name_mappings(idmap
, sid
, root_uid
, nobody_uid
,
651 users_gid
, wheel_gid
):
652 """setup reasonable name mappings for sam names to unix names.
654 :param samdb: SamDB object.
655 :param idmap: IDmap db object.
656 :param sid: The domain sid.
657 :param domaindn: The domain DN.
658 :param root_uid: uid of the UNIX root user.
659 :param nobody_uid: uid of the UNIX nobody user.
660 :param users_gid: gid of the UNIX users group.
661 :param wheel_gid: gid of the UNIX wheel group.
663 idmap
.setup_name_mapping("S-1-5-7", idmap
.TYPE_UID
, nobody_uid
)
664 idmap
.setup_name_mapping("S-1-5-32-544", idmap
.TYPE_GID
, wheel_gid
)
666 idmap
.setup_name_mapping(sid
+ "-500", idmap
.TYPE_UID
, root_uid
)
667 idmap
.setup_name_mapping(sid
+ "-513", idmap
.TYPE_GID
, users_gid
)
670 def setup_samdb_partitions(samdb_path
, logger
, lp
, session_info
,
671 provision_backend
, names
, schema
, serverrole
,
673 """Setup the partitions for the SAM database.
675 Alternatively, provision() may call this, and then populate the database.
677 :note: This will wipe the Sam Database!
679 :note: This function always removes the local SAM LDB file. The erase
680 parameter controls whether to erase the existing data, which
681 may not be stored locally but in LDAP.
684 assert session_info
is not None
686 # We use options=["modules:"] to stop the modules loading - we
687 # just want to wipe and re-initialise the database, not start it up
690 os
.unlink(samdb_path
)
694 samdb
= Ldb(url
=samdb_path
, session_info
=session_info
,
695 lp
=lp
, options
=["modules:"])
697 ldap_backend_line
= "# No LDAP backend"
698 if provision_backend
.type is not "ldb":
699 ldap_backend_line
= "ldapBackend: %s" % provision_backend
.ldap_uri
701 samdb
.transaction_start()
703 logger
.info("Setting up sam.ldb partitions and settings")
704 setup_add_ldif(samdb
, setup_path("provision_partitions.ldif"), {
705 "LDAP_BACKEND_LINE": ldap_backend_line
709 setup_add_ldif(samdb
, setup_path("provision_init.ldif"), {
710 "BACKEND_TYPE": provision_backend
.type,
711 "SERVER_ROLE": serverrole
714 logger
.info("Setting up sam.ldb rootDSE")
715 setup_samdb_rootdse(samdb
, names
)
717 samdb
.transaction_cancel()
720 samdb
.transaction_commit()
723 def secretsdb_self_join(secretsdb
, domain
,
724 netbiosname
, machinepass
, domainsid
=None,
725 realm
=None, dnsdomain
=None,
727 key_version_number
=1,
728 secure_channel_type
=SEC_CHAN_WKSTA
):
729 """Add domain join-specific bits to a secrets database.
731 :param secretsdb: Ldb Handle to the secrets database
732 :param machinepass: Machine password
734 attrs
= ["whenChanged",
741 if realm
is not None:
742 if dnsdomain
is None:
743 dnsdomain
= realm
.lower()
744 dnsname
= '%s.%s' % (netbiosname
.lower(), dnsdomain
.lower())
747 shortname
= netbiosname
.lower()
749 # We don't need to set msg["flatname"] here, because rdn_name will handle
750 # it, and it causes problems for modifies anyway
751 msg
= ldb
.Message(ldb
.Dn(secretsdb
, "flatname=%s,cn=Primary Domains" % domain
))
752 msg
["secureChannelType"] = [str(secure_channel_type
)]
753 msg
["objectClass"] = ["top", "primaryDomain"]
754 if dnsname
is not None:
755 msg
["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
756 msg
["realm"] = [realm
]
757 msg
["saltPrincipal"] = ["host/%s@%s" % (dnsname
, realm
.upper())]
758 msg
["msDS-KeyVersionNumber"] = [str(key_version_number
)]
759 msg
["privateKeytab"] = ["secrets.keytab"]
761 msg
["secret"] = [machinepass
]
762 msg
["samAccountName"] = ["%s$" % netbiosname
]
763 msg
["secureChannelType"] = [str(secure_channel_type
)]
764 if domainsid
is not None:
765 msg
["objectSid"] = [ndr_pack(domainsid
)]
767 # This complex expression tries to ensure that we don't have more
768 # than one record for this SID, realm or netbios domain at a time,
769 # but we don't delete the old record that we are about to modify,
770 # because that would delete the keytab and previous password.
771 res
= secretsdb
.search(base
="cn=Primary Domains", attrs
=attrs
,
772 expression
=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(dn=%s)))" % (domain
, realm
, str(domainsid
), str(msg
.dn
))),
773 scope
=ldb
.SCOPE_ONELEVEL
)
776 secretsdb
.delete(del_msg
.dn
)
778 res
= secretsdb
.search(base
=msg
.dn
, attrs
=attrs
, scope
=ldb
.SCOPE_BASE
)
781 msg
["priorSecret"] = [res
[0]["secret"][0]]
782 msg
["priorWhenChanged"] = [res
[0]["whenChanged"][0]]
785 msg
["privateKeytab"] = [res
[0]["privateKeytab"][0]]
790 msg
["krb5Keytab"] = [res
[0]["krb5Keytab"][0]]
796 msg
[el
].set_flags(ldb
.FLAG_MOD_REPLACE
)
797 secretsdb
.modify(msg
)
798 secretsdb
.rename(res
[0].dn
, msg
.dn
)
800 spn
= [ 'HOST/%s' % shortname
]
801 if secure_channel_type
== SEC_CHAN_BDC
and dnsname
is not None:
802 # we are a domain controller then we add servicePrincipalName
803 # entries for the keytab code to update.
804 spn
.extend([ 'HOST/%s' % dnsname
])
805 msg
["servicePrincipalName"] = spn
810 def setup_secretsdb(paths
, session_info
, backend_credentials
, lp
):
811 """Setup the secrets database.
813 :note: This function does not handle exceptions and transaction on purpose,
814 it's up to the caller to do this job.
816 :param path: Path to the secrets database.
817 :param session_info: Session info.
818 :param credentials: Credentials
819 :param lp: Loadparm context
820 :return: LDB handle for the created secrets database
822 if os
.path
.exists(paths
.secrets
):
823 os
.unlink(paths
.secrets
)
825 keytab_path
= os
.path
.join(paths
.private_dir
, paths
.keytab
)
826 if os
.path
.exists(keytab_path
):
827 os
.unlink(keytab_path
)
829 dns_keytab_path
= os
.path
.join(paths
.private_dir
, paths
.dns_keytab
)
830 if os
.path
.exists(dns_keytab_path
):
831 os
.unlink(dns_keytab_path
)
835 secrets_ldb
= Ldb(path
, session_info
=session_info
,
838 secrets_ldb
.load_ldif_file_add(setup_path("secrets_init.ldif"))
839 secrets_ldb
= Ldb(path
, session_info
=session_info
,
841 secrets_ldb
.transaction_start()
843 secrets_ldb
.load_ldif_file_add(setup_path("secrets.ldif"))
845 if (backend_credentials
is not None and
846 backend_credentials
.authentication_requested()):
847 if backend_credentials
.get_bind_dn() is not None:
848 setup_add_ldif(secrets_ldb
,
849 setup_path("secrets_simple_ldap.ldif"), {
850 "LDAPMANAGERDN": backend_credentials
.get_bind_dn(),
851 "LDAPMANAGERPASS_B64": b64encode(backend_credentials
.get_password())
854 setup_add_ldif(secrets_ldb
,
855 setup_path("secrets_sasl_ldap.ldif"), {
856 "LDAPADMINUSER": backend_credentials
.get_username(),
857 "LDAPADMINREALM": backend_credentials
.get_realm(),
858 "LDAPADMINPASS_B64": b64encode(backend_credentials
.get_password())
861 secrets_ldb
.transaction_cancel()
867 def setup_privileges(path
, session_info
, lp
):
868 """Setup the privileges database.
870 :param path: Path to the privileges database.
871 :param session_info: Session info.
872 :param credentials: Credentials
873 :param lp: Loadparm context
874 :return: LDB handle for the created secrets database
876 if os
.path
.exists(path
):
878 privilege_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
879 privilege_ldb
.erase()
880 privilege_ldb
.load_ldif_file_add(setup_path("provision_privilege.ldif"))
883 def setup_registry(path
, session_info
, lp
):
884 """Setup the registry.
886 :param path: Path to the registry database
887 :param session_info: Session information
888 :param credentials: Credentials
889 :param lp: Loadparm context
891 reg
= samba
.registry
.Registry()
892 hive
= samba
.registry
.open_ldb(path
, session_info
=session_info
, lp_ctx
=lp
)
893 reg
.mount_hive(hive
, samba
.registry
.HKEY_LOCAL_MACHINE
)
894 provision_reg
= setup_path("provision.reg")
895 assert os
.path
.exists(provision_reg
)
896 reg
.diff_apply(provision_reg
)
899 def setup_idmapdb(path
, session_info
, lp
):
900 """Setup the idmap database.
902 :param path: path to the idmap database
903 :param session_info: Session information
904 :param credentials: Credentials
905 :param lp: Loadparm context
907 if os
.path
.exists(path
):
910 idmap_ldb
= IDmapDB(path
, session_info
=session_info
, lp
=lp
)
912 idmap_ldb
.load_ldif_file_add(setup_path("idmap_init.ldif"))
916 def setup_samdb_rootdse(samdb
, names
):
917 """Setup the SamDB rootdse.
919 :param samdb: Sam Database handle
921 setup_add_ldif(samdb
, setup_path("provision_rootdse_add.ldif"), {
922 "SCHEMADN": names
.schemadn
,
923 "DOMAINDN": names
.domaindn
,
924 "ROOTDN" : names
.rootdn
,
925 "CONFIGDN": names
.configdn
,
926 "SERVERDN": names
.serverdn
,
930 def setup_self_join(samdb
, admin_session_info
, names
, fill
, machinepass
, dnspass
,
931 domainsid
, next_rid
, invocationid
,
932 policyguid
, policyguid_dc
, domainControllerFunctionality
,
933 ntdsguid
, dc_rid
=None):
934 """Join a host to its own domain."""
935 assert isinstance(invocationid
, str)
936 if ntdsguid
is not None:
937 ntdsguid_line
= "objectGUID: %s\n"%ntdsguid
944 setup_add_ldif(samdb
, setup_path("provision_self_join.ldif"), {
945 "CONFIGDN": names
.configdn
,
946 "SCHEMADN": names
.schemadn
,
947 "DOMAINDN": names
.domaindn
,
948 "SERVERDN": names
.serverdn
,
949 "INVOCATIONID": invocationid
,
950 "NETBIOSNAME": names
.netbiosname
,
951 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
952 "MACHINEPASS_B64": b64encode(machinepass
.encode('utf-16-le')),
953 "DOMAINSID": str(domainsid
),
954 "DCRID": str(dc_rid
),
955 "SAMBA_VERSION_STRING": version
,
956 "NTDSGUID": ntdsguid_line
,
957 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
958 domainControllerFunctionality
),
959 "RIDALLOCATIONSTART": str(next_rid
+ 100),
960 "RIDALLOCATIONEND": str(next_rid
+ 100 + 499)})
962 setup_add_ldif(samdb
, setup_path("provision_group_policy.ldif"), {
963 "POLICYGUID": policyguid
,
964 "POLICYGUID_DC": policyguid_dc
,
965 "DNSDOMAIN": names
.dnsdomain
,
966 "DOMAINDN": names
.domaindn
})
968 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
969 if fill
== FILL_FULL
:
970 setup_add_ldif(samdb
, setup_path("provision_self_join_config.ldif"), {
971 "CONFIGDN": names
.configdn
,
972 "SCHEMADN": names
.schemadn
,
973 "DOMAINDN": names
.domaindn
,
974 "SERVERDN": names
.serverdn
,
975 "INVOCATIONID": invocationid
,
976 "NETBIOSNAME": names
.netbiosname
,
977 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
978 "MACHINEPASS_B64": b64encode(machinepass
.encode('utf-16-le')),
979 "DOMAINSID": str(domainsid
),
980 "DCRID": str(dc_rid
),
981 "SAMBA_VERSION_STRING": version
,
982 "NTDSGUID": ntdsguid_line
,
983 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
984 domainControllerFunctionality
)})
986 # Setup fSMORoleOwner entries to point at the newly created DC entry
987 setup_modify_ldif(samdb
, setup_path("provision_self_join_modify_config.ldif"), {
988 "CONFIGDN": names
.configdn
,
989 "SCHEMADN": names
.schemadn
,
990 "DEFAULTSITE": names
.sitename
,
991 "NETBIOSNAME": names
.netbiosname
,
992 "SERVERDN": names
.serverdn
,
995 system_session_info
= system_session()
996 samdb
.set_session_info(system_session_info
)
997 # Setup fSMORoleOwner entries to point at the newly created DC entry
999 # to modify a serverReference under cn=config when we are a subdomain, we must
1000 # be system due to ACLs
1001 setup_modify_ldif(samdb
, setup_path("provision_self_join_modify.ldif"), {
1002 "DOMAINDN": names
.domaindn
,
1003 "SERVERDN": names
.serverdn
,
1004 "NETBIOSNAME": names
.netbiosname
,
1007 samdb
.set_session_info(admin_session_info
)
1009 # This is Samba4 specific and should be replaced by the correct
1010 # DNS AD-style setup
1011 setup_add_ldif(samdb
, setup_path("provision_dns_add_samba.ldif"), {
1012 "DNSDOMAIN": names
.dnsdomain
,
1013 "DOMAINDN": names
.domaindn
,
1014 "DNSPASS_B64": b64encode(dnspass
.encode('utf-16-le')),
1015 "HOSTNAME" : names
.hostname
,
1016 "DNSNAME" : '%s.%s' % (
1017 names
.netbiosname
.lower(), names
.dnsdomain
.lower())
1021 def getpolicypath(sysvolpath
, dnsdomain
, guid
):
1022 """Return the physical path of policy given its guid.
1024 :param sysvolpath: Path to the sysvol folder
1025 :param dnsdomain: DNS name of the AD domain
1026 :param guid: The GUID of the policy
1027 :return: A string with the complete path to the policy folder
1031 guid
= "{%s}" % guid
1032 policy_path
= os
.path
.join(sysvolpath
, dnsdomain
, "Policies", guid
)
1036 def create_gpo_struct(policy_path
):
1037 if not os
.path
.exists(policy_path
):
1038 os
.makedirs(policy_path
, 0775)
1039 open(os
.path
.join(policy_path
, "GPT.INI"), 'w').write(
1040 "[General]\r\nVersion=0")
1041 p
= os
.path
.join(policy_path
, "MACHINE")
1042 if not os
.path
.exists(p
):
1043 os
.makedirs(p
, 0775)
1044 p
= os
.path
.join(policy_path
, "USER")
1045 if not os
.path
.exists(p
):
1046 os
.makedirs(p
, 0775)
1049 def create_default_gpo(sysvolpath
, dnsdomain
, policyguid
, policyguid_dc
):
1050 """Create the default GPO for a domain
1052 :param sysvolpath: Physical path for the sysvol folder
1053 :param dnsdomain: DNS domain name of the AD domain
1054 :param policyguid: GUID of the default domain policy
1055 :param policyguid_dc: GUID of the default domain controler policy
1057 policy_path
= getpolicypath(sysvolpath
,dnsdomain
,policyguid
)
1058 create_gpo_struct(policy_path
)
1060 policy_path
= getpolicypath(sysvolpath
,dnsdomain
,policyguid_dc
)
1061 create_gpo_struct(policy_path
)
1064 def setup_samdb(path
, session_info
, provision_backend
, lp
, names
,
1065 logger
, fill
, serverrole
, schema
, am_rodc
=False):
1066 """Setup a complete SAM Database.
1068 :note: This will wipe the main SAM database file!
1071 # Also wipes the database
1072 setup_samdb_partitions(path
, logger
=logger
, lp
=lp
,
1073 provision_backend
=provision_backend
, session_info
=session_info
,
1074 names
=names
, serverrole
=serverrole
, schema
=schema
)
1076 # Load the database, but don's load the global schema and don't connect
1078 samdb
= SamDB(session_info
=session_info
, url
=None, auto_connect
=False,
1079 credentials
=provision_backend
.credentials
, lp
=lp
,
1080 global_schema
=False, am_rodc
=am_rodc
)
1082 logger
.info("Pre-loading the Samba 4 and AD schema")
1084 # Load the schema from the one we computed earlier
1085 samdb
.set_schema(schema
)
1087 # Set the NTDS settings DN manually - in order to have it already around
1088 # before the provisioned tree exists and we connect
1089 samdb
.set_ntds_settings_dn("CN=NTDS Settings,%s" % names
.serverdn
)
1091 # And now we can connect to the DB - the schema won't be loaded from the
1097 def fill_samdb(samdb
, lp
, names
,
1098 logger
, domainsid
, domainguid
, policyguid
, policyguid_dc
, fill
,
1099 adminpass
, krbtgtpass
, machinepass
, invocationid
, dnspass
, ntdsguid
,
1100 serverrole
, am_rodc
=False, dom_for_fun_level
=None, schema
=None,
1101 next_rid
=None, dc_rid
=None):
1103 if next_rid
is None:
1106 # Provision does not make much sense values larger than 1000000000
1107 # as the upper range of the rIDAvailablePool is 1073741823 and
1108 # we don't want to create a domain that cannot allocate rids.
1109 if next_rid
< 1000 or next_rid
> 1000000000:
1110 error
= "You want to run SAMBA 4 with a next_rid of %u, " % (next_rid
)
1111 error
+= "the valid range is %u-%u. The default is %u." % (
1112 1000, 1000000000, 1000)
1113 raise ProvisioningError(error
)
1115 # ATTENTION: Do NOT change these default values without discussion with the
1116 # team and/or release manager. They have a big impact on the whole program!
1117 domainControllerFunctionality
= DS_DOMAIN_FUNCTION_2008_R2
1119 if dom_for_fun_level
is None:
1120 dom_for_fun_level
= DS_DOMAIN_FUNCTION_2003
1122 if dom_for_fun_level
> domainControllerFunctionality
:
1123 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!")
1125 domainFunctionality
= dom_for_fun_level
1126 forestFunctionality
= dom_for_fun_level
1128 # Set the NTDS settings DN manually - in order to have it already around
1129 # before the provisioned tree exists and we connect
1130 samdb
.set_ntds_settings_dn("CN=NTDS Settings,%s" % names
.serverdn
)
1132 samdb
.transaction_start()
1134 # Set the domain functionality levels onto the database.
1135 # Various module (the password_hash module in particular) need
1136 # to know what level of AD we are emulating.
1138 # These will be fixed into the database via the database
1139 # modifictions below, but we need them set from the start.
1140 samdb
.set_opaque_integer("domainFunctionality", domainFunctionality
)
1141 samdb
.set_opaque_integer("forestFunctionality", forestFunctionality
)
1142 samdb
.set_opaque_integer("domainControllerFunctionality",
1143 domainControllerFunctionality
)
1145 samdb
.set_domain_sid(str(domainsid
))
1146 samdb
.set_invocation_id(invocationid
)
1148 logger
.info("Adding DomainDN: %s" % names
.domaindn
)
1150 # impersonate domain admin
1151 admin_session_info
= admin_session(lp
, str(domainsid
))
1152 samdb
.set_session_info(admin_session_info
)
1153 if domainguid
is not None:
1154 domainguid_line
= "objectGUID: %s\n-" % domainguid
1156 domainguid_line
= ""
1158 descr
= b64encode(get_domain_descriptor(domainsid
))
1159 setup_add_ldif(samdb
, setup_path("provision_basedn.ldif"), {
1160 "DOMAINDN": names
.domaindn
,
1161 "DOMAINSID": str(domainsid
),
1162 "DESCRIPTOR": descr
,
1163 "DOMAINGUID": domainguid_line
1166 setup_modify_ldif(samdb
, setup_path("provision_basedn_modify.ldif"), {
1167 "DOMAINDN": names
.domaindn
,
1168 "CREATTIME": str(samba
.unix2nttime(int(time
.time()))),
1169 "NEXTRID": str(next_rid
),
1170 "DEFAULTSITE": names
.sitename
,
1171 "CONFIGDN": names
.configdn
,
1172 "POLICYGUID": policyguid
,
1173 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
),
1174 "SAMBA_VERSION_STRING": version
1177 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1178 if fill
== FILL_FULL
:
1179 logger
.info("Adding configuration container")
1180 descr
= b64encode(get_config_descriptor(domainsid
))
1181 setup_add_ldif(samdb
, setup_path("provision_configuration_basedn.ldif"), {
1182 "CONFIGDN": names
.configdn
,
1183 "DESCRIPTOR": descr
,
1186 # The LDIF here was created when the Schema object was constructed
1187 logger
.info("Setting up sam.ldb schema")
1188 samdb
.add_ldif(schema
.schema_dn_add
, controls
=["relax:0"])
1189 samdb
.modify_ldif(schema
.schema_dn_modify
)
1190 samdb
.write_prefixes_from_schema()
1191 samdb
.add_ldif(schema
.schema_data
, controls
=["relax:0"])
1192 setup_add_ldif(samdb
, setup_path("aggregate_schema.ldif"),
1193 {"SCHEMADN": names
.schemadn
})
1195 # Now register this container in the root of the forest
1196 msg
= ldb
.Message(ldb
.Dn(samdb
, names
.domaindn
))
1197 msg
["subRefs"] = ldb
.MessageElement(names
.configdn
, ldb
.FLAG_MOD_ADD
,
1201 samdb
.transaction_cancel()
1204 samdb
.transaction_commit()
1206 samdb
.transaction_start()
1208 samdb
.invocation_id
= invocationid
1210 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1211 if fill
== FILL_FULL
:
1212 logger
.info("Setting up sam.ldb configuration data")
1213 setup_add_ldif(samdb
, setup_path("provision_configuration.ldif"), {
1214 "CONFIGDN": names
.configdn
,
1215 "NETBIOSNAME": names
.netbiosname
,
1216 "DEFAULTSITE": names
.sitename
,
1217 "DNSDOMAIN": names
.dnsdomain
,
1218 "DOMAIN": names
.domain
,
1219 "SCHEMADN": names
.schemadn
,
1220 "DOMAINDN": names
.domaindn
,
1221 "SERVERDN": names
.serverdn
,
1222 "FOREST_FUNCTIONALITY": str(forestFunctionality
),
1223 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
),
1226 logger
.info("Setting up display specifiers")
1227 display_specifiers_ldif
= read_ms_ldif(
1228 setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1229 display_specifiers_ldif
= substitute_var(display_specifiers_ldif
,
1230 {"CONFIGDN": names
.configdn
})
1231 check_all_substituted(display_specifiers_ldif
)
1232 samdb
.add_ldif(display_specifiers_ldif
)
1234 logger
.info("Adding users container")
1235 setup_add_ldif(samdb
, setup_path("provision_users_add.ldif"), {
1236 "DOMAINDN": names
.domaindn
})
1237 logger
.info("Modifying users container")
1238 setup_modify_ldif(samdb
, setup_path("provision_users_modify.ldif"), {
1239 "DOMAINDN": names
.domaindn
})
1240 logger
.info("Adding computers container")
1241 setup_add_ldif(samdb
, setup_path("provision_computers_add.ldif"), {
1242 "DOMAINDN": names
.domaindn
})
1243 logger
.info("Modifying computers container")
1244 setup_modify_ldif(samdb
,
1245 setup_path("provision_computers_modify.ldif"), {
1246 "DOMAINDN": names
.domaindn
})
1247 logger
.info("Setting up sam.ldb data")
1248 setup_add_ldif(samdb
, setup_path("provision.ldif"), {
1249 "CREATTIME": str(samba
.unix2nttime(int(time
.time()))),
1250 "DOMAINDN": names
.domaindn
,
1251 "NETBIOSNAME": names
.netbiosname
,
1252 "DEFAULTSITE": names
.sitename
,
1253 "CONFIGDN": names
.configdn
,
1254 "SERVERDN": names
.serverdn
,
1255 "RIDAVAILABLESTART": str(next_rid
+ 600),
1256 "POLICYGUID_DC": policyguid_dc
1259 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1260 if fill
== FILL_FULL
:
1261 setup_modify_ldif(samdb
,
1262 setup_path("provision_configuration_references.ldif"), {
1263 "CONFIGDN": names
.configdn
,
1264 "SCHEMADN": names
.schemadn
})
1266 logger
.info("Setting up well known security principals")
1267 setup_add_ldif(samdb
, setup_path("provision_well_known_sec_princ.ldif"), {
1268 "CONFIGDN": names
.configdn
,
1271 if fill
== FILL_FULL
or fill
== FILL_SUBDOMAIN
:
1272 setup_modify_ldif(samdb
,
1273 setup_path("provision_basedn_references.ldif"),
1274 {"DOMAINDN": names
.domaindn
})
1276 logger
.info("Setting up sam.ldb users and groups")
1277 setup_add_ldif(samdb
, setup_path("provision_users.ldif"), {
1278 "DOMAINDN": names
.domaindn
,
1279 "DOMAINSID": str(domainsid
),
1280 "ADMINPASS_B64": b64encode(adminpass
.encode('utf-16-le')),
1281 "KRBTGTPASS_B64": b64encode(krbtgtpass
.encode('utf-16-le'))
1284 logger
.info("Setting up self join")
1285 setup_self_join(samdb
, admin_session_info
, names
=names
, fill
=fill
, invocationid
=invocationid
,
1287 machinepass
=machinepass
,
1288 domainsid
=domainsid
,
1291 policyguid
=policyguid
,
1292 policyguid_dc
=policyguid_dc
,
1293 domainControllerFunctionality
=domainControllerFunctionality
,
1296 ntds_dn
= "CN=NTDS Settings,%s" % names
.serverdn
1297 names
.ntdsguid
= samdb
.searchone(basedn
=ntds_dn
,
1298 attribute
="objectGUID", expression
="", scope
=ldb
.SCOPE_BASE
)
1299 assert isinstance(names
.ntdsguid
, str)
1301 samdb
.transaction_cancel()
1304 samdb
.transaction_commit()
1309 FILL_SUBDOMAIN
= "SUBDOMAIN"
1310 FILL_NT4SYNC
= "NT4SYNC"
1312 SYSVOL_ACL
= "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
1313 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)"
1316 def set_dir_acl(path
, acl
, lp
, domsid
):
1317 setntacl(lp
, path
, acl
, domsid
)
1318 for root
, dirs
, files
in os
.walk(path
, topdown
=False):
1320 setntacl(lp
, os
.path
.join(root
, name
), acl
, domsid
)
1322 setntacl(lp
, os
.path
.join(root
, name
), acl
, domsid
)
1325 def set_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
):
1326 """Set ACL on the sysvol/<dnsname>/Policies folder and the policy
1329 :param sysvol: Physical path for the sysvol folder
1330 :param dnsdomain: The DNS name of the domain
1331 :param domainsid: The SID of the domain
1332 :param domaindn: The DN of the domain (ie. DC=...)
1333 :param samdb: An LDB object on the SAM db
1334 :param lp: an LP object
1337 # Set ACL for GPO root folder
1338 root_policy_path
= os
.path
.join(sysvol
, dnsdomain
, "Policies")
1339 setntacl(lp
, root_policy_path
, POLICIES_ACL
, str(domainsid
))
1341 res
= samdb
.search(base
="CN=Policies,CN=System,%s"%(domaindn),
1342 attrs
=["cn", "nTSecurityDescriptor"],
1343 expression
="", scope
=ldb
.SCOPE_ONELEVEL
)
1346 acl
= ndr_unpack(security
.descriptor
,
1347 str(policy
["nTSecurityDescriptor"])).as_sddl()
1348 policy_path
= getpolicypath(sysvol
, dnsdomain
, str(policy
["cn"]))
1349 set_dir_acl(policy_path
, dsacl2fsacl(acl
, str(domainsid
)), lp
,
1353 def setsysvolacl(samdb
, netlogon
, sysvol
, gid
, domainsid
, dnsdomain
, domaindn
,
1355 """Set the ACL for the sysvol share and the subfolders
1357 :param samdb: An LDB object on the SAM db
1358 :param netlogon: Physical path for the netlogon folder
1359 :param sysvol: Physical path for the sysvol folder
1360 :param gid: The GID of the "Domain adminstrators" group
1361 :param domainsid: The SID of the domain
1362 :param dnsdomain: The DNS name of the domain
1363 :param domaindn: The DN of the domain (ie. DC=...)
1367 os
.chown(sysvol
, -1, gid
)
1373 # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
1374 setntacl(lp
,sysvol
, SYSVOL_ACL
, str(domainsid
))
1375 for root
, dirs
, files
in os
.walk(sysvol
, topdown
=False):
1378 os
.chown(os
.path
.join(root
, name
), -1, gid
)
1379 setntacl(lp
, os
.path
.join(root
, name
), SYSVOL_ACL
, str(domainsid
))
1382 os
.chown(os
.path
.join(root
, name
), -1, gid
)
1383 setntacl(lp
, os
.path
.join(root
, name
), SYSVOL_ACL
, str(domainsid
))
1385 # Set acls on Policy folder and policies folders
1386 set_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
)
1389 def interface_ips_v4(lp
):
1390 '''return only IPv4 IPs'''
1391 ips
= samba
.interface_ips(lp
, False)
1394 if i
.find(':') == -1:
1398 def interface_ips_v6(lp
, linklocal
=False):
1399 '''return only IPv6 IPs'''
1400 ips
= samba
.interface_ips(lp
, False)
1403 if i
.find(':') != -1 and (linklocal
or i
.find('%') == -1):
1408 def provision_fill(samdb
, secrets_ldb
, logger
, names
, paths
,
1409 domainsid
, schema
=None,
1410 targetdir
=None, samdb_fill
=FILL_FULL
,
1411 hostip
=None, hostip6
=None,
1412 next_rid
=1000, dc_rid
=None, adminpass
=None, krbtgtpass
=None,
1413 domainguid
=None, policyguid
=None, policyguid_dc
=None,
1414 invocationid
=None, machinepass
=None, ntdsguid
=None,
1415 dns_backend
=None, dnspass
=None,
1416 serverrole
=None, dom_for_fun_level
=None,
1417 am_rodc
=False, lp
=None):
1418 # create/adapt the group policy GUIDs
1419 # Default GUID for default policy are described at
1420 # "How Core Group Policy Works"
1421 # http://technet.microsoft.com/en-us/library/cc784268%28WS.10%29.aspx
1422 if policyguid
is None:
1423 policyguid
= DEFAULT_POLICY_GUID
1424 policyguid
= policyguid
.upper()
1425 if policyguid_dc
is None:
1426 policyguid_dc
= DEFAULT_DC_POLICY_GUID
1427 policyguid_dc
= policyguid_dc
.upper()
1429 if invocationid
is None:
1430 invocationid
= str(uuid
.uuid4())
1432 if adminpass
is None:
1433 adminpass
= samba
.generate_random_password(12, 32)
1434 if krbtgtpass
is None:
1435 krbtgtpass
= samba
.generate_random_password(128, 255)
1436 if machinepass
is None:
1437 machinepass
= samba
.generate_random_password(128, 255)
1439 dnspass
= samba
.generate_random_password(128, 255)
1441 samdb
= fill_samdb(samdb
, lp
, names
, logger
=logger
,
1442 domainsid
=domainsid
, schema
=schema
, domainguid
=domainguid
,
1443 policyguid
=policyguid
, policyguid_dc
=policyguid_dc
,
1444 fill
=samdb_fill
, adminpass
=adminpass
, krbtgtpass
=krbtgtpass
,
1445 invocationid
=invocationid
, machinepass
=machinepass
,
1446 dnspass
=dnspass
, ntdsguid
=ntdsguid
, serverrole
=serverrole
,
1447 dom_for_fun_level
=dom_for_fun_level
, am_rodc
=am_rodc
,
1448 next_rid
=next_rid
, dc_rid
=dc_rid
)
1450 if serverrole
== "domain controller":
1451 # Set up group policies (domain policy and domain controller
1453 create_default_gpo(paths
.sysvol
, names
.dnsdomain
, policyguid
,
1455 setsysvolacl(samdb
, paths
.netlogon
, paths
.sysvol
, paths
.wheel_gid
,
1456 domainsid
, names
.dnsdomain
, names
.domaindn
, lp
)
1458 secretsdb_self_join(secrets_ldb
, domain
=names
.domain
,
1459 realm
=names
.realm
, dnsdomain
=names
.dnsdomain
,
1460 netbiosname
=names
.netbiosname
, domainsid
=domainsid
,
1461 machinepass
=machinepass
, secure_channel_type
=SEC_CHAN_BDC
)
1463 # Now set up the right msDS-SupportedEncryptionTypes into the DB
1464 # In future, this might be determined from some configuration
1465 kerberos_enctypes
= str(ENC_ALL_TYPES
)
1468 msg
= ldb
.Message(ldb
.Dn(samdb
,
1469 samdb
.searchone("distinguishedName",
1470 expression
="samAccountName=%s$" % names
.netbiosname
,
1471 scope
=ldb
.SCOPE_SUBTREE
)))
1472 msg
["msDS-SupportedEncryptionTypes"] = ldb
.MessageElement(
1473 elements
=kerberos_enctypes
, flags
=ldb
.FLAG_MOD_REPLACE
,
1474 name
="msDS-SupportedEncryptionTypes")
1476 except ldb
.LdbError
, (enum
, estr
):
1477 if enum
!= ldb
.ERR_NO_SUCH_ATTRIBUTE
:
1478 # It might be that this attribute does not exist in this schema
1481 setup_ad_dns(samdb
, secrets_ldb
, domainsid
, names
, paths
, lp
, logger
,
1482 hostip
=hostip
, hostip6
=hostip6
, dns_backend
=dns_backend
,
1483 dnspass
=dnspass
, os_level
=dom_for_fun_level
,
1484 targetdir
=targetdir
, site
=DEFAULTSITE
)
1486 domainguid
= samdb
.searchone(basedn
=samdb
.get_default_basedn(),
1487 attribute
="objectGUID")
1488 assert isinstance(domainguid
, str)
1490 lastProvisionUSNs
= get_last_provision_usn(samdb
)
1491 maxUSN
= get_max_usn(samdb
, str(names
.rootdn
))
1492 if lastProvisionUSNs
is not None:
1493 update_provision_usn(samdb
, 0, maxUSN
, invocationid
, 1)
1495 set_provision_usn(samdb
, 0, maxUSN
, invocationid
)
1497 logger
.info("Setting up sam.ldb rootDSE marking as synchronized")
1498 setup_modify_ldif(samdb
, setup_path("provision_rootdse_modify.ldif"),
1499 { 'NTDSGUID' : names
.ntdsguid
})
1501 # fix any dangling GUIDs from the provision
1502 logger
.info("Fixing provision GUIDs")
1503 chk
= dbcheck(samdb
, samdb_schema
=samdb
, verbose
=False, fix
=True, yes
=True, quiet
=True)
1504 samdb
.transaction_start()
1505 # a small number of GUIDs are missing because of ordering issues in the
1507 for schema_obj
in ['CN=Domain', 'CN=Organizational-Person', 'CN=Contact', 'CN=inetOrgPerson']:
1508 chk
.check_database(DN
="%s,%s" % (schema_obj
, names
.schemadn
),
1509 scope
=ldb
.SCOPE_BASE
, attrs
=['defaultObjectCategory'])
1510 chk
.check_database(DN
="CN=IP Security,CN=System,%s" % names
.domaindn
,
1511 scope
=ldb
.SCOPE_ONELEVEL
,
1512 attrs
=['ipsecOwnersReference',
1513 'ipsecFilterReference',
1514 'ipsecISAKMPReference',
1515 'ipsecNegotiationPolicyReference',
1516 'ipsecNFAReference'])
1517 samdb
.transaction_commit()
1519 def provision(logger
, session_info
, credentials
, smbconf
=None,
1520 targetdir
=None, samdb_fill
=FILL_FULL
, realm
=None, rootdn
=None,
1521 domaindn
=None, schemadn
=None, configdn
=None, serverdn
=None,
1522 domain
=None, hostname
=None, hostip
=None, hostip6
=None, domainsid
=None,
1523 next_rid
=1000, dc_rid
=None, adminpass
=None, ldapadminpass
=None, krbtgtpass
=None,
1524 domainguid
=None, policyguid
=None, policyguid_dc
=None,
1525 dns_backend
=None, dnspass
=None,
1526 invocationid
=None, machinepass
=None, ntdsguid
=None,
1527 root
=None, nobody
=None, users
=None, wheel
=None, backup
=None, aci
=None,
1528 serverrole
=None, dom_for_fun_level
=None,
1529 backend_type
=None, sitename
=None,
1530 ol_mmr_urls
=None, ol_olc
=None, slapd_path
=None,
1531 useeadb
=False, am_rodc
=False,
1535 :note: caution, this wipes all existing data!
1539 roles
["ROLE_STANDALONE"] = "standalone"
1540 roles
["ROLE_DOMAIN_MEMBER"] = "member server"
1541 roles
["ROLE_DOMAIN_BDC"] = "domain controller"
1542 roles
["ROLE_DOMAIN_PDC"] = "domain controller"
1543 roles
["dc"] = "domain controller"
1544 roles
["member"] = "member server"
1545 roles
["domain controller"] = "domain controller"
1546 roles
["member server"] = "member server"
1547 roles
["standalone"] = "standalone"
1550 serverrole
= roles
[serverrole
]
1552 raise ProvisioningError('server role (%s) should be one of "domain controller", "member server", "standalone"' % serverrole
)
1554 if ldapadminpass
is None:
1555 # Make a new, random password between Samba and it's LDAP server
1556 ldapadminpass
=samba
.generate_random_password(128, 255)
1558 if backend_type
is None:
1559 backend_type
= "ldb"
1561 if domainsid
is None:
1562 domainsid
= security
.random_sid()
1564 domainsid
= security
.dom_sid(domainsid
)
1566 sid_generator
= "internal"
1567 if backend_type
== "fedora-ds":
1568 sid_generator
= "backend"
1570 root_uid
= findnss_uid([root
or "root"])
1571 nobody_uid
= findnss_uid([nobody
or "nobody"])
1572 users_gid
= findnss_gid([users
or "users", 'users', 'other', 'staff'])
1574 wheel_gid
= findnss_gid(["wheel", "adm"])
1576 wheel_gid
= findnss_gid([wheel
])
1578 bind_gid
= findnss_gid(["bind", "named"])
1582 if targetdir
is not None:
1583 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
1584 elif smbconf
is None:
1585 smbconf
= samba
.param
.default_path()
1586 if not os
.path
.exists(os
.path
.dirname(smbconf
)):
1587 os
.makedirs(os
.path
.dirname(smbconf
))
1589 # only install a new smb.conf if there isn't one there already
1590 if os
.path
.exists(smbconf
):
1591 # if Samba Team members can't figure out the weird errors
1592 # loading an empty smb.conf gives, then we need to be smarter.
1593 # Pretend it just didn't exist --abartlet
1594 data
= open(smbconf
, 'r').read()
1595 data
= data
.lstrip()
1596 if data
is None or data
== "":
1597 make_smbconf(smbconf
, hostname
, domain
, realm
,
1598 serverrole
, targetdir
, sid_generator
, useeadb
,
1601 make_smbconf(smbconf
, hostname
, domain
, realm
, serverrole
,
1602 targetdir
, sid_generator
, useeadb
, lp
=lp
)
1605 lp
= samba
.param
.LoadParm()
1607 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
1608 dnsdomain
=realm
, serverrole
=serverrole
, domaindn
=domaindn
,
1609 configdn
=configdn
, schemadn
=schemadn
, serverdn
=serverdn
,
1610 sitename
=sitename
, rootdn
=rootdn
)
1611 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
1613 paths
.bind_gid
= bind_gid
1614 paths
.wheel_gid
= wheel_gid
1617 logger
.info("Looking up IPv4 addresses")
1618 hostips
= interface_ips_v4(lp
)
1619 if len(hostips
) > 0:
1621 if len(hostips
) > 1:
1622 logger
.warning("More than one IPv4 address found. Using %s",
1624 if hostip
== "127.0.0.1":
1627 logger
.warning("No IPv4 address will be assigned")
1630 logger
.info("Looking up IPv6 addresses")
1631 hostips
= interface_ips_v6(lp
, linklocal
=False)
1633 hostip6
= hostips
[0]
1634 if len(hostips
) > 1:
1635 logger
.warning("More than one IPv6 address found. Using %s", hostip6
)
1637 logger
.warning("No IPv6 address will be assigned")
1639 names
.hostip
= hostip
1640 names
.hostip6
= hostip6
1642 if serverrole
is None:
1643 serverrole
= lp
.get("server role")
1645 if not os
.path
.exists(paths
.private_dir
):
1646 os
.mkdir(paths
.private_dir
)
1647 if not os
.path
.exists(os
.path
.join(paths
.private_dir
, "tls")):
1648 os
.mkdir(os
.path
.join(paths
.private_dir
, "tls"))
1650 ldapi_url
= "ldapi://%s" % urllib
.quote(paths
.s4_ldapi_path
, safe
="")
1652 schema
= Schema(domainsid
, invocationid
=invocationid
,
1653 schemadn
=names
.schemadn
)
1655 if backend_type
== "ldb":
1656 provision_backend
= LDBBackend(backend_type
, paths
=paths
,
1657 lp
=lp
, credentials
=credentials
,
1658 names
=names
, logger
=logger
)
1659 elif backend_type
== "existing":
1660 # If support for this is ever added back, then the URI will need to be specified again
1661 provision_backend
= ExistingBackend(backend_type
, paths
=paths
,
1662 lp
=lp
, credentials
=credentials
,
1663 names
=names
, logger
=logger
,
1664 ldap_backend_forced_uri
=None)
1665 elif backend_type
== "fedora-ds":
1666 provision_backend
= FDSBackend(backend_type
, paths
=paths
,
1667 lp
=lp
, credentials
=credentials
,
1668 names
=names
, logger
=logger
, domainsid
=domainsid
,
1669 schema
=schema
, hostname
=hostname
, ldapadminpass
=ldapadminpass
,
1670 slapd_path
=slapd_path
,
1672 elif backend_type
== "openldap":
1673 provision_backend
= OpenLDAPBackend(backend_type
, paths
=paths
,
1674 lp
=lp
, credentials
=credentials
,
1675 names
=names
, logger
=logger
, domainsid
=domainsid
,
1676 schema
=schema
, hostname
=hostname
, ldapadminpass
=ldapadminpass
,
1677 slapd_path
=slapd_path
, ol_mmr_urls
=ol_mmr_urls
)
1679 raise ValueError("Unknown LDAP backend type selected")
1681 provision_backend
.init()
1682 provision_backend
.start()
1684 # only install a new shares config db if there is none
1685 if not os
.path
.exists(paths
.shareconf
):
1686 logger
.info("Setting up share.ldb")
1687 share_ldb
= Ldb(paths
.shareconf
, session_info
=session_info
,
1689 share_ldb
.load_ldif_file_add(setup_path("share.ldif"))
1691 logger
.info("Setting up secrets.ldb")
1692 secrets_ldb
= setup_secretsdb(paths
,
1693 session_info
=session_info
,
1694 backend_credentials
=provision_backend
.secrets_credentials
, lp
=lp
)
1697 logger
.info("Setting up the registry")
1698 setup_registry(paths
.hklm
, session_info
,
1701 logger
.info("Setting up the privileges database")
1702 setup_privileges(paths
.privilege
, session_info
, lp
=lp
)
1704 logger
.info("Setting up idmap db")
1705 idmap
= setup_idmapdb(paths
.idmapdb
,
1706 session_info
=session_info
, lp
=lp
)
1708 setup_name_mappings(idmap
, sid
=str(domainsid
),
1709 root_uid
=root_uid
, nobody_uid
=nobody_uid
,
1710 users_gid
=users_gid
, wheel_gid
=wheel_gid
)
1712 logger
.info("Setting up SAM db")
1713 samdb
= setup_samdb(paths
.samdb
, session_info
,
1714 provision_backend
, lp
, names
, logger
=logger
,
1715 serverrole
=serverrole
,
1716 schema
=schema
, fill
=samdb_fill
, am_rodc
=am_rodc
)
1718 if serverrole
== "domain controller":
1719 if paths
.netlogon
is None:
1720 logger
.info("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
1721 logger
.info("Please either remove %s or see the template at %s" %
1722 (paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1723 assert paths
.netlogon
is not None
1725 if paths
.sysvol
is None:
1726 logger
.info("Existing smb.conf does not have a [sysvol] share, but you"
1727 " are configuring a DC.")
1728 logger
.info("Please either remove %s or see the template at %s" %
1729 (paths
.smbconf
, setup_path("provision.smb.conf.dc")))
1730 assert paths
.sysvol
is not None
1732 if not os
.path
.isdir(paths
.netlogon
):
1733 os
.makedirs(paths
.netlogon
, 0755)
1735 if samdb_fill
== FILL_FULL
:
1736 provision_fill(samdb
, secrets_ldb
, logger
,
1737 names
, paths
, schema
=schema
, targetdir
=targetdir
,
1738 samdb_fill
=samdb_fill
, hostip
=hostip
, hostip6
=hostip6
, domainsid
=domainsid
,
1739 next_rid
=next_rid
, dc_rid
=dc_rid
, adminpass
=adminpass
,
1740 krbtgtpass
=krbtgtpass
, domainguid
=domainguid
,
1741 policyguid
=policyguid
, policyguid_dc
=policyguid_dc
,
1742 invocationid
=invocationid
, machinepass
=machinepass
,
1743 ntdsguid
=ntdsguid
, dns_backend
=dns_backend
, dnspass
=dnspass
,
1744 serverrole
=serverrole
, dom_for_fun_level
=dom_for_fun_level
,
1745 am_rodc
=am_rodc
, lp
=lp
)
1747 create_krb5_conf(paths
.krb5conf
,
1748 dnsdomain
=names
.dnsdomain
, hostname
=names
.hostname
,
1750 logger
.info("A Kerberos configuration suitable for Samba 4 has been "
1751 "generated at %s", paths
.krb5conf
)
1753 if serverrole
== "domain controller":
1754 create_dns_update_list(lp
, logger
, paths
)
1756 provision_backend
.post_setup()
1757 provision_backend
.shutdown()
1759 create_phpldapadmin_config(paths
.phpldapadminconfig
,
1762 secrets_ldb
.transaction_cancel()
1765 # Now commit the secrets.ldb to disk
1766 secrets_ldb
.transaction_commit()
1768 # the commit creates the dns.keytab, now chown it
1769 dns_keytab_path
= os
.path
.join(paths
.private_dir
, paths
.dns_keytab
)
1770 if os
.path
.isfile(dns_keytab_path
) and paths
.bind_gid
is not None:
1772 os
.chmod(dns_keytab_path
, 0640)
1773 os
.chown(dns_keytab_path
, -1, paths
.bind_gid
)
1775 if not os
.environ
.has_key('SAMBA_SELFTEST'):
1776 logger
.info("Failed to chown %s to bind gid %u",
1777 dns_keytab_path
, paths
.bind_gid
)
1779 logger
.info("A phpLDAPadmin configuration file suitable for administering the Samba 4 LDAP server has been created in %s .",
1780 paths
.phpldapadminconfig
)
1782 logger
.info("Once the above files are installed, your Samba4 server will be ready to use")
1783 logger
.info("Server Role: %s" % serverrole
)
1784 logger
.info("Hostname: %s" % names
.hostname
)
1785 logger
.info("NetBIOS Domain: %s" % names
.domain
)
1786 logger
.info("DNS Domain: %s" % names
.dnsdomain
)
1787 logger
.info("DOMAIN SID: %s" % str(domainsid
))
1788 if samdb_fill
== FILL_FULL
:
1789 logger
.info("Admin password: %s" % adminpass
)
1790 if provision_backend
.type is not "ldb":
1791 if provision_backend
.credentials
.get_bind_dn() is not None:
1792 logger
.info("LDAP Backend Admin DN: %s" %
1793 provision_backend
.credentials
.get_bind_dn())
1795 logger
.info("LDAP Admin User: %s" %
1796 provision_backend
.credentials
.get_username())
1798 logger
.info("LDAP Admin Password: %s" %
1799 provision_backend
.credentials
.get_password())
1801 if provision_backend
.slapd_command_escaped
is not None:
1802 # now display slapd_command_file.txt to show how slapd must be
1804 logger
.info("Use later the following commandline to start slapd, then Samba:")
1805 logger
.info(provision_backend
.slapd_command_escaped
)
1806 logger
.info("This slapd-Commandline is also stored under: %s/ldap_backend_startup.sh",
1807 provision_backend
.ldapdir
)
1809 result
= ProvisionResult()
1810 result
.domaindn
= domaindn
1811 result
.paths
= paths
1812 result
.names
= names
1814 result
.samdb
= samdb
1815 result
.idmap
= idmap
1819 def provision_become_dc(smbconf
=None, targetdir
=None,
1820 realm
=None, rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
1821 serverdn
=None, domain
=None, hostname
=None, domainsid
=None,
1822 adminpass
=None, krbtgtpass
=None, domainguid
=None, policyguid
=None,
1823 policyguid_dc
=None, invocationid
=None, machinepass
=None, dnspass
=None,
1824 dns_backend
=None, root
=None, nobody
=None, users
=None, wheel
=None, backup
=None,
1825 serverrole
=None, ldap_backend
=None, ldap_backend_type
=None,
1826 sitename
=None, debuglevel
=1):
1828 logger
= logging
.getLogger("provision")
1829 samba
.set_debug_level(debuglevel
)
1831 res
= provision(logger
, system_session(), None,
1832 smbconf
=smbconf
, targetdir
=targetdir
, samdb_fill
=FILL_DRS
,
1833 realm
=realm
, rootdn
=rootdn
, domaindn
=domaindn
, schemadn
=schemadn
,
1834 configdn
=configdn
, serverdn
=serverdn
, domain
=domain
,
1835 hostname
=hostname
, hostip
=None, domainsid
=domainsid
,
1836 machinepass
=machinepass
, serverrole
="domain controller",
1837 sitename
=sitename
, dns_backend
=dns_backend
, dnspass
=dnspass
)
1838 res
.lp
.set("debuglevel", str(debuglevel
))
1842 def create_phpldapadmin_config(path
, ldapi_uri
):
1843 """Create a PHP LDAP admin configuration file.
1845 :param path: Path to write the configuration to.
1847 setup_file(setup_path("phpldapadmin-config.php"), path
,
1848 {"S4_LDAPI_URI": ldapi_uri
})
1851 def create_krb5_conf(path
, dnsdomain
, hostname
, realm
):
1852 """Write out a file containing zone statements suitable for inclusion in a
1853 named.conf file (including GSS-TSIG configuration).
1855 :param path: Path of the new named.conf file.
1856 :param dnsdomain: DNS Domain name
1857 :param hostname: Local hostname
1858 :param realm: Realm name
1860 setup_file(setup_path("krb5.conf"), path
, {
1861 "DNSDOMAIN": dnsdomain
,
1862 "HOSTNAME": hostname
,
1867 class ProvisioningError(Exception):
1868 """A generic provision error."""
1870 def __init__(self
, value
):
1874 return "ProvisioningError: " + self
.value
1877 class InvalidNetbiosName(Exception):
1878 """A specified name was not a valid NetBIOS name."""
1879 def __init__(self
, name
):
1880 super(InvalidNetbiosName
, self
).__init
__(
1881 "The name '%r' is not a valid NetBIOS name" % name
)