2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2012
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
.samba3
import smbd
, passdb
48 from samba
.samba3
import param
as s3param
49 from samba
.dsdb
import DS_DOMAIN_FUNCTION_2000
53 check_all_substituted
,
54 is_valid_netbios_char
,
60 from samba
.dcerpc
import security
, misc
61 from samba
.dcerpc
.misc
import (
65 from samba
.dsdb
import (
66 DS_DOMAIN_FUNCTION_2003
,
67 DS_DOMAIN_FUNCTION_2008_R2
,
70 from samba
.idmap
import IDmapDB
71 from samba
.ms_display_specifiers
import read_ms_ldif
72 from samba
.ntacls
import setntacl
, dsacl2fsacl
73 from samba
.ndr
import ndr_pack
, ndr_unpack
74 from samba
.provision
.backend
import (
80 from samba
.provision
.descriptor
import (
81 get_config_descriptor
,
84 from samba
.provision
.common
import (
89 from samba
.provision
.sambadns
import (
91 create_dns_update_list
96 from samba
.schema
import Schema
97 from samba
.samdb
import SamDB
98 from samba
.dbchecker
import dbcheck
101 DEFAULT_POLICY_GUID
= "31B2F340-016D-11D2-945F-00C04FB984F9"
102 DEFAULT_DC_POLICY_GUID
= "6AC1786C-016F-11D2-945F-00C04fB984F9"
103 DEFAULTSITE
= "Default-First-Site-Name"
104 LAST_PROVISION_USN_ATTRIBUTE
= "lastProvisionUSN"
107 class ProvisionPaths(object):
110 self
.shareconf
= None
121 self
.dns_keytab
= None
124 self
.private_dir
= None
125 self
.state_dir
= None
126 self
.phpldapadminconfig
= None
129 class ProvisionNames(object):
136 self
.ldapmanagerdn
= None
137 self
.dnsdomain
= None
139 self
.netbiosname
= None
145 def find_provision_key_parameters(samdb
, secretsdb
, idmapdb
, paths
, smbconf
, lp
):
146 """Get key provision parameters (realm, domain, ...) from a given provision
148 :param samdb: An LDB object connected to the sam.ldb file
149 :param secretsdb: An LDB object connected to the secrets.ldb file
150 :param idmapdb: An LDB object connected to the idmap.ldb file
151 :param paths: A list of path to provision object
152 :param smbconf: Path to the smb.conf file
153 :param lp: A LoadParm object
154 :return: A list of key provision parameters
156 names
= ProvisionNames()
157 names
.adminpass
= None
159 # NT domain, kerberos realm, root dn, domain dn, domain dns name
160 names
.domain
= string
.upper(lp
.get("workgroup"))
161 names
.realm
= lp
.get("realm")
162 names
.dnsdomain
= names
.realm
.lower()
163 basedn
= samba
.dn_from_dns_name(names
.dnsdomain
)
164 names
.realm
= string
.upper(names
.realm
)
166 # Get the netbiosname first (could be obtained from smb.conf in theory)
167 res
= secretsdb
.search(expression
="(flatname=%s)" %
168 names
.domain
,base
="CN=Primary Domains",
169 scope
=ldb
.SCOPE_SUBTREE
, attrs
=["sAMAccountName"])
170 names
.netbiosname
= str(res
[0]["sAMAccountName"]).replace("$","")
172 names
.smbconf
= smbconf
174 # That's a bit simplistic but it's ok as long as we have only 3
176 current
= samdb
.search(expression
="(objectClass=*)",
177 base
="", scope
=ldb
.SCOPE_BASE
,
178 attrs
=["defaultNamingContext", "schemaNamingContext",
179 "configurationNamingContext","rootDomainNamingContext"])
181 names
.configdn
= current
[0]["configurationNamingContext"]
182 configdn
= str(names
.configdn
)
183 names
.schemadn
= current
[0]["schemaNamingContext"]
184 if not (ldb
.Dn(samdb
, basedn
) == (ldb
.Dn(samdb
,
185 current
[0]["defaultNamingContext"][0]))):
186 raise ProvisioningError(("basedn in %s (%s) and from %s (%s)"
187 "is not the same ..." % (paths
.samdb
,
188 str(current
[0]["defaultNamingContext"][0]),
189 paths
.smbconf
, basedn
)))
191 names
.domaindn
=current
[0]["defaultNamingContext"]
192 names
.rootdn
=current
[0]["rootDomainNamingContext"]
194 res3
= samdb
.search(expression
="(objectClass=site)",
195 base
="CN=Sites," + configdn
, scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn"])
196 names
.sitename
= str(res3
[0]["cn"])
198 # dns hostname and server dn
199 res4
= samdb
.search(expression
="(CN=%s)" % names
.netbiosname
,
200 base
="OU=Domain Controllers,%s" % basedn
,
201 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["dNSHostName"])
202 names
.hostname
= str(res4
[0]["dNSHostName"]).replace("." + names
.dnsdomain
,"")
204 server_res
= samdb
.search(expression
="serverReference=%s" % res4
[0].dn
,
205 attrs
=[], base
=configdn
)
206 names
.serverdn
= server_res
[0].dn
208 # invocation id/objectguid
209 res5
= samdb
.search(expression
="(objectClass=*)",
210 base
="CN=NTDS Settings,%s" % str(names
.serverdn
), scope
=ldb
.SCOPE_BASE
,
211 attrs
=["invocationID", "objectGUID"])
212 names
.invocation
= str(ndr_unpack(misc
.GUID
, res5
[0]["invocationId"][0]))
213 names
.ntdsguid
= str(ndr_unpack(misc
.GUID
, res5
[0]["objectGUID"][0]))
216 res6
= samdb
.search(expression
="(objectClass=*)", base
=basedn
,
217 scope
=ldb
.SCOPE_BASE
, attrs
=["objectGUID",
218 "objectSid","msDS-Behavior-Version" ])
219 names
.domainguid
= str(ndr_unpack(misc
.GUID
, res6
[0]["objectGUID"][0]))
220 names
.domainsid
= ndr_unpack( security
.dom_sid
, res6
[0]["objectSid"][0])
221 if res6
[0].get("msDS-Behavior-Version") is None or \
222 int(res6
[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000
:
223 names
.domainlevel
= DS_DOMAIN_FUNCTION_2000
225 names
.domainlevel
= int(res6
[0]["msDS-Behavior-Version"][0])
228 res7
= samdb
.search(expression
="(displayName=Default Domain Policy)",
229 base
="CN=Policies,CN=System," + basedn
,
230 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn","displayName"])
231 names
.policyid
= str(res7
[0]["cn"]).replace("{","").replace("}","")
233 res8
= samdb
.search(expression
="(displayName=Default Domain Controllers"
235 base
="CN=Policies,CN=System," + basedn
,
236 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn","displayName"])
238 names
.policyid_dc
= str(res8
[0]["cn"]).replace("{","").replace("}","")
240 names
.policyid_dc
= None
241 res9
= idmapdb
.search(expression
="(cn=%s)" %
242 (security
.SID_BUILTIN_ADMINISTRATORS
),
245 names
.wheel_gid
= res9
[0]["xidNumber"]
247 raise ProvisioningError("Unable to find uid/gid for Domain Admins rid")
251 def update_provision_usn(samdb
, low
, high
, id, replace
=False):
252 """Update the field provisionUSN in sam.ldb
254 This field is used to track range of USN modified by provision and
256 This value is used afterward by next provision to figure out if
257 the field have been modified since last provision.
259 :param samdb: An LDB object connect to sam.ldb
260 :param low: The lowest USN modified by this upgrade
261 :param high: The highest USN modified by this upgrade
262 :param id: The invocation id of the samba's dc
263 :param replace: A boolean indicating if the range should replace any
264 existing one or appended (default)
269 entry
= samdb
.search(base
="@PROVISION",
270 scope
=ldb
.SCOPE_BASE
,
271 attrs
=[LAST_PROVISION_USN_ATTRIBUTE
, "dn"])
272 for e
in entry
[0][LAST_PROVISION_USN_ATTRIBUTE
]:
273 if not re
.search(';', e
):
274 e
= "%s;%s" % (e
, id)
277 tab
.append("%s-%s;%s" % (low
, high
, id))
278 delta
= ldb
.Message()
279 delta
.dn
= ldb
.Dn(samdb
, "@PROVISION")
280 delta
[LAST_PROVISION_USN_ATTRIBUTE
] = ldb
.MessageElement(tab
,
281 ldb
.FLAG_MOD_REPLACE
, LAST_PROVISION_USN_ATTRIBUTE
)
282 entry
= samdb
.search(expression
='provisionnerID=*',
283 base
="@PROVISION", scope
=ldb
.SCOPE_BASE
,
284 attrs
=["provisionnerID"])
285 if len(entry
) == 0 or len(entry
[0]) == 0:
286 delta
["provisionnerID"] = ldb
.MessageElement(id, ldb
.FLAG_MOD_ADD
, "provisionnerID")
290 def set_provision_usn(samdb
, low
, high
, id):
291 """Set the field provisionUSN in sam.ldb
292 This field is used to track range of USN modified by provision and
294 This value is used afterward by next provision to figure out if
295 the field have been modified since last provision.
297 :param samdb: An LDB object connect to sam.ldb
298 :param low: The lowest USN modified by this upgrade
299 :param high: The highest USN modified by this upgrade
300 :param id: The invocationId of the provision"""
303 tab
.append("%s-%s;%s" % (low
, high
, id))
305 delta
= ldb
.Message()
306 delta
.dn
= ldb
.Dn(samdb
, "@PROVISION")
307 delta
[LAST_PROVISION_USN_ATTRIBUTE
] = ldb
.MessageElement(tab
,
308 ldb
.FLAG_MOD_ADD
, LAST_PROVISION_USN_ATTRIBUTE
)
312 def get_max_usn(samdb
,basedn
):
313 """ This function return the biggest USN present in the provision
315 :param samdb: A LDB object pointing to the sam.ldb
316 :param basedn: A string containing the base DN of the provision
318 :return: The biggest USN in the provision"""
320 res
= samdb
.search(expression
="objectClass=*",base
=basedn
,
321 scope
=ldb
.SCOPE_SUBTREE
,attrs
=["uSNChanged"],
322 controls
=["search_options:1:2",
323 "server_sort:1:1:uSNChanged",
324 "paged_results:1:1"])
325 return res
[0]["uSNChanged"]
328 def get_last_provision_usn(sam
):
329 """Get USNs ranges modified by a provision or an upgradeprovision
331 :param sam: An LDB object pointing to the sam.ldb
332 :return: a dictionnary which keys are invocation id and values are an array
333 of integer representing the different ranges
336 entry
= sam
.search(expression
="%s=*" % LAST_PROVISION_USN_ATTRIBUTE
,
337 base
="@PROVISION", scope
=ldb
.SCOPE_BASE
,
338 attrs
=[LAST_PROVISION_USN_ATTRIBUTE
, "provisionnerID"])
339 except ldb
.LdbError
, (ecode
, emsg
):
340 if ecode
== ldb
.ERR_NO_SUCH_OBJECT
:
347 if entry
[0].get("provisionnerID"):
348 for e
in entry
[0]["provisionnerID"]:
350 for r
in entry
[0][LAST_PROVISION_USN_ATTRIBUTE
]:
351 tab1
= str(r
).split(';')
356 if (len(myids
) > 0 and id not in myids
):
358 tab2
= p
.split(tab1
[0])
359 if range.get(id) == None:
361 range[id].append(tab2
[0])
362 range[id].append(tab2
[1])
368 class ProvisionResult(object):
369 """Result of a provision.
371 :ivar server_role: The server role
372 :ivar paths: ProvisionPaths instance
373 :ivar domaindn: The domain dn, as string
377 self
.server_role
= None
384 self
.domainsid
= None
385 self
.adminpass_generated
= None
386 self
.adminpass
= None
387 self
.backend_result
= None
389 def report_logger(self
, logger
):
390 """Report this provision result to a logger."""
392 "Once the above files are installed, your Samba4 server will "
394 if self
.adminpass_generated
:
395 logger
.info("Admin password: %s", self
.adminpass
)
396 logger
.info("Server Role: %s", self
.server_role
)
397 logger
.info("Hostname: %s", self
.names
.hostname
)
398 logger
.info("NetBIOS Domain: %s", self
.names
.domain
)
399 logger
.info("DNS Domain: %s", self
.names
.dnsdomain
)
400 logger
.info("DOMAIN SID: %s", self
.domainsid
)
402 if self
.paths
.phpldapadminconfig
is not None:
404 "A phpLDAPadmin configuration file suitable for administering "
405 "the Samba 4 LDAP server has been created in %s.",
406 self
.paths
.phpldapadminconfig
)
408 if self
.backend_result
:
409 self
.backend_result
.report_logger(logger
)
412 def check_install(lp
, session_info
, credentials
):
413 """Check whether the current install seems ok.
415 :param lp: Loadparm context
416 :param session_info: Session information
417 :param credentials: Credentials
419 if lp
.get("realm") == "":
420 raise Exception("Realm empty")
421 samdb
= Ldb(lp
.samdb_url(), session_info
=session_info
,
422 credentials
=credentials
, lp
=lp
)
423 if len(samdb
.search("(cn=Administrator)")) != 1:
424 raise ProvisioningError("No administrator account found")
427 def findnss(nssfn
, names
):
428 """Find a user or group from a list of possibilities.
430 :param nssfn: NSS Function to try (should raise KeyError if not found)
431 :param names: Names to check.
432 :return: Value return by first names list.
439 raise KeyError("Unable to find user/group in %r" % names
)
442 findnss_uid
= lambda names
: findnss(pwd
.getpwnam
, names
)[2]
443 findnss_gid
= lambda names
: findnss(grp
.getgrnam
, names
)[2]
446 def provision_paths_from_lp(lp
, dnsdomain
):
447 """Set the default paths for provisioning.
449 :param lp: Loadparm context.
450 :param dnsdomain: DNS Domain name
452 paths
= ProvisionPaths()
453 paths
.private_dir
= lp
.get("private dir")
454 paths
.state_dir
= lp
.get("state directory")
456 # This is stored without path prefix for the "privateKeytab" attribute in
457 # "secrets_dns.ldif".
458 paths
.dns_keytab
= "dns.keytab"
459 paths
.keytab
= "secrets.keytab"
461 paths
.shareconf
= os
.path
.join(paths
.private_dir
, "share.ldb")
462 paths
.samdb
= os
.path
.join(paths
.private_dir
, "sam.ldb")
463 paths
.idmapdb
= os
.path
.join(paths
.private_dir
, "idmap.ldb")
464 paths
.secrets
= os
.path
.join(paths
.private_dir
, "secrets.ldb")
465 paths
.privilege
= os
.path
.join(paths
.private_dir
, "privilege.ldb")
466 paths
.dns
= os
.path
.join(paths
.private_dir
, "dns", dnsdomain
+ ".zone")
467 paths
.dns_update_list
= os
.path
.join(paths
.private_dir
, "dns_update_list")
468 paths
.spn_update_list
= os
.path
.join(paths
.private_dir
, "spn_update_list")
469 paths
.namedconf
= os
.path
.join(paths
.private_dir
, "named.conf")
470 paths
.namedconf_update
= os
.path
.join(paths
.private_dir
, "named.conf.update")
471 paths
.namedtxt
= os
.path
.join(paths
.private_dir
, "named.txt")
472 paths
.krb5conf
= os
.path
.join(paths
.private_dir
, "krb5.conf")
473 paths
.winsdb
= os
.path
.join(paths
.private_dir
, "wins.ldb")
474 paths
.s4_ldapi_path
= os
.path
.join(paths
.private_dir
, "ldapi")
475 paths
.phpldapadminconfig
= os
.path
.join(paths
.private_dir
,
476 "phpldapadmin-config.php")
477 paths
.hklm
= "hklm.ldb"
478 paths
.hkcr
= "hkcr.ldb"
479 paths
.hkcu
= "hkcu.ldb"
480 paths
.hku
= "hku.ldb"
481 paths
.hkpd
= "hkpd.ldb"
482 paths
.hkpt
= "hkpt.ldb"
483 paths
.sysvol
= lp
.get("path", "sysvol")
484 paths
.netlogon
= lp
.get("path", "netlogon")
485 paths
.smbconf
= lp
.configfile
489 def determine_netbios_name(hostname
):
490 """Determine a netbios name from a hostname."""
491 # remove forbidden chars and force the length to be <16
492 netbiosname
= "".join([x
for x
in hostname
if is_valid_netbios_char(x
)])
493 return netbiosname
[:MAX_NETBIOS_NAME_LEN
].upper()
496 def guess_names(lp
=None, hostname
=None, domain
=None, dnsdomain
=None,
497 serverrole
=None, rootdn
=None, domaindn
=None, configdn
=None,
498 schemadn
=None, serverdn
=None, sitename
=None):
499 """Guess configuration settings to use."""
502 hostname
= socket
.gethostname().split(".")[0]
504 netbiosname
= lp
.get("netbios name")
505 if netbiosname
is None:
506 netbiosname
= determine_netbios_name(hostname
)
507 netbiosname
= netbiosname
.upper()
508 if not valid_netbios_name(netbiosname
):
509 raise InvalidNetbiosName(netbiosname
)
511 if dnsdomain
is None:
512 dnsdomain
= lp
.get("realm")
513 if dnsdomain
is None or dnsdomain
== "":
514 raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp
.configfile
)
516 dnsdomain
= dnsdomain
.lower()
518 if serverrole
is None:
519 serverrole
= lp
.get("server role")
520 if serverrole
is None:
521 raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp
.configfile
)
523 serverrole
= serverrole
.lower()
525 realm
= dnsdomain
.upper()
527 if lp
.get("realm") == "":
528 raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s. Please remove the smb.conf file and let provision generate it" % lp
.configfile
)
530 if lp
.get("realm").upper() != realm
:
531 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
))
533 if lp
.get("server role").lower() != serverrole
:
534 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"), lp
.configfile
, serverrole
))
536 if serverrole
== "active directory domain controller":
538 # This will, for better or worse, default to 'WORKGROUP'
539 domain
= lp
.get("workgroup")
540 domain
= domain
.upper()
542 if lp
.get("workgroup").upper() != domain
:
543 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
))
546 domaindn
= samba
.dn_from_dns_name(dnsdomain
)
548 if domain
== netbiosname
:
549 raise ProvisioningError("guess_names: Domain '%s' must not be equal to short host name '%s'!" % (domain
, netbiosname
))
553 domaindn
= "DC=" + netbiosname
555 if not valid_netbios_name(domain
):
556 raise InvalidNetbiosName(domain
)
558 if hostname
.upper() == realm
:
559 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm
, hostname
))
560 if netbiosname
.upper() == realm
:
561 raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!" % (realm
, netbiosname
))
563 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm
, domain
))
569 configdn
= "CN=Configuration," + rootdn
571 schemadn
= "CN=Schema," + configdn
574 sitename
= DEFAULTSITE
576 names
= ProvisionNames()
577 names
.rootdn
= rootdn
578 names
.domaindn
= domaindn
579 names
.configdn
= configdn
580 names
.schemadn
= schemadn
581 names
.ldapmanagerdn
= "CN=Manager," + rootdn
582 names
.dnsdomain
= dnsdomain
583 names
.domain
= domain
585 names
.netbiosname
= netbiosname
586 names
.hostname
= hostname
587 names
.sitename
= sitename
588 names
.serverdn
= "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (
589 netbiosname
, sitename
, configdn
)
594 def make_smbconf(smbconf
, hostname
, domain
, realm
, targetdir
,
595 serverrole
=None, eadb
=False, use_ntvfs
=False, lp
=None,
597 """Create a new smb.conf file based on a couple of basic settings.
599 assert smbconf
is not None
602 hostname
= socket
.gethostname().split(".")[0]
604 netbiosname
= determine_netbios_name(hostname
)
606 if serverrole
is None:
607 serverrole
= "standalone server"
609 assert domain
is not None
610 domain
= domain
.upper()
612 assert realm
is not None
613 realm
= realm
.upper()
616 "passdb backend": "samba4",
617 "netbios name": netbiosname
,
620 "server role": serverrole
,
624 lp
= samba
.param
.LoadParm()
625 #Load non-existent file
626 if os
.path
.exists(smbconf
):
629 if global_param
is not None:
630 for ent
in global_param
:
631 if global_param
[ent
] is not None:
632 global_settings
[ent
] = " ".join(global_param
[ent
])
634 if targetdir
is not None:
635 global_settings
["private dir"] = os
.path
.abspath(os
.path
.join(targetdir
, "private"))
636 global_settings
["lock dir"] = os
.path
.abspath(targetdir
)
637 global_settings
["state directory"] = os
.path
.abspath(os
.path
.join(targetdir
, "state"))
638 global_settings
["cache directory"] = os
.path
.abspath(os
.path
.join(targetdir
, "cache"))
640 lp
.set("lock dir", os
.path
.abspath(targetdir
))
641 lp
.set("state directory", global_settings
["state directory"])
642 lp
.set("cache directory", global_settings
["cache directory"])
645 if use_ntvfs
and not lp
.get("posix:eadb"):
646 if targetdir
is not None:
647 privdir
= os
.path
.join(targetdir
, "private")
649 privdir
= lp
.get("private dir")
650 lp
.set("posix:eadb", os
.path
.abspath(os
.path
.join(privdir
, "eadb.tdb")))
651 elif not use_ntvfs
and not lp
.get("xattr_tdb:file"):
652 if targetdir
is not None:
653 statedir
= os
.path
.join(targetdir
, "state")
655 statedir
= lp
.get("state directory")
656 lp
.set("xattr_tdb:file", os
.path
.abspath(os
.path
.join(statedir
, "xattr.tdb")))
659 if serverrole
== "active directory domain controller":
660 shares
["sysvol"] = os
.path
.join(lp
.get("state directory"), "sysvol")
661 shares
["netlogon"] = os
.path
.join(shares
["sysvol"], realm
.lower(),
664 f
= open(smbconf
, 'w')
666 f
.write("[globals]\n")
667 for key
, val
in global_settings
.iteritems():
668 f
.write("\t%s = %s\n" % (key
, val
))
671 for name
, path
in shares
.iteritems():
672 f
.write("[%s]\n" % name
)
673 f
.write("\tpath = %s\n" % path
)
674 f
.write("\tread only = no\n")
678 # reload the smb.conf
681 # and dump it without any values that are the default
682 # this ensures that any smb.conf parameters that were set
683 # on the provision/join command line are set in the resulting smb.conf
684 f
= open(smbconf
, mode
='w')
691 def setup_name_mappings(idmap
, sid
, root_uid
, nobody_uid
,
692 users_gid
, wheel_gid
):
693 """setup reasonable name mappings for sam names to unix names.
695 :param samdb: SamDB object.
696 :param idmap: IDmap db object.
697 :param sid: The domain sid.
698 :param domaindn: The domain DN.
699 :param root_uid: uid of the UNIX root user.
700 :param nobody_uid: uid of the UNIX nobody user.
701 :param users_gid: gid of the UNIX users group.
702 :param wheel_gid: gid of the UNIX wheel group.
704 idmap
.setup_name_mapping("S-1-5-7", idmap
.TYPE_UID
, nobody_uid
)
705 idmap
.setup_name_mapping("S-1-5-32-544", idmap
.TYPE_GID
, wheel_gid
)
707 idmap
.setup_name_mapping(sid
+ "-500", idmap
.TYPE_UID
, root_uid
)
708 idmap
.setup_name_mapping(sid
+ "-513", idmap
.TYPE_GID
, users_gid
)
711 def setup_samdb_partitions(samdb_path
, logger
, lp
, session_info
,
712 provision_backend
, names
, schema
, serverrole
,
714 """Setup the partitions for the SAM database.
716 Alternatively, provision() may call this, and then populate the database.
718 :note: This will wipe the Sam Database!
720 :note: This function always removes the local SAM LDB file. The erase
721 parameter controls whether to erase the existing data, which
722 may not be stored locally but in LDAP.
725 assert session_info
is not None
727 # We use options=["modules:"] to stop the modules loading - we
728 # just want to wipe and re-initialise the database, not start it up
731 os
.unlink(samdb_path
)
735 samdb
= Ldb(url
=samdb_path
, session_info
=session_info
,
736 lp
=lp
, options
=["modules:"])
738 ldap_backend_line
= "# No LDAP backend"
739 if provision_backend
.type != "ldb":
740 ldap_backend_line
= "ldapBackend: %s" % provision_backend
.ldap_uri
742 samdb
.transaction_start()
744 logger
.info("Setting up sam.ldb partitions and settings")
745 setup_add_ldif(samdb
, setup_path("provision_partitions.ldif"), {
746 "LDAP_BACKEND_LINE": ldap_backend_line
750 setup_add_ldif(samdb
, setup_path("provision_init.ldif"), {
751 "BACKEND_TYPE": provision_backend
.type,
752 "SERVER_ROLE": serverrole
755 logger
.info("Setting up sam.ldb rootDSE")
756 setup_samdb_rootdse(samdb
, names
)
758 samdb
.transaction_cancel()
761 samdb
.transaction_commit()
764 def secretsdb_self_join(secretsdb
, domain
,
765 netbiosname
, machinepass
, domainsid
=None,
766 realm
=None, dnsdomain
=None,
768 key_version_number
=1,
769 secure_channel_type
=SEC_CHAN_WKSTA
):
770 """Add domain join-specific bits to a secrets database.
772 :param secretsdb: Ldb Handle to the secrets database
773 :param machinepass: Machine password
775 attrs
= ["whenChanged",
782 if realm
is not None:
783 if dnsdomain
is None:
784 dnsdomain
= realm
.lower()
785 dnsname
= '%s.%s' % (netbiosname
.lower(), dnsdomain
.lower())
788 shortname
= netbiosname
.lower()
790 # We don't need to set msg["flatname"] here, because rdn_name will handle
791 # it, and it causes problems for modifies anyway
792 msg
= ldb
.Message(ldb
.Dn(secretsdb
, "flatname=%s,cn=Primary Domains" % domain
))
793 msg
["secureChannelType"] = [str(secure_channel_type
)]
794 msg
["objectClass"] = ["top", "primaryDomain"]
795 if dnsname
is not None:
796 msg
["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
797 msg
["realm"] = [realm
]
798 msg
["saltPrincipal"] = ["host/%s@%s" % (dnsname
, realm
.upper())]
799 msg
["msDS-KeyVersionNumber"] = [str(key_version_number
)]
800 msg
["privateKeytab"] = ["secrets.keytab"]
802 msg
["secret"] = [machinepass
]
803 msg
["samAccountName"] = ["%s$" % netbiosname
]
804 msg
["secureChannelType"] = [str(secure_channel_type
)]
805 if domainsid
is not None:
806 msg
["objectSid"] = [ndr_pack(domainsid
)]
808 # This complex expression tries to ensure that we don't have more
809 # than one record for this SID, realm or netbios domain at a time,
810 # but we don't delete the old record that we are about to modify,
811 # because that would delete the keytab and previous password.
812 res
= secretsdb
.search(base
="cn=Primary Domains", attrs
=attrs
,
813 expression
=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(distinguishedName=%s)))" % (domain
, realm
, str(domainsid
), str(msg
.dn
))),
814 scope
=ldb
.SCOPE_ONELEVEL
)
817 secretsdb
.delete(del_msg
.dn
)
819 res
= secretsdb
.search(base
=msg
.dn
, attrs
=attrs
, scope
=ldb
.SCOPE_BASE
)
822 msg
["priorSecret"] = [res
[0]["secret"][0]]
823 msg
["priorWhenChanged"] = [res
[0]["whenChanged"][0]]
826 msg
["privateKeytab"] = [res
[0]["privateKeytab"][0]]
831 msg
["krb5Keytab"] = [res
[0]["krb5Keytab"][0]]
837 msg
[el
].set_flags(ldb
.FLAG_MOD_REPLACE
)
838 secretsdb
.modify(msg
)
839 secretsdb
.rename(res
[0].dn
, msg
.dn
)
841 spn
= [ 'HOST/%s' % shortname
]
842 if secure_channel_type
== SEC_CHAN_BDC
and dnsname
is not None:
843 # we are a domain controller then we add servicePrincipalName
844 # entries for the keytab code to update.
845 spn
.extend([ 'HOST/%s' % dnsname
])
846 msg
["servicePrincipalName"] = spn
851 def setup_secretsdb(paths
, session_info
, backend_credentials
, lp
):
852 """Setup the secrets database.
854 :note: This function does not handle exceptions and transaction on purpose,
855 it's up to the caller to do this job.
857 :param path: Path to the secrets database.
858 :param session_info: Session info.
859 :param credentials: Credentials
860 :param lp: Loadparm context
861 :return: LDB handle for the created secrets database
863 if os
.path
.exists(paths
.secrets
):
864 os
.unlink(paths
.secrets
)
866 keytab_path
= os
.path
.join(paths
.private_dir
, paths
.keytab
)
867 if os
.path
.exists(keytab_path
):
868 os
.unlink(keytab_path
)
870 dns_keytab_path
= os
.path
.join(paths
.private_dir
, paths
.dns_keytab
)
871 if os
.path
.exists(dns_keytab_path
):
872 os
.unlink(dns_keytab_path
)
876 secrets_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
878 secrets_ldb
.load_ldif_file_add(setup_path("secrets_init.ldif"))
879 secrets_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
880 secrets_ldb
.transaction_start()
882 secrets_ldb
.load_ldif_file_add(setup_path("secrets.ldif"))
884 if (backend_credentials
is not None and
885 backend_credentials
.authentication_requested()):
886 if backend_credentials
.get_bind_dn() is not None:
887 setup_add_ldif(secrets_ldb
,
888 setup_path("secrets_simple_ldap.ldif"), {
889 "LDAPMANAGERDN": backend_credentials
.get_bind_dn(),
890 "LDAPMANAGERPASS_B64": b64encode(backend_credentials
.get_password())
893 setup_add_ldif(secrets_ldb
,
894 setup_path("secrets_sasl_ldap.ldif"), {
895 "LDAPADMINUSER": backend_credentials
.get_username(),
896 "LDAPADMINREALM": backend_credentials
.get_realm(),
897 "LDAPADMINPASS_B64": b64encode(backend_credentials
.get_password())
900 secrets_ldb
.transaction_cancel()
905 def setup_privileges(path
, session_info
, lp
):
906 """Setup the privileges database.
908 :param path: Path to the privileges database.
909 :param session_info: Session info.
910 :param credentials: Credentials
911 :param lp: Loadparm context
912 :return: LDB handle for the created secrets database
914 if os
.path
.exists(path
):
916 privilege_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
917 privilege_ldb
.erase()
918 privilege_ldb
.load_ldif_file_add(setup_path("provision_privilege.ldif"))
921 def setup_registry(path
, session_info
, lp
):
922 """Setup the registry.
924 :param path: Path to the registry database
925 :param session_info: Session information
926 :param credentials: Credentials
927 :param lp: Loadparm context
929 reg
= samba
.registry
.Registry()
930 hive
= samba
.registry
.open_ldb(path
, session_info
=session_info
, lp_ctx
=lp
)
931 reg
.mount_hive(hive
, samba
.registry
.HKEY_LOCAL_MACHINE
)
932 provision_reg
= setup_path("provision.reg")
933 assert os
.path
.exists(provision_reg
)
934 reg
.diff_apply(provision_reg
)
937 def setup_idmapdb(path
, session_info
, lp
):
938 """Setup the idmap database.
940 :param path: path to the idmap database
941 :param session_info: Session information
942 :param credentials: Credentials
943 :param lp: Loadparm context
945 if os
.path
.exists(path
):
948 idmap_ldb
= IDmapDB(path
, session_info
=session_info
, lp
=lp
)
950 idmap_ldb
.load_ldif_file_add(setup_path("idmap_init.ldif"))
954 def setup_samdb_rootdse(samdb
, names
):
955 """Setup the SamDB rootdse.
957 :param samdb: Sam Database handle
959 setup_add_ldif(samdb
, setup_path("provision_rootdse_add.ldif"), {
960 "SCHEMADN": names
.schemadn
,
961 "DOMAINDN": names
.domaindn
,
962 "ROOTDN" : names
.rootdn
,
963 "CONFIGDN": names
.configdn
,
964 "SERVERDN": names
.serverdn
,
968 def setup_self_join(samdb
, admin_session_info
, names
, fill
, machinepass
,
969 dnspass
, domainsid
, next_rid
, invocationid
, policyguid
, policyguid_dc
,
970 domainControllerFunctionality
, ntdsguid
=None, dc_rid
=None):
971 """Join a host to its own domain."""
972 assert isinstance(invocationid
, str)
973 if ntdsguid
is not None:
974 ntdsguid_line
= "objectGUID: %s\n"%ntdsguid
981 setup_add_ldif(samdb
, setup_path("provision_self_join.ldif"), {
982 "CONFIGDN": names
.configdn
,
983 "SCHEMADN": names
.schemadn
,
984 "DOMAINDN": names
.domaindn
,
985 "SERVERDN": names
.serverdn
,
986 "INVOCATIONID": invocationid
,
987 "NETBIOSNAME": names
.netbiosname
,
988 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
989 "MACHINEPASS_B64": b64encode(machinepass
.encode('utf-16-le')),
990 "DOMAINSID": str(domainsid
),
991 "DCRID": str(dc_rid
),
992 "SAMBA_VERSION_STRING": version
,
993 "NTDSGUID": ntdsguid_line
,
994 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
995 domainControllerFunctionality
),
996 "RIDALLOCATIONSTART": str(next_rid
+ 100),
997 "RIDALLOCATIONEND": str(next_rid
+ 100 + 499)})
999 setup_add_ldif(samdb
, setup_path("provision_group_policy.ldif"), {
1000 "POLICYGUID": policyguid
,
1001 "POLICYGUID_DC": policyguid_dc
,
1002 "DNSDOMAIN": names
.dnsdomain
,
1003 "DOMAINDN": names
.domaindn
})
1005 # If we are setting up a subdomain, then this has been replicated in, so we
1006 # don't need to add it
1007 if fill
== FILL_FULL
:
1008 setup_add_ldif(samdb
, setup_path("provision_self_join_config.ldif"), {
1009 "CONFIGDN": names
.configdn
,
1010 "SCHEMADN": names
.schemadn
,
1011 "DOMAINDN": names
.domaindn
,
1012 "SERVERDN": names
.serverdn
,
1013 "INVOCATIONID": invocationid
,
1014 "NETBIOSNAME": names
.netbiosname
,
1015 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
1016 "MACHINEPASS_B64": b64encode(machinepass
.encode('utf-16-le')),
1017 "DOMAINSID": str(domainsid
),
1018 "DCRID": str(dc_rid
),
1019 "SAMBA_VERSION_STRING": version
,
1020 "NTDSGUID": ntdsguid_line
,
1021 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
1022 domainControllerFunctionality
)})
1024 # Setup fSMORoleOwner entries to point at the newly created DC entry
1025 setup_modify_ldif(samdb
,
1026 setup_path("provision_self_join_modify_config.ldif"), {
1027 "CONFIGDN": names
.configdn
,
1028 "SCHEMADN": names
.schemadn
,
1029 "DEFAULTSITE": names
.sitename
,
1030 "NETBIOSNAME": names
.netbiosname
,
1031 "SERVERDN": names
.serverdn
,
1034 system_session_info
= system_session()
1035 samdb
.set_session_info(system_session_info
)
1036 # Setup fSMORoleOwner entries to point at the newly created DC entry to
1037 # modify a serverReference under cn=config when we are a subdomain, we must
1038 # be system due to ACLs
1039 setup_modify_ldif(samdb
, setup_path("provision_self_join_modify.ldif"), {
1040 "DOMAINDN": names
.domaindn
,
1041 "SERVERDN": names
.serverdn
,
1042 "NETBIOSNAME": names
.netbiosname
,
1045 samdb
.set_session_info(admin_session_info
)
1047 # This is Samba4 specific and should be replaced by the correct
1048 # DNS AD-style setup
1049 setup_add_ldif(samdb
, setup_path("provision_dns_add_samba.ldif"), {
1050 "DNSDOMAIN": names
.dnsdomain
,
1051 "DOMAINDN": names
.domaindn
,
1052 "DNSPASS_B64": b64encode(dnspass
.encode('utf-16-le')),
1053 "HOSTNAME" : names
.hostname
,
1054 "DNSNAME" : '%s.%s' % (
1055 names
.netbiosname
.lower(), names
.dnsdomain
.lower())
1059 def getpolicypath(sysvolpath
, dnsdomain
, guid
):
1060 """Return the physical path of policy given its guid.
1062 :param sysvolpath: Path to the sysvol folder
1063 :param dnsdomain: DNS name of the AD domain
1064 :param guid: The GUID of the policy
1065 :return: A string with the complete path to the policy folder
1068 guid
= "{%s}" % guid
1069 policy_path
= os
.path
.join(sysvolpath
, dnsdomain
, "Policies", guid
)
1073 def create_gpo_struct(policy_path
):
1074 if not os
.path
.exists(policy_path
):
1075 os
.makedirs(policy_path
, 0775)
1076 f
= open(os
.path
.join(policy_path
, "GPT.INI"), 'w')
1078 f
.write("[General]\r\nVersion=0")
1081 p
= os
.path
.join(policy_path
, "MACHINE")
1082 if not os
.path
.exists(p
):
1083 os
.makedirs(p
, 0775)
1084 p
= os
.path
.join(policy_path
, "USER")
1085 if not os
.path
.exists(p
):
1086 os
.makedirs(p
, 0775)
1089 def create_default_gpo(sysvolpath
, dnsdomain
, policyguid
, policyguid_dc
):
1090 """Create the default GPO for a domain
1092 :param sysvolpath: Physical path for the sysvol folder
1093 :param dnsdomain: DNS domain name of the AD domain
1094 :param policyguid: GUID of the default domain policy
1095 :param policyguid_dc: GUID of the default domain controler policy
1097 policy_path
= getpolicypath(sysvolpath
,dnsdomain
,policyguid
)
1098 create_gpo_struct(policy_path
)
1100 policy_path
= getpolicypath(sysvolpath
,dnsdomain
,policyguid_dc
)
1101 create_gpo_struct(policy_path
)
1104 def setup_samdb(path
, session_info
, provision_backend
, lp
, names
,
1105 logger
, fill
, serverrole
, schema
, am_rodc
=False):
1106 """Setup a complete SAM Database.
1108 :note: This will wipe the main SAM database file!
1111 # Also wipes the database
1112 setup_samdb_partitions(path
, logger
=logger
, lp
=lp
,
1113 provision_backend
=provision_backend
, session_info
=session_info
,
1114 names
=names
, serverrole
=serverrole
, schema
=schema
)
1116 # Load the database, but don's load the global schema and don't connect
1118 samdb
= SamDB(session_info
=session_info
, url
=None, auto_connect
=False,
1119 credentials
=provision_backend
.credentials
, lp
=lp
,
1120 global_schema
=False, am_rodc
=am_rodc
)
1122 logger
.info("Pre-loading the Samba 4 and AD schema")
1124 # Load the schema from the one we computed earlier
1125 samdb
.set_schema(schema
, write_indices_and_attributes
=False)
1127 # Set the NTDS settings DN manually - in order to have it already around
1128 # before the provisioned tree exists and we connect
1129 samdb
.set_ntds_settings_dn("CN=NTDS Settings,%s" % names
.serverdn
)
1131 # And now we can connect to the DB - the schema won't be loaded from the
1135 # But we have to give it one more kick to have it use the schema
1136 # during provision - it needs, now that it is connected, to write
1137 # the schema @ATTRIBUTES and @INDEXLIST records to the database.
1138 samdb
.set_schema(schema
, write_indices_and_attributes
=True)
1143 def fill_samdb(samdb
, lp
, names
,
1144 logger
, domainsid
, domainguid
, policyguid
, policyguid_dc
, fill
,
1145 adminpass
, krbtgtpass
, machinepass
, invocationid
, dnspass
, ntdsguid
,
1146 serverrole
, am_rodc
=False, dom_for_fun_level
=None, schema
=None,
1147 next_rid
=None, dc_rid
=None):
1149 if next_rid
is None:
1152 # Provision does not make much sense values larger than 1000000000
1153 # as the upper range of the rIDAvailablePool is 1073741823 and
1154 # we don't want to create a domain that cannot allocate rids.
1155 if next_rid
< 1000 or next_rid
> 1000000000:
1156 error
= "You want to run SAMBA 4 with a next_rid of %u, " % (next_rid
)
1157 error
+= "the valid range is %u-%u. The default is %u." % (
1158 1000, 1000000000, 1000)
1159 raise ProvisioningError(error
)
1161 # ATTENTION: Do NOT change these default values without discussion with the
1162 # team and/or release manager. They have a big impact on the whole program!
1163 domainControllerFunctionality
= DS_DOMAIN_FUNCTION_2008_R2
1165 if dom_for_fun_level
is None:
1166 dom_for_fun_level
= DS_DOMAIN_FUNCTION_2003
1168 if dom_for_fun_level
> domainControllerFunctionality
:
1169 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!")
1171 domainFunctionality
= dom_for_fun_level
1172 forestFunctionality
= dom_for_fun_level
1174 # Set the NTDS settings DN manually - in order to have it already around
1175 # before the provisioned tree exists and we connect
1176 samdb
.set_ntds_settings_dn("CN=NTDS Settings,%s" % names
.serverdn
)
1178 samdb
.transaction_start()
1180 # Set the domain functionality levels onto the database.
1181 # Various module (the password_hash module in particular) need
1182 # to know what level of AD we are emulating.
1184 # These will be fixed into the database via the database
1185 # modifictions below, but we need them set from the start.
1186 samdb
.set_opaque_integer("domainFunctionality", domainFunctionality
)
1187 samdb
.set_opaque_integer("forestFunctionality", forestFunctionality
)
1188 samdb
.set_opaque_integer("domainControllerFunctionality",
1189 domainControllerFunctionality
)
1191 samdb
.set_domain_sid(str(domainsid
))
1192 samdb
.set_invocation_id(invocationid
)
1194 logger
.info("Adding DomainDN: %s" % names
.domaindn
)
1196 # impersonate domain admin
1197 admin_session_info
= admin_session(lp
, str(domainsid
))
1198 samdb
.set_session_info(admin_session_info
)
1199 if domainguid
is not None:
1200 domainguid_line
= "objectGUID: %s\n-" % domainguid
1202 domainguid_line
= ""
1204 descr
= b64encode(get_domain_descriptor(domainsid
))
1205 setup_add_ldif(samdb
, setup_path("provision_basedn.ldif"), {
1206 "DOMAINDN": names
.domaindn
,
1207 "DOMAINSID": str(domainsid
),
1208 "DESCRIPTOR": descr
,
1209 "DOMAINGUID": domainguid_line
1212 setup_modify_ldif(samdb
, setup_path("provision_basedn_modify.ldif"), {
1213 "DOMAINDN": names
.domaindn
,
1214 "CREATTIME": str(samba
.unix2nttime(int(time
.time()))),
1215 "NEXTRID": str(next_rid
),
1216 "DEFAULTSITE": names
.sitename
,
1217 "CONFIGDN": names
.configdn
,
1218 "POLICYGUID": policyguid
,
1219 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
),
1220 "SAMBA_VERSION_STRING": version
1223 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1224 if fill
== FILL_FULL
:
1225 logger
.info("Adding configuration container")
1226 descr
= b64encode(get_config_descriptor(domainsid
))
1227 setup_add_ldif(samdb
, setup_path("provision_configuration_basedn.ldif"), {
1228 "CONFIGDN": names
.configdn
,
1229 "DESCRIPTOR": descr
,
1232 # The LDIF here was created when the Schema object was constructed
1233 logger
.info("Setting up sam.ldb schema")
1234 samdb
.add_ldif(schema
.schema_dn_add
, controls
=["relax:0"])
1235 samdb
.modify_ldif(schema
.schema_dn_modify
)
1236 samdb
.write_prefixes_from_schema()
1237 samdb
.add_ldif(schema
.schema_data
, controls
=["relax:0"])
1238 setup_add_ldif(samdb
, setup_path("aggregate_schema.ldif"),
1239 {"SCHEMADN": names
.schemadn
})
1241 # Now register this container in the root of the forest
1242 msg
= ldb
.Message(ldb
.Dn(samdb
, names
.domaindn
))
1243 msg
["subRefs"] = ldb
.MessageElement(names
.configdn
, ldb
.FLAG_MOD_ADD
,
1247 samdb
.transaction_cancel()
1250 samdb
.transaction_commit()
1252 samdb
.transaction_start()
1254 samdb
.invocation_id
= invocationid
1256 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1257 if fill
== FILL_FULL
:
1258 logger
.info("Setting up sam.ldb configuration data")
1259 setup_add_ldif(samdb
, setup_path("provision_configuration.ldif"), {
1260 "CONFIGDN": names
.configdn
,
1261 "NETBIOSNAME": names
.netbiosname
,
1262 "DEFAULTSITE": names
.sitename
,
1263 "DNSDOMAIN": names
.dnsdomain
,
1264 "DOMAIN": names
.domain
,
1265 "SCHEMADN": names
.schemadn
,
1266 "DOMAINDN": names
.domaindn
,
1267 "SERVERDN": names
.serverdn
,
1268 "FOREST_FUNCTIONALITY": str(forestFunctionality
),
1269 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
),
1272 logger
.info("Setting up display specifiers")
1273 display_specifiers_ldif
= read_ms_ldif(
1274 setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1275 display_specifiers_ldif
= substitute_var(display_specifiers_ldif
,
1276 {"CONFIGDN": names
.configdn
})
1277 check_all_substituted(display_specifiers_ldif
)
1278 samdb
.add_ldif(display_specifiers_ldif
)
1280 logger
.info("Adding users container")
1281 setup_add_ldif(samdb
, setup_path("provision_users_add.ldif"), {
1282 "DOMAINDN": names
.domaindn
})
1283 logger
.info("Modifying users container")
1284 setup_modify_ldif(samdb
, setup_path("provision_users_modify.ldif"), {
1285 "DOMAINDN": names
.domaindn
})
1286 logger
.info("Adding computers container")
1287 setup_add_ldif(samdb
, setup_path("provision_computers_add.ldif"), {
1288 "DOMAINDN": names
.domaindn
})
1289 logger
.info("Modifying computers container")
1290 setup_modify_ldif(samdb
,
1291 setup_path("provision_computers_modify.ldif"), {
1292 "DOMAINDN": names
.domaindn
})
1293 logger
.info("Setting up sam.ldb data")
1294 setup_add_ldif(samdb
, setup_path("provision.ldif"), {
1295 "CREATTIME": str(samba
.unix2nttime(int(time
.time()))),
1296 "DOMAINDN": names
.domaindn
,
1297 "NETBIOSNAME": names
.netbiosname
,
1298 "DEFAULTSITE": names
.sitename
,
1299 "CONFIGDN": names
.configdn
,
1300 "SERVERDN": names
.serverdn
,
1301 "RIDAVAILABLESTART": str(next_rid
+ 600),
1302 "POLICYGUID_DC": policyguid_dc
1305 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1306 if fill
== FILL_FULL
:
1307 setup_modify_ldif(samdb
,
1308 setup_path("provision_configuration_references.ldif"), {
1309 "CONFIGDN": names
.configdn
,
1310 "SCHEMADN": names
.schemadn
})
1312 logger
.info("Setting up well known security principals")
1313 setup_add_ldif(samdb
, setup_path("provision_well_known_sec_princ.ldif"), {
1314 "CONFIGDN": names
.configdn
,
1317 if fill
== FILL_FULL
or fill
== FILL_SUBDOMAIN
:
1318 setup_modify_ldif(samdb
,
1319 setup_path("provision_basedn_references.ldif"),
1320 {"DOMAINDN": names
.domaindn
})
1322 logger
.info("Setting up sam.ldb users and groups")
1323 setup_add_ldif(samdb
, setup_path("provision_users.ldif"), {
1324 "DOMAINDN": names
.domaindn
,
1325 "DOMAINSID": str(domainsid
),
1326 "ADMINPASS_B64": b64encode(adminpass
.encode('utf-16-le')),
1327 "KRBTGTPASS_B64": b64encode(krbtgtpass
.encode('utf-16-le'))
1330 logger
.info("Setting up self join")
1331 setup_self_join(samdb
, admin_session_info
, names
=names
, fill
=fill
,
1332 invocationid
=invocationid
,
1334 machinepass
=machinepass
,
1335 domainsid
=domainsid
,
1338 policyguid
=policyguid
,
1339 policyguid_dc
=policyguid_dc
,
1340 domainControllerFunctionality
=domainControllerFunctionality
,
1343 ntds_dn
= "CN=NTDS Settings,%s" % names
.serverdn
1344 names
.ntdsguid
= samdb
.searchone(basedn
=ntds_dn
,
1345 attribute
="objectGUID", expression
="", scope
=ldb
.SCOPE_BASE
)
1346 assert isinstance(names
.ntdsguid
, str)
1348 samdb
.transaction_cancel()
1351 samdb
.transaction_commit()
1356 FILL_SUBDOMAIN
= "SUBDOMAIN"
1357 FILL_NT4SYNC
= "NT4SYNC"
1359 SYSVOL_ACL
= "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
1360 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)"
1363 def set_dir_acl(path
, acl
, lp
, domsid
, use_ntvfs
):
1364 setntacl(lp
, path
, acl
, domsid
, use_ntvfs
=use_ntvfs
)
1365 for root
, dirs
, files
in os
.walk(path
, topdown
=False):
1367 setntacl(lp
, os
.path
.join(root
, name
), acl
, domsid
, use_ntvfs
=use_ntvfs
)
1369 setntacl(lp
, os
.path
.join(root
, name
), acl
, domsid
, use_ntvfs
=use_ntvfs
)
1372 def set_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
, use_ntvfs
):
1373 """Set ACL on the sysvol/<dnsname>/Policies folder and the policy
1376 :param sysvol: Physical path for the sysvol folder
1377 :param dnsdomain: The DNS name of the domain
1378 :param domainsid: The SID of the domain
1379 :param domaindn: The DN of the domain (ie. DC=...)
1380 :param samdb: An LDB object on the SAM db
1381 :param lp: an LP object
1384 # Set ACL for GPO root folder
1385 root_policy_path
= os
.path
.join(sysvol
, dnsdomain
, "Policies")
1386 setntacl(lp
, root_policy_path
, POLICIES_ACL
, str(domainsid
), use_ntvfs
=use_ntvfs
)
1388 res
= samdb
.search(base
="CN=Policies,CN=System,%s"%(domaindn),
1389 attrs
=["cn", "nTSecurityDescriptor"],
1390 expression
="", scope
=ldb
.SCOPE_ONELEVEL
)
1393 acl
= ndr_unpack(security
.descriptor
,
1394 str(policy
["nTSecurityDescriptor"])).as_sddl()
1395 policy_path
= getpolicypath(sysvol
, dnsdomain
, str(policy
["cn"]))
1396 set_dir_acl(policy_path
, dsacl2fsacl(acl
, str(domainsid
)), lp
,
1397 str(domainsid
), use_ntvfs
)
1400 def setsysvolacl(samdb
, netlogon
, sysvol
, uid
, gid
, domainsid
, dnsdomain
, domaindn
,
1402 """Set the ACL for the sysvol share and the subfolders
1404 :param samdb: An LDB object on the SAM db
1405 :param netlogon: Physical path for the netlogon folder
1406 :param sysvol: Physical path for the sysvol folder
1407 :param gid: The GID of the "Domain adminstrators" group
1408 :param domainsid: The SID of the domain
1409 :param dnsdomain: The DNS name of the domain
1410 :param domaindn: The DN of the domain (ie. DC=...)
1414 # This will ensure that the smbd code we are running when setting ACLs is initialised with the smb.conf
1415 s3conf
= s3param
.get_context()
1416 s3conf
.load(lp
.configfile
)
1417 # ensure we are using the right samba4 passdb backend, no matter what
1418 s3conf
.set("passdb backend", "samba4:%s" % samdb
.url
)
1419 # ensure that we init the samba4 backend, so the domain sid is marked in secrets.tdb
1420 s4_passdb
= passdb
.PDB(s3conf
.get("passdb backend"))
1422 # now ensure everything matches correctly, to avoid wierd issues
1423 if passdb
.get_global_sam_sid() != domainsid
:
1424 raise ProvisioningError('SID as seen by smbd [%s] does not match SID as seen by the provision script [%s]!' % (passdb
.get_global_sam_sid(), domainsid
))
1426 domain_info
= s4_passdb
.domain_info()
1427 if domain_info
["dom_sid"] != domainsid
:
1428 raise ProvisioningError('SID as seen by pdb_samba4 [%s] does not match SID as seen by the provision script [%s]!' % (domain_info
["dom_sid"], domainsid
))
1430 if domain_info
["dns_domain"].upper() != dnsdomain
.upper():
1431 raise ProvisioningError('Realm as seen by pdb_samba4 [%s] does not match Realm as seen by the provision script [%s]!' % (domain_info
["dns_domain"].upper(), dnsdomain
.upper()))
1436 os
.chown(sysvol
, -1, gid
)
1442 # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
1443 setntacl(lp
,sysvol
, SYSVOL_ACL
, str(domainsid
), use_ntvfs
=use_ntvfs
)
1444 for root
, dirs
, files
in os
.walk(sysvol
, topdown
=False):
1446 if use_ntvfs
and canchown
:
1447 os
.chown(os
.path
.join(root
, name
), -1, gid
)
1448 setntacl(lp
, os
.path
.join(root
, name
), SYSVOL_ACL
, str(domainsid
), use_ntvfs
=use_ntvfs
)
1450 if use_ntvfs
and canchown
:
1451 os
.chown(os
.path
.join(root
, name
), -1, gid
)
1452 setntacl(lp
, os
.path
.join(root
, name
), SYSVOL_ACL
, str(domainsid
), use_ntvfs
=use_ntvfs
)
1454 # Set acls on Policy folder and policies folders
1455 set_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
, use_ntvfs
)
1458 def interface_ips_v4(lp
):
1459 '''return only IPv4 IPs'''
1460 ips
= samba
.interface_ips(lp
, False)
1463 if i
.find(':') == -1:
1467 def interface_ips_v6(lp
, linklocal
=False):
1468 '''return only IPv6 IPs'''
1469 ips
= samba
.interface_ips(lp
, False)
1472 if i
.find(':') != -1 and (linklocal
or i
.find('%') == -1):
1477 def provision_fill(samdb
, secrets_ldb
, logger
, names
, paths
,
1478 domainsid
, schema
=None,
1479 targetdir
=None, samdb_fill
=FILL_FULL
,
1480 hostip
=None, hostip6
=None,
1481 next_rid
=1000, dc_rid
=None, adminpass
=None, krbtgtpass
=None,
1482 domainguid
=None, policyguid
=None, policyguid_dc
=None,
1483 invocationid
=None, machinepass
=None, ntdsguid
=None,
1484 dns_backend
=None, dnspass
=None,
1485 serverrole
=None, dom_for_fun_level
=None,
1486 am_rodc
=False, lp
=None, use_ntvfs
=False):
1487 # create/adapt the group policy GUIDs
1488 # Default GUID for default policy are described at
1489 # "How Core Group Policy Works"
1490 # http://technet.microsoft.com/en-us/library/cc784268%28WS.10%29.aspx
1491 if policyguid
is None:
1492 policyguid
= DEFAULT_POLICY_GUID
1493 policyguid
= policyguid
.upper()
1494 if policyguid_dc
is None:
1495 policyguid_dc
= DEFAULT_DC_POLICY_GUID
1496 policyguid_dc
= policyguid_dc
.upper()
1498 if invocationid
is None:
1499 invocationid
= str(uuid
.uuid4())
1501 if krbtgtpass
is None:
1502 krbtgtpass
= samba
.generate_random_password(128, 255)
1503 if machinepass
is None:
1504 machinepass
= samba
.generate_random_password(128, 255)
1506 dnspass
= samba
.generate_random_password(128, 255)
1508 samdb
= fill_samdb(samdb
, lp
, names
, logger
=logger
,
1509 domainsid
=domainsid
, schema
=schema
, domainguid
=domainguid
,
1510 policyguid
=policyguid
, policyguid_dc
=policyguid_dc
,
1511 fill
=samdb_fill
, adminpass
=adminpass
, krbtgtpass
=krbtgtpass
,
1512 invocationid
=invocationid
, machinepass
=machinepass
,
1513 dnspass
=dnspass
, ntdsguid
=ntdsguid
, serverrole
=serverrole
,
1514 dom_for_fun_level
=dom_for_fun_level
, am_rodc
=am_rodc
,
1515 next_rid
=next_rid
, dc_rid
=dc_rid
)
1517 if serverrole
== "active directory domain controller":
1519 # Set up group policies (domain policy and domain controller
1521 create_default_gpo(paths
.sysvol
, names
.dnsdomain
, policyguid
,
1523 setsysvolacl(samdb
, paths
.netlogon
, paths
.sysvol
, paths
.root_uid
, paths
.wheel_gid
,
1524 domainsid
, names
.dnsdomain
, names
.domaindn
, lp
, use_ntvfs
)
1526 secretsdb_self_join(secrets_ldb
, domain
=names
.domain
,
1527 realm
=names
.realm
, dnsdomain
=names
.dnsdomain
,
1528 netbiosname
=names
.netbiosname
, domainsid
=domainsid
,
1529 machinepass
=machinepass
, secure_channel_type
=SEC_CHAN_BDC
)
1531 # Now set up the right msDS-SupportedEncryptionTypes into the DB
1532 # In future, this might be determined from some configuration
1533 kerberos_enctypes
= str(ENC_ALL_TYPES
)
1536 msg
= ldb
.Message(ldb
.Dn(samdb
,
1537 samdb
.searchone("distinguishedName",
1538 expression
="samAccountName=%s$" % names
.netbiosname
,
1539 scope
=ldb
.SCOPE_SUBTREE
)))
1540 msg
["msDS-SupportedEncryptionTypes"] = ldb
.MessageElement(
1541 elements
=kerberos_enctypes
, flags
=ldb
.FLAG_MOD_REPLACE
,
1542 name
="msDS-SupportedEncryptionTypes")
1544 except ldb
.LdbError
, (enum
, estr
):
1545 if enum
!= ldb
.ERR_NO_SUCH_ATTRIBUTE
:
1546 # It might be that this attribute does not exist in this schema
1549 setup_ad_dns(samdb
, secrets_ldb
, domainsid
, names
, paths
, lp
, logger
,
1550 hostip
=hostip
, hostip6
=hostip6
, dns_backend
=dns_backend
,
1551 dnspass
=dnspass
, os_level
=dom_for_fun_level
,
1552 targetdir
=targetdir
, site
=DEFAULTSITE
)
1554 domainguid
= samdb
.searchone(basedn
=samdb
.get_default_basedn(),
1555 attribute
="objectGUID")
1556 assert isinstance(domainguid
, str)
1558 lastProvisionUSNs
= get_last_provision_usn(samdb
)
1559 maxUSN
= get_max_usn(samdb
, str(names
.rootdn
))
1560 if lastProvisionUSNs
is not None:
1561 update_provision_usn(samdb
, 0, maxUSN
, invocationid
, 1)
1563 set_provision_usn(samdb
, 0, maxUSN
, invocationid
)
1565 logger
.info("Setting up sam.ldb rootDSE marking as synchronized")
1566 setup_modify_ldif(samdb
, setup_path("provision_rootdse_modify.ldif"),
1567 { 'NTDSGUID' : names
.ntdsguid
})
1569 # fix any dangling GUIDs from the provision
1570 logger
.info("Fixing provision GUIDs")
1571 chk
= dbcheck(samdb
, samdb_schema
=samdb
, verbose
=False, fix
=True, yes
=True,
1573 samdb
.transaction_start()
1575 # a small number of GUIDs are missing because of ordering issues in the
1577 for schema_obj
in ['CN=Domain', 'CN=Organizational-Person', 'CN=Contact', 'CN=inetOrgPerson']:
1578 chk
.check_database(DN
="%s,%s" % (schema_obj
, names
.schemadn
),
1579 scope
=ldb
.SCOPE_BASE
, attrs
=['defaultObjectCategory'])
1580 chk
.check_database(DN
="CN=IP Security,CN=System,%s" % names
.domaindn
,
1581 scope
=ldb
.SCOPE_ONELEVEL
,
1582 attrs
=['ipsecOwnersReference',
1583 'ipsecFilterReference',
1584 'ipsecISAKMPReference',
1585 'ipsecNegotiationPolicyReference',
1586 'ipsecNFAReference'])
1588 samdb
.transaction_cancel()
1591 samdb
.transaction_commit()
1595 "ROLE_STANDALONE": "standalone server",
1596 "ROLE_DOMAIN_MEMBER": "member server",
1597 "ROLE_DOMAIN_BDC": "active directory domain controller",
1598 "ROLE_DOMAIN_PDC": "active directory domain controller",
1599 "dc": "active directory domain controller",
1600 "member": "member server",
1601 "domain controller": "active directory domain controller",
1602 "active directory domain controller": "active directory domain controller",
1603 "member server": "member server",
1604 "standalone": "standalone server",
1605 "standalone server": "standalone server",
1609 def sanitize_server_role(role
):
1610 """Sanitize a server role name.
1612 :param role: Server role
1613 :raise ValueError: If the role can not be interpreted
1614 :return: Sanitized server role (one of "member server",
1615 "active directory domain controller", "standalone server")
1618 return _ROLES_MAP
[role
]
1620 raise ValueError(role
)
1622 def provision_fake_ypserver(logger
, samdb
, domaindn
, netbiosname
, nisdomain
, maxuid
, maxgid
):
1623 """Creates AD entries for the fake ypserver
1624 needed for being able to manipulate posix attrs via ADUC
1626 samdb
.transaction_start()
1628 logger
.info("Setting up fake yp server settings")
1629 setup_add_ldif(samdb
, setup_path("ypServ30.ldif"), {
1630 "DOMAINDN": domaindn
,
1631 "NETBIOSNAME": netbiosname
,
1632 "NISDOMAIN": nisdomain
,
1635 samdb
.transaction_cancel()
1638 samdb
.transaction_commit()
1644 def provision(logger
, session_info
, credentials
, smbconf
=None,
1645 targetdir
=None, samdb_fill
=FILL_FULL
, realm
=None, rootdn
=None,
1646 domaindn
=None, schemadn
=None, configdn
=None, serverdn
=None,
1647 domain
=None, hostname
=None, hostip
=None, hostip6
=None, domainsid
=None,
1648 next_rid
=1000, dc_rid
=None, adminpass
=None, ldapadminpass
=None, krbtgtpass
=None,
1649 domainguid
=None, policyguid
=None, policyguid_dc
=None,
1650 dns_backend
=None, dnspass
=None,
1651 invocationid
=None, machinepass
=None, ntdsguid
=None,
1652 root
=None, nobody
=None, users
=None, wheel
=None, backup
=None, aci
=None,
1653 serverrole
=None, dom_for_fun_level
=None,
1654 backend_type
=None, sitename
=None,
1655 ol_mmr_urls
=None, ol_olc
=None, slapd_path
="/bin/false",
1656 useeadb
=False, am_rodc
=False,
1657 lp
=None, use_ntvfs
=False,
1658 use_rfc2307
=False, maxuid
=None, maxgid
=None):
1661 :note: caution, this wipes all existing data!
1665 serverrole
= sanitize_server_role(serverrole
)
1667 raise ProvisioningError('server role (%s) should be one of "active directory domain controller", "member server", "standalone server"' % serverrole
)
1669 if ldapadminpass
is None:
1670 # Make a new, random password between Samba and it's LDAP server
1671 ldapadminpass
= samba
.generate_random_password(128, 255)
1673 if backend_type
is None:
1674 backend_type
= "ldb"
1676 if domainsid
is None:
1677 domainsid
= security
.random_sid()
1679 domainsid
= security
.dom_sid(domainsid
)
1681 root_uid
= findnss_uid([root
or "root"])
1682 nobody_uid
= findnss_uid([nobody
or "nobody"])
1683 users_gid
= findnss_gid([users
or "users", 'users', 'other', 'staff'])
1685 wheel_gid
= findnss_gid(["wheel", "adm"])
1687 wheel_gid
= findnss_gid([wheel
])
1689 bind_gid
= findnss_gid(["bind", "named"])
1693 if targetdir
is not None:
1694 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
1695 elif smbconf
is None:
1696 smbconf
= samba
.param
.default_path()
1697 if not os
.path
.exists(os
.path
.dirname(smbconf
)):
1698 os
.makedirs(os
.path
.dirname(smbconf
))
1700 server_services
= []
1703 global_param
["idmap_ldb:use rfc2307"] = ["yes"]
1705 if dns_backend
== "SAMBA_INTERNAL":
1706 server_services
.append("+dns")
1709 server_services
.append("+smb")
1710 server_services
.append("-s3fs")
1711 global_param
["dcerpc endpoint servers"] = ["+winreg", "+srvsvc"]
1713 if len(server_services
) > 0:
1714 global_param
["server services"] = server_services
1716 # only install a new smb.conf if there isn't one there already
1717 if os
.path
.exists(smbconf
):
1718 # if Samba Team members can't figure out the weird errors
1719 # loading an empty smb.conf gives, then we need to be smarter.
1720 # Pretend it just didn't exist --abartlet
1721 f
= open(smbconf
, 'r')
1723 data
= f
.read().lstrip()
1726 if data
is None or data
== "":
1727 make_smbconf(smbconf
, hostname
, domain
, realm
,
1728 targetdir
, serverrole
=serverrole
,
1729 eadb
=useeadb
, use_ntvfs
=use_ntvfs
,
1730 lp
=lp
, global_param
=global_param
)
1732 make_smbconf(smbconf
, hostname
, domain
, realm
, targetdir
,
1733 serverrole
=serverrole
,
1734 eadb
=useeadb
, use_ntvfs
=use_ntvfs
, lp
=lp
, global_param
=global_param
)
1737 lp
= samba
.param
.LoadParm()
1739 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
1740 dnsdomain
=realm
, serverrole
=serverrole
, domaindn
=domaindn
,
1741 configdn
=configdn
, schemadn
=schemadn
, serverdn
=serverdn
,
1742 sitename
=sitename
, rootdn
=rootdn
)
1743 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
1745 paths
.bind_gid
= bind_gid
1746 paths
.root_uid
= root_uid
;
1747 paths
.wheel_gid
= wheel_gid
1750 logger
.info("Looking up IPv4 addresses")
1751 hostips
= interface_ips_v4(lp
)
1752 if len(hostips
) > 0:
1754 if len(hostips
) > 1:
1755 logger
.warning("More than one IPv4 address found. Using %s",
1757 if hostip
== "127.0.0.1":
1760 logger
.warning("No IPv4 address will be assigned")
1763 logger
.info("Looking up IPv6 addresses")
1764 hostips
= interface_ips_v6(lp
, linklocal
=False)
1766 hostip6
= hostips
[0]
1767 if len(hostips
) > 1:
1768 logger
.warning("More than one IPv6 address found. Using %s", hostip6
)
1770 logger
.warning("No IPv6 address will be assigned")
1772 names
.hostip
= hostip
1773 names
.hostip6
= hostip6
1775 if serverrole
is None:
1776 serverrole
= lp
.get("server role")
1778 if not os
.path
.exists(paths
.private_dir
):
1779 os
.mkdir(paths
.private_dir
)
1780 if not os
.path
.exists(os
.path
.join(paths
.private_dir
, "tls")):
1781 os
.mkdir(os
.path
.join(paths
.private_dir
, "tls"))
1782 if not os
.path
.exists(paths
.state_dir
):
1783 os
.mkdir(paths
.state_dir
)
1785 if paths
.sysvol
and not os
.path
.exists(paths
.sysvol
):
1786 os
.makedirs(paths
.sysvol
, 0775)
1788 if not use_ntvfs
and serverrole
== "active directory domain controller":
1789 s3conf
= s3param
.get_context()
1790 s3conf
.load(lp
.configfile
)
1792 if paths
.sysvol
is None:
1793 raise MissingShareError("sysvol", paths
.smbconf
)
1795 if not smbd
.have_posix_acls():
1796 # This clue is only strictly correct for RPM and
1797 # Debian-like Linux systems, but hopefully other users
1798 # will get enough clue from it.
1799 raise ProvisioningError("Samba was compiled without the posix ACL support that s3fs requires. Try installing libacl1-dev or libacl-devel, then re-run configure and make.")
1801 file = tempfile
.NamedTemporaryFile(dir=os
.path
.abspath(paths
.sysvol
))
1804 smbd
.set_simple_acl(file.name
, root_uid
, wheel_gid
)
1806 raise ProvisioningError("Your filesystem or build does not support posix ACLs, which s3fs requires. Try the mounting the filesystem with the 'acl' option.")
1808 smbd
.chown(file.name
, root_uid
, wheel_gid
)
1810 raise ProvisioningError("Unable to chown a file on your filesystem. You may not be running provision as root. ")
1814 ldapi_url
= "ldapi://%s" % urllib
.quote(paths
.s4_ldapi_path
, safe
="")
1816 schema
= Schema(domainsid
, invocationid
=invocationid
,
1817 schemadn
=names
.schemadn
)
1819 if backend_type
== "ldb":
1820 provision_backend
= LDBBackend(backend_type
, paths
=paths
,
1821 lp
=lp
, credentials
=credentials
,
1822 names
=names
, logger
=logger
)
1823 elif backend_type
== "existing":
1824 # If support for this is ever added back, then the URI will need to be specified again
1825 provision_backend
= ExistingBackend(backend_type
, paths
=paths
,
1826 lp
=lp
, credentials
=credentials
,
1827 names
=names
, logger
=logger
,
1828 ldap_backend_forced_uri
=None)
1829 elif backend_type
== "fedora-ds":
1830 provision_backend
= FDSBackend(backend_type
, paths
=paths
,
1831 lp
=lp
, credentials
=credentials
,
1832 names
=names
, logger
=logger
, domainsid
=domainsid
,
1833 schema
=schema
, hostname
=hostname
, ldapadminpass
=ldapadminpass
,
1834 slapd_path
=slapd_path
,
1836 elif backend_type
== "openldap":
1837 provision_backend
= OpenLDAPBackend(backend_type
, paths
=paths
,
1838 lp
=lp
, credentials
=credentials
,
1839 names
=names
, logger
=logger
, domainsid
=domainsid
,
1840 schema
=schema
, hostname
=hostname
, ldapadminpass
=ldapadminpass
,
1841 slapd_path
=slapd_path
, ol_mmr_urls
=ol_mmr_urls
)
1843 raise ValueError("Unknown LDAP backend type selected")
1845 provision_backend
.init()
1846 provision_backend
.start()
1848 # only install a new shares config db if there is none
1849 if not os
.path
.exists(paths
.shareconf
):
1850 logger
.info("Setting up share.ldb")
1851 share_ldb
= Ldb(paths
.shareconf
, session_info
=session_info
, lp
=lp
)
1852 share_ldb
.load_ldif_file_add(setup_path("share.ldif"))
1854 logger
.info("Setting up secrets.ldb")
1855 secrets_ldb
= setup_secretsdb(paths
,
1856 session_info
=session_info
,
1857 backend_credentials
=provision_backend
.secrets_credentials
, lp
=lp
)
1860 logger
.info("Setting up the registry")
1861 setup_registry(paths
.hklm
, session_info
, lp
=lp
)
1863 logger
.info("Setting up the privileges database")
1864 setup_privileges(paths
.privilege
, session_info
, lp
=lp
)
1866 logger
.info("Setting up idmap db")
1867 idmap
= setup_idmapdb(paths
.idmapdb
, session_info
=session_info
, lp
=lp
)
1869 setup_name_mappings(idmap
, sid
=str(domainsid
),
1870 root_uid
=root_uid
, nobody_uid
=nobody_uid
,
1871 users_gid
=users_gid
, wheel_gid
=wheel_gid
)
1873 logger
.info("Setting up SAM db")
1874 samdb
= setup_samdb(paths
.samdb
, session_info
,
1875 provision_backend
, lp
, names
, logger
=logger
,
1876 serverrole
=serverrole
,
1877 schema
=schema
, fill
=samdb_fill
, am_rodc
=am_rodc
)
1879 if serverrole
== "active directory domain controller":
1880 if paths
.netlogon
is None:
1881 raise MissingShareError("netlogon", paths
.smbconf
)
1883 if paths
.sysvol
is None:
1884 raise MissingShareError("sysvol", paths
.smbconf
)
1886 if not os
.path
.isdir(paths
.netlogon
):
1887 os
.makedirs(paths
.netlogon
, 0755)
1889 if adminpass
is None:
1890 adminpass
= samba
.generate_random_password(12, 32)
1891 adminpass_generated
= True
1893 adminpass_generated
= False
1895 if samdb_fill
== FILL_FULL
:
1896 provision_fill(samdb
, secrets_ldb
, logger
, names
, paths
,
1897 schema
=schema
, targetdir
=targetdir
, samdb_fill
=samdb_fill
,
1898 hostip
=hostip
, hostip6
=hostip6
, domainsid
=domainsid
,
1899 next_rid
=next_rid
, dc_rid
=dc_rid
, adminpass
=adminpass
,
1900 krbtgtpass
=krbtgtpass
, domainguid
=domainguid
,
1901 policyguid
=policyguid
, policyguid_dc
=policyguid_dc
,
1902 invocationid
=invocationid
, machinepass
=machinepass
,
1903 ntdsguid
=ntdsguid
, dns_backend
=dns_backend
,
1904 dnspass
=dnspass
, serverrole
=serverrole
,
1905 dom_for_fun_level
=dom_for_fun_level
, am_rodc
=am_rodc
,
1906 lp
=lp
, use_ntvfs
=use_ntvfs
)
1908 create_krb5_conf(paths
.krb5conf
,
1909 dnsdomain
=names
.dnsdomain
, hostname
=names
.hostname
,
1911 logger
.info("A Kerberos configuration suitable for Samba 4 has been "
1912 "generated at %s", paths
.krb5conf
)
1914 if serverrole
== "active directory domain controller":
1915 create_dns_update_list(lp
, logger
, paths
)
1917 backend_result
= provision_backend
.post_setup()
1918 provision_backend
.shutdown()
1920 create_phpldapadmin_config(paths
.phpldapadminconfig
,
1923 secrets_ldb
.transaction_cancel()
1926 # Now commit the secrets.ldb to disk
1927 secrets_ldb
.transaction_commit()
1929 # the commit creates the dns.keytab, now chown it
1930 dns_keytab_path
= os
.path
.join(paths
.private_dir
, paths
.dns_keytab
)
1931 if os
.path
.isfile(dns_keytab_path
) and paths
.bind_gid
is not None:
1933 os
.chmod(dns_keytab_path
, 0640)
1934 os
.chown(dns_keytab_path
, -1, paths
.bind_gid
)
1936 if not os
.environ
.has_key('SAMBA_SELFTEST'):
1937 logger
.info("Failed to chown %s to bind gid %u",
1938 dns_keytab_path
, paths
.bind_gid
)
1940 result
= ProvisionResult()
1941 result
.server_role
= serverrole
1942 result
.domaindn
= domaindn
1943 result
.paths
= paths
1944 result
.names
= names
1946 result
.samdb
= samdb
1947 result
.idmap
= idmap
1948 result
.domainsid
= str(domainsid
)
1950 if samdb_fill
== FILL_FULL
:
1951 result
.adminpass_generated
= adminpass_generated
1952 result
.adminpass
= adminpass
1954 result
.adminpass_generated
= False
1955 result
.adminpass
= None
1957 result
.backend_result
= backend_result
1960 provision_fake_ypserver(logger
=logger
, samdb
=samdb
, domaindn
=names
.domaindn
, netbiosname
=names
.netbiosname
,
1961 nisdomain
=(names
.domain
).lower(), maxuid
=maxuid
, maxgid
=maxgid
)
1966 def provision_become_dc(smbconf
=None, targetdir
=None,
1967 realm
=None, rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
1968 serverdn
=None, domain
=None, hostname
=None, domainsid
=None,
1969 adminpass
=None, krbtgtpass
=None, domainguid
=None, policyguid
=None,
1970 policyguid_dc
=None, invocationid
=None, machinepass
=None, dnspass
=None,
1971 dns_backend
=None, root
=None, nobody
=None, users
=None, wheel
=None,
1972 backup
=None, serverrole
=None, ldap_backend
=None,
1973 ldap_backend_type
=None, sitename
=None, debuglevel
=1, use_ntvfs
=False):
1975 logger
= logging
.getLogger("provision")
1976 samba
.set_debug_level(debuglevel
)
1978 res
= provision(logger
, system_session(), None,
1979 smbconf
=smbconf
, targetdir
=targetdir
, samdb_fill
=FILL_DRS
,
1980 realm
=realm
, rootdn
=rootdn
, domaindn
=domaindn
, schemadn
=schemadn
,
1981 configdn
=configdn
, serverdn
=serverdn
, domain
=domain
,
1982 hostname
=hostname
, hostip
=None, domainsid
=domainsid
,
1983 machinepass
=machinepass
, serverrole
="active directory domain controller",
1984 sitename
=sitename
, dns_backend
=dns_backend
, dnspass
=dnspass
, use_ntvfs
=use_ntvfs
)
1985 res
.lp
.set("debuglevel", str(debuglevel
))
1989 def create_phpldapadmin_config(path
, ldapi_uri
):
1990 """Create a PHP LDAP admin configuration file.
1992 :param path: Path to write the configuration to.
1994 setup_file(setup_path("phpldapadmin-config.php"), path
,
1995 {"S4_LDAPI_URI": ldapi_uri
})
1998 def create_krb5_conf(path
, dnsdomain
, hostname
, realm
):
1999 """Write out a file containing zone statements suitable for inclusion in a
2000 named.conf file (including GSS-TSIG configuration).
2002 :param path: Path of the new named.conf file.
2003 :param dnsdomain: DNS Domain name
2004 :param hostname: Local hostname
2005 :param realm: Realm name
2007 setup_file(setup_path("krb5.conf"), path
, {
2008 "DNSDOMAIN": dnsdomain
,
2009 "HOSTNAME": hostname
,
2014 class ProvisioningError(Exception):
2015 """A generic provision error."""
2017 def __init__(self
, value
):
2021 return "ProvisioningError: " + self
.value
2024 class InvalidNetbiosName(Exception):
2025 """A specified name was not a valid NetBIOS name."""
2027 def __init__(self
, name
):
2028 super(InvalidNetbiosName
, self
).__init
__(
2029 "The name '%r' is not a valid NetBIOS name" % name
)
2032 class MissingShareError(ProvisioningError
):
2034 def __init__(self
, name
, smbconf
):
2035 super(MissingShareError
, self
).__init
__(
2036 "Existing smb.conf does not have a [%s] share, but you are "
2037 "configuring a DC. Please remove %s or add the share manually." %