1 # Unix SMB/CIFS implementation.
2 # backend code for provisioning a Samba4 server
4 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2012
5 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
6 # Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
8 # Based on the original in EJS:
9 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 """Functions for setting up a Samba configuration."""
27 __docformat__
= "restructuredText"
29 from base64
import b64encode
44 from samba
.auth
import system_session
, admin_session
46 from samba
.samba3
import smbd
, passdb
47 from samba
.samba3
import param
as s3param
48 from samba
.dsdb
import DS_DOMAIN_FUNCTION_2000
52 check_all_substituted
,
53 is_valid_netbios_char
,
59 from samba
.dcerpc
import security
, misc
60 from samba
.dcerpc
.misc
import (
64 from samba
.dsdb
import (
65 DS_DOMAIN_FUNCTION_2003
,
66 DS_DOMAIN_FUNCTION_2008_R2
,
69 from samba
.idmap
import IDmapDB
70 from samba
.ms_display_specifiers
import read_ms_ldif
71 from samba
.ntacls
import setntacl
, getntacl
, dsacl2fsacl
72 from samba
.ndr
import ndr_pack
, ndr_unpack
73 from samba
.provision
.backend
import (
79 from samba
.descriptor
import (
81 get_config_descriptor
,
82 get_config_partitions_descriptor
,
83 get_config_sites_descriptor
,
84 get_config_ntds_quotas_descriptor
,
85 get_config_delete_protected1_descriptor
,
86 get_config_delete_protected1wd_descriptor
,
87 get_config_delete_protected2_descriptor
,
88 get_domain_descriptor
,
89 get_domain_infrastructure_descriptor
,
90 get_domain_builtin_descriptor
,
91 get_domain_computers_descriptor
,
92 get_domain_users_descriptor
,
93 get_domain_controllers_descriptor
,
94 get_domain_delete_protected1_descriptor
,
95 get_domain_delete_protected2_descriptor
,
96 get_dns_partition_descriptor
,
97 get_dns_forest_microsoft_dns_descriptor
,
98 get_dns_domain_microsoft_dns_descriptor
,
100 from samba
.provision
.common
import (
105 from samba
.provision
.sambadns
import (
108 create_dns_update_list
112 import samba
.registry
113 from samba
.schema
import Schema
114 from samba
.samdb
import SamDB
115 from samba
.dbchecker
import dbcheck
118 DEFAULT_POLICY_GUID
= "31B2F340-016D-11D2-945F-00C04FB984F9"
119 DEFAULT_DC_POLICY_GUID
= "6AC1786C-016F-11D2-945F-00C04fB984F9"
120 DEFAULTSITE
= "Default-First-Site-Name"
121 LAST_PROVISION_USN_ATTRIBUTE
= "lastProvisionUSN"
124 class ProvisionPaths(object):
127 self
.shareconf
= None
138 self
.dns_keytab
= None
141 self
.private_dir
= None
142 self
.state_dir
= None
145 class ProvisionNames(object):
153 self
.dnsforestdn
= None
154 self
.dnsdomaindn
= None
155 self
.ldapmanagerdn
= None
156 self
.dnsdomain
= None
158 self
.netbiosname
= None
166 def find_provision_key_parameters(samdb
, secretsdb
, idmapdb
, paths
, smbconf
,
168 """Get key provision parameters (realm, domain, ...) from a given provision
170 :param samdb: An LDB object connected to the sam.ldb file
171 :param secretsdb: An LDB object connected to the secrets.ldb file
172 :param idmapdb: An LDB object connected to the idmap.ldb file
173 :param paths: A list of path to provision object
174 :param smbconf: Path to the smb.conf file
175 :param lp: A LoadParm object
176 :return: A list of key provision parameters
178 names
= ProvisionNames()
179 names
.adminpass
= None
181 # NT domain, kerberos realm, root dn, domain dn, domain dns name
182 names
.domain
= string
.upper(lp
.get("workgroup"))
183 names
.realm
= lp
.get("realm")
184 names
.dnsdomain
= names
.realm
.lower()
185 basedn
= samba
.dn_from_dns_name(names
.dnsdomain
)
186 names
.realm
= string
.upper(names
.realm
)
188 # Get the netbiosname first (could be obtained from smb.conf in theory)
189 res
= secretsdb
.search(expression
="(flatname=%s)" %
190 names
.domain
,base
="CN=Primary Domains",
191 scope
=ldb
.SCOPE_SUBTREE
, attrs
=["sAMAccountName"])
192 names
.netbiosname
= str(res
[0]["sAMAccountName"]).replace("$","")
194 names
.smbconf
= smbconf
196 # That's a bit simplistic but it's ok as long as we have only 3
198 current
= samdb
.search(expression
="(objectClass=*)",
199 base
="", scope
=ldb
.SCOPE_BASE
,
200 attrs
=["defaultNamingContext", "schemaNamingContext",
201 "configurationNamingContext","rootDomainNamingContext",
204 names
.configdn
= current
[0]["configurationNamingContext"][0]
205 names
.schemadn
= current
[0]["schemaNamingContext"][0]
206 if not (ldb
.Dn(samdb
, basedn
) == (ldb
.Dn(samdb
,
207 current
[0]["defaultNamingContext"][0]))):
208 raise ProvisioningError(("basedn in %s (%s) and from %s (%s)"
209 "is not the same ..." % (paths
.samdb
,
210 str(current
[0]["defaultNamingContext"][0]),
211 paths
.smbconf
, basedn
)))
213 names
.domaindn
=current
[0]["defaultNamingContext"][0]
214 names
.rootdn
=current
[0]["rootDomainNamingContext"][0]
215 names
.ncs
=current
[0]["namingContexts"]
216 names
.dnsforestdn
= None
217 names
.dnsdomaindn
= None
219 for i
in range(0, len(names
.ncs
)):
222 dnsforestdn
= "DC=ForestDnsZones,%s" % (str(names
.rootdn
))
223 if nc
== dnsforestdn
:
224 names
.dnsforestdn
= dnsforestdn
227 dnsdomaindn
= "DC=DomainDnsZones,%s" % (str(names
.domaindn
))
228 if nc
== dnsdomaindn
:
229 names
.dnsdomaindn
= dnsdomaindn
233 res3
= samdb
.search(expression
="(objectClass=site)",
234 base
="CN=Sites," + names
.configdn
, scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn"])
235 names
.sitename
= str(res3
[0]["cn"])
237 # dns hostname and server dn
238 res4
= samdb
.search(expression
="(CN=%s)" % names
.netbiosname
,
239 base
="OU=Domain Controllers,%s" % basedn
,
240 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["dNSHostName"])
241 names
.hostname
= str(res4
[0]["dNSHostName"]).replace("." + names
.dnsdomain
, "")
243 server_res
= samdb
.search(expression
="serverReference=%s" % res4
[0].dn
,
244 attrs
=[], base
=names
.configdn
)
245 names
.serverdn
= str(server_res
[0].dn
)
247 # invocation id/objectguid
248 res5
= samdb
.search(expression
="(objectClass=*)",
249 base
="CN=NTDS Settings,%s" % str(names
.serverdn
),
250 scope
=ldb
.SCOPE_BASE
,
251 attrs
=["invocationID", "objectGUID"])
252 names
.invocation
= str(ndr_unpack(misc
.GUID
, res5
[0]["invocationId"][0]))
253 names
.ntdsguid
= str(ndr_unpack(misc
.GUID
, res5
[0]["objectGUID"][0]))
256 res6
= samdb
.search(expression
="(objectClass=*)", base
=basedn
,
257 scope
=ldb
.SCOPE_BASE
, attrs
=["objectGUID",
258 "objectSid","msDS-Behavior-Version" ])
259 names
.domainguid
= str(ndr_unpack(misc
.GUID
, res6
[0]["objectGUID"][0]))
260 names
.domainsid
= ndr_unpack( security
.dom_sid
, res6
[0]["objectSid"][0])
261 if res6
[0].get("msDS-Behavior-Version") is None or \
262 int(res6
[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000
:
263 names
.domainlevel
= DS_DOMAIN_FUNCTION_2000
265 names
.domainlevel
= int(res6
[0]["msDS-Behavior-Version"][0])
268 res7
= samdb
.search(expression
="(displayName=Default Domain Policy)",
269 base
="CN=Policies,CN=System," + basedn
,
270 scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["cn","displayName"])
271 names
.policyid
= str(res7
[0]["cn"]).replace("{","").replace("}","")
273 res8
= samdb
.search(expression
="(displayName=Default Domain Controllers"
275 base
="CN=Policies,CN=System," + basedn
,
276 scope
=ldb
.SCOPE_ONELEVEL
,
277 attrs
=["cn","displayName"])
279 names
.policyid_dc
= str(res8
[0]["cn"]).replace("{","").replace("}","")
281 names
.policyid_dc
= None
283 res9
= idmapdb
.search(expression
="(cn=%s-%s)" %
284 (str(names
.domainsid
), security
.DOMAIN_RID_ADMINISTRATOR
),
285 attrs
=["xidNumber", "type"])
287 raise ProvisioningError("Unable to find uid/gid for Domain Admins rid (%s-%s" % (str(names
.domainsid
), security
.DOMAIN_RID_ADMINISTRATOR
))
288 if res9
[0]["type"][0] == "ID_TYPE_BOTH":
289 names
.root_gid
= res9
[0]["xidNumber"][0]
291 names
.root_gid
= pwd
.getpwuid(int(res9
[0]["xidNumber"][0])).pw_gid
293 res10
= samdb
.search(expression
="(samaccountname=dns)",
294 scope
=ldb
.SCOPE_SUBTREE
, attrs
=["dn"],
295 controls
=["search_options:1:2"])
297 has_legacy_dns_account
= True
299 has_legacy_dns_account
= False
301 res11
= samdb
.search(expression
="(samaccountname=dns-%s)" % names
.netbiosname
,
302 scope
=ldb
.SCOPE_SUBTREE
, attrs
=["dn"],
303 controls
=["search_options:1:2"])
305 has_dns_account
= True
307 has_dns_account
= False
309 if names
.dnsdomaindn
is not None:
311 names
.dns_backend
= 'BIND9_DLZ'
313 names
.dns_backend
= 'SAMBA_INTERNAL'
314 elif has_dns_account
or has_legacy_dns_account
:
315 names
.dns_backend
= 'BIND9_FLATFILE'
317 names
.dns_backend
= 'NONE'
319 dns_admins_sid
= get_dnsadmins_sid(samdb
, names
.domaindn
)
320 names
.name_map
['DnsAdmins'] = str(dns_admins_sid
)
325 def update_provision_usn(samdb
, low
, high
, id, replace
=False):
326 """Update the field provisionUSN in sam.ldb
328 This field is used to track range of USN modified by provision and
330 This value is used afterward by next provision to figure out if
331 the field have been modified since last provision.
333 :param samdb: An LDB object connect to sam.ldb
334 :param low: The lowest USN modified by this upgrade
335 :param high: The highest USN modified by this upgrade
336 :param id: The invocation id of the samba's dc
337 :param replace: A boolean indicating if the range should replace any
338 existing one or appended (default)
343 entry
= samdb
.search(base
="@PROVISION",
344 scope
=ldb
.SCOPE_BASE
,
345 attrs
=[LAST_PROVISION_USN_ATTRIBUTE
, "dn"])
346 for e
in entry
[0][LAST_PROVISION_USN_ATTRIBUTE
]:
347 if not re
.search(';', e
):
348 e
= "%s;%s" % (e
, id)
351 tab
.append("%s-%s;%s" % (low
, high
, id))
352 delta
= ldb
.Message()
353 delta
.dn
= ldb
.Dn(samdb
, "@PROVISION")
354 delta
[LAST_PROVISION_USN_ATTRIBUTE
] = ldb
.MessageElement(tab
,
355 ldb
.FLAG_MOD_REPLACE
, LAST_PROVISION_USN_ATTRIBUTE
)
356 entry
= samdb
.search(expression
='provisionnerID=*',
357 base
="@PROVISION", scope
=ldb
.SCOPE_BASE
,
358 attrs
=["provisionnerID"])
359 if len(entry
) == 0 or len(entry
[0]) == 0:
360 delta
["provisionnerID"] = ldb
.MessageElement(id, ldb
.FLAG_MOD_ADD
, "provisionnerID")
364 def set_provision_usn(samdb
, low
, high
, id):
365 """Set the field provisionUSN in sam.ldb
366 This field is used to track range of USN modified by provision and
368 This value is used afterward by next provision to figure out if
369 the field have been modified since last provision.
371 :param samdb: An LDB object connect to sam.ldb
372 :param low: The lowest USN modified by this upgrade
373 :param high: The highest USN modified by this upgrade
374 :param id: The invocationId of the provision"""
377 tab
.append("%s-%s;%s" % (low
, high
, id))
379 delta
= ldb
.Message()
380 delta
.dn
= ldb
.Dn(samdb
, "@PROVISION")
381 delta
[LAST_PROVISION_USN_ATTRIBUTE
] = ldb
.MessageElement(tab
,
382 ldb
.FLAG_MOD_ADD
, LAST_PROVISION_USN_ATTRIBUTE
)
386 def get_max_usn(samdb
,basedn
):
387 """ This function return the biggest USN present in the provision
389 :param samdb: A LDB object pointing to the sam.ldb
390 :param basedn: A string containing the base DN of the provision
392 :return: The biggest USN in the provision"""
394 res
= samdb
.search(expression
="objectClass=*",base
=basedn
,
395 scope
=ldb
.SCOPE_SUBTREE
,attrs
=["uSNChanged"],
396 controls
=["search_options:1:2",
397 "server_sort:1:1:uSNChanged",
398 "paged_results:1:1"])
399 return res
[0]["uSNChanged"]
402 def get_last_provision_usn(sam
):
403 """Get USNs ranges modified by a provision or an upgradeprovision
405 :param sam: An LDB object pointing to the sam.ldb
406 :return: a dictionary which keys are invocation id and values are an array
407 of integer representing the different ranges
410 entry
= sam
.search(expression
="%s=*" % LAST_PROVISION_USN_ATTRIBUTE
,
411 base
="@PROVISION", scope
=ldb
.SCOPE_BASE
,
412 attrs
=[LAST_PROVISION_USN_ATTRIBUTE
, "provisionnerID"])
413 except ldb
.LdbError
, (ecode
, emsg
):
414 if ecode
== ldb
.ERR_NO_SUCH_OBJECT
:
421 if entry
[0].get("provisionnerID"):
422 for e
in entry
[0]["provisionnerID"]:
424 for r
in entry
[0][LAST_PROVISION_USN_ATTRIBUTE
]:
425 tab1
= str(r
).split(';')
430 if (len(myids
) > 0 and id not in myids
):
432 tab2
= p
.split(tab1
[0])
433 if range.get(id) is None:
435 range[id].append(tab2
[0])
436 range[id].append(tab2
[1])
442 class ProvisionResult(object):
443 """Result of a provision.
445 :ivar server_role: The server role
446 :ivar paths: ProvisionPaths instance
447 :ivar domaindn: The domain dn, as string
451 self
.server_role
= None
458 self
.domainsid
= None
459 self
.adminpass_generated
= None
460 self
.adminpass
= None
461 self
.backend_result
= None
463 def report_logger(self
, logger
):
464 """Report this provision result to a logger."""
466 "Once the above files are installed, your Samba4 server will "
468 if self
.adminpass_generated
:
469 logger
.info("Admin password: %s", self
.adminpass
)
470 logger
.info("Server Role: %s", self
.server_role
)
471 logger
.info("Hostname: %s", self
.names
.hostname
)
472 logger
.info("NetBIOS Domain: %s", self
.names
.domain
)
473 logger
.info("DNS Domain: %s", self
.names
.dnsdomain
)
474 logger
.info("DOMAIN SID: %s", self
.domainsid
)
476 if self
.backend_result
:
477 self
.backend_result
.report_logger(logger
)
480 def check_install(lp
, session_info
, credentials
):
481 """Check whether the current install seems ok.
483 :param lp: Loadparm context
484 :param session_info: Session information
485 :param credentials: Credentials
487 if lp
.get("realm") == "":
488 raise Exception("Realm empty")
489 samdb
= Ldb(lp
.samdb_url(), session_info
=session_info
,
490 credentials
=credentials
, lp
=lp
)
491 if len(samdb
.search("(cn=Administrator)")) != 1:
492 raise ProvisioningError("No administrator account found")
495 def findnss(nssfn
, names
):
496 """Find a user or group from a list of possibilities.
498 :param nssfn: NSS Function to try (should raise KeyError if not found)
499 :param names: Names to check.
500 :return: Value return by first names list.
507 raise KeyError("Unable to find user/group in %r" % names
)
510 findnss_uid
= lambda names
: findnss(pwd
.getpwnam
, names
)[2]
511 findnss_gid
= lambda names
: findnss(grp
.getgrnam
, names
)[2]
514 def provision_paths_from_lp(lp
, dnsdomain
):
515 """Set the default paths for provisioning.
517 :param lp: Loadparm context.
518 :param dnsdomain: DNS Domain name
520 paths
= ProvisionPaths()
521 paths
.private_dir
= lp
.get("private dir")
522 paths
.state_dir
= lp
.get("state directory")
524 # This is stored without path prefix for the "privateKeytab" attribute in
525 # "secrets_dns.ldif".
526 paths
.dns_keytab
= "dns.keytab"
527 paths
.keytab
= "secrets.keytab"
529 paths
.shareconf
= os
.path
.join(paths
.private_dir
, "share.ldb")
530 paths
.samdb
= os
.path
.join(paths
.private_dir
, "sam.ldb")
531 paths
.idmapdb
= os
.path
.join(paths
.private_dir
, "idmap.ldb")
532 paths
.secrets
= os
.path
.join(paths
.private_dir
, "secrets.ldb")
533 paths
.privilege
= os
.path
.join(paths
.private_dir
, "privilege.ldb")
534 paths
.dns
= os
.path
.join(paths
.private_dir
, "dns", dnsdomain
+ ".zone")
535 paths
.dns_update_list
= os
.path
.join(paths
.private_dir
, "dns_update_list")
536 paths
.spn_update_list
= os
.path
.join(paths
.private_dir
, "spn_update_list")
537 paths
.namedconf
= os
.path
.join(paths
.private_dir
, "named.conf")
538 paths
.namedconf_update
= os
.path
.join(paths
.private_dir
, "named.conf.update")
539 paths
.namedtxt
= os
.path
.join(paths
.private_dir
, "named.txt")
540 paths
.krb5conf
= os
.path
.join(paths
.private_dir
, "krb5.conf")
541 paths
.winsdb
= os
.path
.join(paths
.private_dir
, "wins.ldb")
542 paths
.s4_ldapi_path
= os
.path
.join(paths
.private_dir
, "ldapi")
543 paths
.hklm
= "hklm.ldb"
544 paths
.hkcr
= "hkcr.ldb"
545 paths
.hkcu
= "hkcu.ldb"
546 paths
.hku
= "hku.ldb"
547 paths
.hkpd
= "hkpd.ldb"
548 paths
.hkpt
= "hkpt.ldb"
549 paths
.sysvol
= lp
.get("path", "sysvol")
550 paths
.netlogon
= lp
.get("path", "netlogon")
551 paths
.smbconf
= lp
.configfile
555 def determine_netbios_name(hostname
):
556 """Determine a netbios name from a hostname."""
557 # remove forbidden chars and force the length to be <16
558 netbiosname
= "".join([x
for x
in hostname
if is_valid_netbios_char(x
)])
559 return netbiosname
[:MAX_NETBIOS_NAME_LEN
].upper()
562 def guess_names(lp
=None, hostname
=None, domain
=None, dnsdomain
=None,
563 serverrole
=None, rootdn
=None, domaindn
=None, configdn
=None,
564 schemadn
=None, serverdn
=None, sitename
=None,
565 domain_names_forced
=False):
566 """Guess configuration settings to use."""
569 hostname
= socket
.gethostname().split(".")[0]
571 netbiosname
= lp
.get("netbios name")
572 if netbiosname
is None:
573 netbiosname
= determine_netbios_name(hostname
)
574 netbiosname
= netbiosname
.upper()
575 if not valid_netbios_name(netbiosname
):
576 raise InvalidNetbiosName(netbiosname
)
578 if dnsdomain
is None:
579 dnsdomain
= lp
.get("realm")
580 if dnsdomain
is None or dnsdomain
== "":
581 raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp
.configfile
)
583 dnsdomain
= dnsdomain
.lower()
585 if serverrole
is None:
586 serverrole
= lp
.get("server role")
587 if serverrole
is None:
588 raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp
.configfile
)
590 serverrole
= serverrole
.lower()
592 realm
= dnsdomain
.upper()
594 if lp
.get("realm") == "":
595 raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s. Please remove the smb.conf file and let provision generate it" % lp
.configfile
)
597 if lp
.get("realm").upper() != realm
:
598 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
))
600 if lp
.get("server role").lower() != serverrole
:
601 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
))
603 if serverrole
== "active directory domain controller":
605 # This will, for better or worse, default to 'WORKGROUP'
606 domain
= lp
.get("workgroup")
607 domain
= domain
.upper()
609 if lp
.get("workgroup").upper() != domain
:
610 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
))
613 domaindn
= samba
.dn_from_dns_name(dnsdomain
)
615 if domain
== netbiosname
:
616 raise ProvisioningError("guess_names: Domain '%s' must not be equal to short host name '%s'!" % (domain
, netbiosname
))
620 domaindn
= "DC=" + netbiosname
622 if not valid_netbios_name(domain
):
623 raise InvalidNetbiosName(domain
)
625 if hostname
.upper() == realm
:
626 raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm
, hostname
))
627 if netbiosname
.upper() == realm
:
628 raise ProvisioningError("guess_names: Realm '%s' must not be equal to NetBIOS hostname '%s'!" % (realm
, netbiosname
))
629 if domain
== realm
and not domain_names_forced
:
630 raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm
, domain
))
636 configdn
= "CN=Configuration," + rootdn
638 schemadn
= "CN=Schema," + configdn
641 sitename
= DEFAULTSITE
643 names
= ProvisionNames()
644 names
.rootdn
= rootdn
645 names
.domaindn
= domaindn
646 names
.configdn
= configdn
647 names
.schemadn
= schemadn
648 names
.ldapmanagerdn
= "CN=Manager," + rootdn
649 names
.dnsdomain
= dnsdomain
650 names
.domain
= domain
652 names
.netbiosname
= netbiosname
653 names
.hostname
= hostname
654 names
.sitename
= sitename
655 names
.serverdn
= "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (
656 netbiosname
, sitename
, configdn
)
661 def make_smbconf(smbconf
, hostname
, domain
, realm
, targetdir
,
662 serverrole
=None, eadb
=False, use_ntvfs
=False, lp
=None,
664 """Create a new smb.conf file based on a couple of basic settings.
666 assert smbconf
is not None
669 hostname
= socket
.gethostname().split(".")[0]
671 netbiosname
= determine_netbios_name(hostname
)
673 if serverrole
is None:
674 serverrole
= "standalone server"
676 assert domain
is not None
677 domain
= domain
.upper()
679 assert realm
is not None
680 realm
= realm
.upper()
683 "netbios name": netbiosname
,
686 "server role": serverrole
,
690 lp
= samba
.param
.LoadParm()
691 #Load non-existent file
692 if os
.path
.exists(smbconf
):
695 if global_param
is not None:
696 for ent
in global_param
:
697 if global_param
[ent
] is not None:
698 global_settings
[ent
] = " ".join(global_param
[ent
])
700 if targetdir
is not None:
701 global_settings
["private dir"] = os
.path
.abspath(os
.path
.join(targetdir
, "private"))
702 global_settings
["lock dir"] = os
.path
.abspath(targetdir
)
703 global_settings
["state directory"] = os
.path
.abspath(os
.path
.join(targetdir
, "state"))
704 global_settings
["cache directory"] = os
.path
.abspath(os
.path
.join(targetdir
, "cache"))
706 lp
.set("lock dir", os
.path
.abspath(targetdir
))
707 lp
.set("state directory", global_settings
["state directory"])
708 lp
.set("cache directory", global_settings
["cache directory"])
711 if use_ntvfs
and not lp
.get("posix:eadb"):
712 if targetdir
is not None:
713 privdir
= os
.path
.join(targetdir
, "private")
715 privdir
= lp
.get("private dir")
716 lp
.set("posix:eadb", os
.path
.abspath(os
.path
.join(privdir
, "eadb.tdb")))
717 elif not use_ntvfs
and not lp
.get("xattr_tdb:file"):
718 if targetdir
is not None:
719 statedir
= os
.path
.join(targetdir
, "state")
721 statedir
= lp
.get("state directory")
722 lp
.set("xattr_tdb:file", os
.path
.abspath(os
.path
.join(statedir
, "xattr.tdb")))
725 if serverrole
== "active directory domain controller":
726 shares
["sysvol"] = os
.path
.join(lp
.get("state directory"), "sysvol")
727 shares
["netlogon"] = os
.path
.join(shares
["sysvol"], realm
.lower(),
730 global_settings
["passdb backend"] = "samba_dsdb"
732 f
= open(smbconf
, 'w')
734 f
.write("[globals]\n")
735 for key
, val
in global_settings
.iteritems():
736 f
.write("\t%s = %s\n" % (key
, val
))
739 for name
, path
in shares
.iteritems():
740 f
.write("[%s]\n" % name
)
741 f
.write("\tpath = %s\n" % path
)
742 f
.write("\tread only = no\n")
746 # reload the smb.conf
749 # and dump it without any values that are the default
750 # this ensures that any smb.conf parameters that were set
751 # on the provision/join command line are set in the resulting smb.conf
752 f
= open(smbconf
, mode
='w')
759 def setup_name_mappings(idmap
, sid
, root_uid
, nobody_uid
,
760 users_gid
, root_gid
):
761 """setup reasonable name mappings for sam names to unix names.
763 :param samdb: SamDB object.
764 :param idmap: IDmap db object.
765 :param sid: The domain sid.
766 :param domaindn: The domain DN.
767 :param root_uid: uid of the UNIX root user.
768 :param nobody_uid: uid of the UNIX nobody user.
769 :param users_gid: gid of the UNIX users group.
770 :param root_gid: gid of the UNIX root group.
772 idmap
.setup_name_mapping("S-1-5-7", idmap
.TYPE_UID
, nobody_uid
)
774 idmap
.setup_name_mapping(sid
+ "-500", idmap
.TYPE_UID
, root_uid
)
775 idmap
.setup_name_mapping(sid
+ "-513", idmap
.TYPE_GID
, users_gid
)
778 def setup_samdb_partitions(samdb_path
, logger
, lp
, session_info
,
779 provision_backend
, names
, schema
, serverrole
,
781 """Setup the partitions for the SAM database.
783 Alternatively, provision() may call this, and then populate the database.
785 :note: This will wipe the Sam Database!
787 :note: This function always removes the local SAM LDB file. The erase
788 parameter controls whether to erase the existing data, which
789 may not be stored locally but in LDAP.
792 assert session_info
is not None
794 # We use options=["modules:"] to stop the modules loading - we
795 # just want to wipe and re-initialise the database, not start it up
798 os
.unlink(samdb_path
)
802 samdb
= Ldb(url
=samdb_path
, session_info
=session_info
,
803 lp
=lp
, options
=["modules:"])
805 ldap_backend_line
= "# No LDAP backend"
806 if provision_backend
.type != "ldb":
807 ldap_backend_line
= "ldapBackend: %s" % provision_backend
.ldap_uri
809 samdb
.transaction_start()
811 logger
.info("Setting up sam.ldb partitions and settings")
812 setup_add_ldif(samdb
, setup_path("provision_partitions.ldif"), {
813 "LDAP_BACKEND_LINE": ldap_backend_line
817 setup_add_ldif(samdb
, setup_path("provision_init.ldif"), {
818 "BACKEND_TYPE": provision_backend
.type,
819 "SERVER_ROLE": serverrole
822 logger
.info("Setting up sam.ldb rootDSE")
823 setup_samdb_rootdse(samdb
, names
)
825 samdb
.transaction_cancel()
828 samdb
.transaction_commit()
831 def secretsdb_self_join(secretsdb
, domain
,
832 netbiosname
, machinepass
, domainsid
=None,
833 realm
=None, dnsdomain
=None,
835 key_version_number
=1,
836 secure_channel_type
=SEC_CHAN_WKSTA
):
837 """Add domain join-specific bits to a secrets database.
839 :param secretsdb: Ldb Handle to the secrets database
840 :param machinepass: Machine password
842 attrs
= ["whenChanged",
849 if realm
is not None:
850 if dnsdomain
is None:
851 dnsdomain
= realm
.lower()
852 dnsname
= '%s.%s' % (netbiosname
.lower(), dnsdomain
.lower())
855 shortname
= netbiosname
.lower()
857 # We don't need to set msg["flatname"] here, because rdn_name will handle
858 # it, and it causes problems for modifies anyway
859 msg
= ldb
.Message(ldb
.Dn(secretsdb
, "flatname=%s,cn=Primary Domains" % domain
))
860 msg
["secureChannelType"] = [str(secure_channel_type
)]
861 msg
["objectClass"] = ["top", "primaryDomain"]
862 if dnsname
is not None:
863 msg
["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
864 msg
["realm"] = [realm
]
865 msg
["saltPrincipal"] = ["host/%s@%s" % (dnsname
, realm
.upper())]
866 msg
["msDS-KeyVersionNumber"] = [str(key_version_number
)]
867 msg
["privateKeytab"] = ["secrets.keytab"]
869 msg
["secret"] = [machinepass
]
870 msg
["samAccountName"] = ["%s$" % netbiosname
]
871 msg
["secureChannelType"] = [str(secure_channel_type
)]
872 if domainsid
is not None:
873 msg
["objectSid"] = [ndr_pack(domainsid
)]
875 # This complex expression tries to ensure that we don't have more
876 # than one record for this SID, realm or netbios domain at a time,
877 # but we don't delete the old record that we are about to modify,
878 # because that would delete the keytab and previous password.
879 res
= secretsdb
.search(base
="cn=Primary Domains", attrs
=attrs
,
880 expression
=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(distinguishedName=%s)))" % (domain
, realm
, str(domainsid
), str(msg
.dn
))),
881 scope
=ldb
.SCOPE_ONELEVEL
)
884 secretsdb
.delete(del_msg
.dn
)
886 res
= secretsdb
.search(base
=msg
.dn
, attrs
=attrs
, scope
=ldb
.SCOPE_BASE
)
889 msg
["priorSecret"] = [res
[0]["secret"][0]]
890 msg
["priorWhenChanged"] = [res
[0]["whenChanged"][0]]
893 msg
["privateKeytab"] = [res
[0]["privateKeytab"][0]]
898 msg
["krb5Keytab"] = [res
[0]["krb5Keytab"][0]]
904 msg
[el
].set_flags(ldb
.FLAG_MOD_REPLACE
)
905 secretsdb
.modify(msg
)
906 secretsdb
.rename(res
[0].dn
, msg
.dn
)
908 spn
= [ 'HOST/%s' % shortname
]
909 if secure_channel_type
== SEC_CHAN_BDC
and dnsname
is not None:
910 # we are a domain controller then we add servicePrincipalName
911 # entries for the keytab code to update.
912 spn
.extend([ 'HOST/%s' % dnsname
])
913 msg
["servicePrincipalName"] = spn
918 def setup_secretsdb(paths
, session_info
, backend_credentials
, lp
):
919 """Setup the secrets database.
921 :note: This function does not handle exceptions and transaction on purpose,
922 it's up to the caller to do this job.
924 :param path: Path to the secrets database.
925 :param session_info: Session info.
926 :param credentials: Credentials
927 :param lp: Loadparm context
928 :return: LDB handle for the created secrets database
930 if os
.path
.exists(paths
.secrets
):
931 os
.unlink(paths
.secrets
)
933 keytab_path
= os
.path
.join(paths
.private_dir
, paths
.keytab
)
934 if os
.path
.exists(keytab_path
):
935 os
.unlink(keytab_path
)
937 dns_keytab_path
= os
.path
.join(paths
.private_dir
, paths
.dns_keytab
)
938 if os
.path
.exists(dns_keytab_path
):
939 os
.unlink(dns_keytab_path
)
943 secrets_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
945 secrets_ldb
.load_ldif_file_add(setup_path("secrets_init.ldif"))
946 secrets_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
947 secrets_ldb
.transaction_start()
949 secrets_ldb
.load_ldif_file_add(setup_path("secrets.ldif"))
951 if (backend_credentials
is not None and
952 backend_credentials
.authentication_requested()):
953 if backend_credentials
.get_bind_dn() is not None:
954 setup_add_ldif(secrets_ldb
,
955 setup_path("secrets_simple_ldap.ldif"), {
956 "LDAPMANAGERDN": backend_credentials
.get_bind_dn(),
957 "LDAPMANAGERPASS_B64": b64encode(backend_credentials
.get_password())
960 setup_add_ldif(secrets_ldb
,
961 setup_path("secrets_sasl_ldap.ldif"), {
962 "LDAPADMINUSER": backend_credentials
.get_username(),
963 "LDAPADMINREALM": backend_credentials
.get_realm(),
964 "LDAPADMINPASS_B64": b64encode(backend_credentials
.get_password())
967 secrets_ldb
.transaction_cancel()
972 def setup_privileges(path
, session_info
, lp
):
973 """Setup the privileges database.
975 :param path: Path to the privileges database.
976 :param session_info: Session info.
977 :param credentials: Credentials
978 :param lp: Loadparm context
979 :return: LDB handle for the created secrets database
981 if os
.path
.exists(path
):
983 privilege_ldb
= Ldb(path
, session_info
=session_info
, lp
=lp
)
984 privilege_ldb
.erase()
985 privilege_ldb
.load_ldif_file_add(setup_path("provision_privilege.ldif"))
988 def setup_registry(path
, session_info
, lp
):
989 """Setup the registry.
991 :param path: Path to the registry database
992 :param session_info: Session information
993 :param credentials: Credentials
994 :param lp: Loadparm context
996 reg
= samba
.registry
.Registry()
997 hive
= samba
.registry
.open_ldb(path
, session_info
=session_info
, lp_ctx
=lp
)
998 reg
.mount_hive(hive
, samba
.registry
.HKEY_LOCAL_MACHINE
)
999 provision_reg
= setup_path("provision.reg")
1000 assert os
.path
.exists(provision_reg
)
1001 reg
.diff_apply(provision_reg
)
1004 def setup_idmapdb(path
, session_info
, lp
):
1005 """Setup the idmap database.
1007 :param path: path to the idmap database
1008 :param session_info: Session information
1009 :param credentials: Credentials
1010 :param lp: Loadparm context
1012 if os
.path
.exists(path
):
1015 idmap_ldb
= IDmapDB(path
, session_info
=session_info
, lp
=lp
)
1017 idmap_ldb
.load_ldif_file_add(setup_path("idmap_init.ldif"))
1021 def setup_samdb_rootdse(samdb
, names
):
1022 """Setup the SamDB rootdse.
1024 :param samdb: Sam Database handle
1026 setup_add_ldif(samdb
, setup_path("provision_rootdse_add.ldif"), {
1027 "SCHEMADN": names
.schemadn
,
1028 "DOMAINDN": names
.domaindn
,
1029 "ROOTDN" : names
.rootdn
,
1030 "CONFIGDN": names
.configdn
,
1031 "SERVERDN": names
.serverdn
,
1035 def setup_self_join(samdb
, admin_session_info
, names
, fill
, machinepass
,
1036 dns_backend
, dnspass
, domainsid
, next_rid
, invocationid
,
1037 policyguid
, policyguid_dc
,
1038 domainControllerFunctionality
, ntdsguid
=None, dc_rid
=None):
1039 """Join a host to its own domain."""
1040 assert isinstance(invocationid
, str)
1041 if ntdsguid
is not None:
1042 ntdsguid_line
= "objectGUID: %s\n"%ntdsguid
1049 setup_add_ldif(samdb
, setup_path("provision_self_join.ldif"), {
1050 "CONFIGDN": names
.configdn
,
1051 "SCHEMADN": names
.schemadn
,
1052 "DOMAINDN": names
.domaindn
,
1053 "SERVERDN": names
.serverdn
,
1054 "INVOCATIONID": invocationid
,
1055 "NETBIOSNAME": names
.netbiosname
,
1056 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
1057 "MACHINEPASS_B64": b64encode(machinepass
.encode('utf-16-le')),
1058 "DOMAINSID": str(domainsid
),
1059 "DCRID": str(dc_rid
),
1060 "SAMBA_VERSION_STRING": version
,
1061 "NTDSGUID": ntdsguid_line
,
1062 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
1063 domainControllerFunctionality
),
1064 "RIDALLOCATIONSTART": str(next_rid
+ 100),
1065 "RIDALLOCATIONEND": str(next_rid
+ 100 + 499)})
1067 setup_add_ldif(samdb
, setup_path("provision_group_policy.ldif"), {
1068 "POLICYGUID": policyguid
,
1069 "POLICYGUID_DC": policyguid_dc
,
1070 "DNSDOMAIN": names
.dnsdomain
,
1071 "DOMAINDN": names
.domaindn
})
1073 # If we are setting up a subdomain, then this has been replicated in, so we
1074 # don't need to add it
1075 if fill
== FILL_FULL
:
1076 setup_add_ldif(samdb
, setup_path("provision_self_join_config.ldif"), {
1077 "CONFIGDN": names
.configdn
,
1078 "SCHEMADN": names
.schemadn
,
1079 "DOMAINDN": names
.domaindn
,
1080 "SERVERDN": names
.serverdn
,
1081 "INVOCATIONID": invocationid
,
1082 "NETBIOSNAME": names
.netbiosname
,
1083 "DNSNAME": "%s.%s" % (names
.hostname
, names
.dnsdomain
),
1084 "MACHINEPASS_B64": b64encode(machinepass
.encode('utf-16-le')),
1085 "DOMAINSID": str(domainsid
),
1086 "DCRID": str(dc_rid
),
1087 "SAMBA_VERSION_STRING": version
,
1088 "NTDSGUID": ntdsguid_line
,
1089 "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
1090 domainControllerFunctionality
)})
1092 # Setup fSMORoleOwner entries to point at the newly created DC entry
1093 setup_modify_ldif(samdb
,
1094 setup_path("provision_self_join_modify_config.ldif"), {
1095 "CONFIGDN": names
.configdn
,
1096 "SCHEMADN": names
.schemadn
,
1097 "DEFAULTSITE": names
.sitename
,
1098 "NETBIOSNAME": names
.netbiosname
,
1099 "SERVERDN": names
.serverdn
,
1102 system_session_info
= system_session()
1103 samdb
.set_session_info(system_session_info
)
1104 # Setup fSMORoleOwner entries to point at the newly created DC entry to
1105 # modify a serverReference under cn=config when we are a subdomain, we must
1106 # be system due to ACLs
1107 setup_modify_ldif(samdb
, setup_path("provision_self_join_modify.ldif"), {
1108 "DOMAINDN": names
.domaindn
,
1109 "SERVERDN": names
.serverdn
,
1110 "NETBIOSNAME": names
.netbiosname
,
1113 samdb
.set_session_info(admin_session_info
)
1115 if dns_backend
!= "SAMBA_INTERNAL":
1116 # This is Samba4 specific and should be replaced by the correct
1117 # DNS AD-style setup
1118 setup_add_ldif(samdb
, setup_path("provision_dns_add_samba.ldif"), {
1119 "DNSDOMAIN": names
.dnsdomain
,
1120 "DOMAINDN": names
.domaindn
,
1121 "DNSPASS_B64": b64encode(dnspass
.encode('utf-16-le')),
1122 "HOSTNAME" : names
.hostname
,
1123 "DNSNAME" : '%s.%s' % (
1124 names
.netbiosname
.lower(), names
.dnsdomain
.lower())
1128 def getpolicypath(sysvolpath
, dnsdomain
, guid
):
1129 """Return the physical path of policy given its guid.
1131 :param sysvolpath: Path to the sysvol folder
1132 :param dnsdomain: DNS name of the AD domain
1133 :param guid: The GUID of the policy
1134 :return: A string with the complete path to the policy folder
1137 guid
= "{%s}" % guid
1138 policy_path
= os
.path
.join(sysvolpath
, dnsdomain
, "Policies", guid
)
1142 def create_gpo_struct(policy_path
):
1143 if not os
.path
.exists(policy_path
):
1144 os
.makedirs(policy_path
, 0775)
1145 f
= open(os
.path
.join(policy_path
, "GPT.INI"), 'w')
1147 f
.write("[General]\r\nVersion=0")
1150 p
= os
.path
.join(policy_path
, "MACHINE")
1151 if not os
.path
.exists(p
):
1152 os
.makedirs(p
, 0775)
1153 p
= os
.path
.join(policy_path
, "USER")
1154 if not os
.path
.exists(p
):
1155 os
.makedirs(p
, 0775)
1158 def create_default_gpo(sysvolpath
, dnsdomain
, policyguid
, policyguid_dc
):
1159 """Create the default GPO for a domain
1161 :param sysvolpath: Physical path for the sysvol folder
1162 :param dnsdomain: DNS domain name of the AD domain
1163 :param policyguid: GUID of the default domain policy
1164 :param policyguid_dc: GUID of the default domain controler policy
1166 policy_path
= getpolicypath(sysvolpath
,dnsdomain
,policyguid
)
1167 create_gpo_struct(policy_path
)
1169 policy_path
= getpolicypath(sysvolpath
,dnsdomain
,policyguid_dc
)
1170 create_gpo_struct(policy_path
)
1173 def setup_samdb(path
, session_info
, provision_backend
, lp
, names
,
1174 logger
, fill
, serverrole
, schema
, am_rodc
=False):
1175 """Setup a complete SAM Database.
1177 :note: This will wipe the main SAM database file!
1180 # Also wipes the database
1181 setup_samdb_partitions(path
, logger
=logger
, lp
=lp
,
1182 provision_backend
=provision_backend
, session_info
=session_info
,
1183 names
=names
, serverrole
=serverrole
, schema
=schema
)
1185 # Load the database, but don's load the global schema and don't connect
1187 samdb
= SamDB(session_info
=session_info
, url
=None, auto_connect
=False,
1188 credentials
=provision_backend
.credentials
, lp
=lp
,
1189 global_schema
=False, am_rodc
=am_rodc
)
1191 logger
.info("Pre-loading the Samba 4 and AD schema")
1193 # Load the schema from the one we computed earlier
1194 samdb
.set_schema(schema
, write_indices_and_attributes
=False)
1196 # Set the NTDS settings DN manually - in order to have it already around
1197 # before the provisioned tree exists and we connect
1198 samdb
.set_ntds_settings_dn("CN=NTDS Settings,%s" % names
.serverdn
)
1200 # And now we can connect to the DB - the schema won't be loaded from the
1204 # But we have to give it one more kick to have it use the schema
1205 # during provision - it needs, now that it is connected, to write
1206 # the schema @ATTRIBUTES and @INDEXLIST records to the database.
1207 samdb
.set_schema(schema
, write_indices_and_attributes
=True)
1212 def fill_samdb(samdb
, lp
, names
, logger
, domainsid
, domainguid
, policyguid
,
1213 policyguid_dc
, fill
, adminpass
, krbtgtpass
, machinepass
, dns_backend
,
1214 dnspass
, invocationid
, ntdsguid
, serverrole
, am_rodc
=False,
1215 dom_for_fun_level
=None, schema
=None, next_rid
=None, dc_rid
=None):
1217 if next_rid
is None:
1220 # Provision does not make much sense values larger than 1000000000
1221 # as the upper range of the rIDAvailablePool is 1073741823 and
1222 # we don't want to create a domain that cannot allocate rids.
1223 if next_rid
< 1000 or next_rid
> 1000000000:
1224 error
= "You want to run SAMBA 4 with a next_rid of %u, " % (next_rid
)
1225 error
+= "the valid range is %u-%u. The default is %u." % (
1226 1000, 1000000000, 1000)
1227 raise ProvisioningError(error
)
1229 # ATTENTION: Do NOT change these default values without discussion with the
1230 # team and/or release manager. They have a big impact on the whole program!
1231 domainControllerFunctionality
= DS_DOMAIN_FUNCTION_2008_R2
1233 if dom_for_fun_level
is None:
1234 dom_for_fun_level
= DS_DOMAIN_FUNCTION_2003
1236 if dom_for_fun_level
> domainControllerFunctionality
:
1237 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!")
1239 domainFunctionality
= dom_for_fun_level
1240 forestFunctionality
= dom_for_fun_level
1242 # Set the NTDS settings DN manually - in order to have it already around
1243 # before the provisioned tree exists and we connect
1244 samdb
.set_ntds_settings_dn("CN=NTDS Settings,%s" % names
.serverdn
)
1246 samdb
.transaction_start()
1248 # Set the domain functionality levels onto the database.
1249 # Various module (the password_hash module in particular) need
1250 # to know what level of AD we are emulating.
1252 # These will be fixed into the database via the database
1253 # modifictions below, but we need them set from the start.
1254 samdb
.set_opaque_integer("domainFunctionality", domainFunctionality
)
1255 samdb
.set_opaque_integer("forestFunctionality", forestFunctionality
)
1256 samdb
.set_opaque_integer("domainControllerFunctionality",
1257 domainControllerFunctionality
)
1259 samdb
.set_domain_sid(str(domainsid
))
1260 samdb
.set_invocation_id(invocationid
)
1262 logger
.info("Adding DomainDN: %s" % names
.domaindn
)
1264 # impersonate domain admin
1265 admin_session_info
= admin_session(lp
, str(domainsid
))
1266 samdb
.set_session_info(admin_session_info
)
1267 if domainguid
is not None:
1268 domainguid_line
= "objectGUID: %s\n-" % domainguid
1270 domainguid_line
= ""
1272 descr
= b64encode(get_domain_descriptor(domainsid
))
1273 setup_add_ldif(samdb
, setup_path("provision_basedn.ldif"), {
1274 "DOMAINDN": names
.domaindn
,
1275 "DOMAINSID": str(domainsid
),
1276 "DESCRIPTOR": descr
,
1277 "DOMAINGUID": domainguid_line
1280 setup_modify_ldif(samdb
, setup_path("provision_basedn_modify.ldif"), {
1281 "DOMAINDN": names
.domaindn
,
1282 "CREATTIME": str(samba
.unix2nttime(int(time
.time()))),
1283 "NEXTRID": str(next_rid
),
1284 "DEFAULTSITE": names
.sitename
,
1285 "CONFIGDN": names
.configdn
,
1286 "POLICYGUID": policyguid
,
1287 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
),
1288 "SAMBA_VERSION_STRING": version
1291 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1292 if fill
== FILL_FULL
:
1293 logger
.info("Adding configuration container")
1294 descr
= b64encode(get_config_descriptor(domainsid
))
1295 setup_add_ldif(samdb
, setup_path("provision_configuration_basedn.ldif"), {
1296 "CONFIGDN": names
.configdn
,
1297 "DESCRIPTOR": descr
,
1300 # The LDIF here was created when the Schema object was constructed
1301 logger
.info("Setting up sam.ldb schema")
1302 samdb
.add_ldif(schema
.schema_dn_add
, controls
=["relax:0"])
1303 samdb
.modify_ldif(schema
.schema_dn_modify
)
1304 samdb
.write_prefixes_from_schema()
1305 samdb
.add_ldif(schema
.schema_data
, controls
=["relax:0"])
1306 setup_add_ldif(samdb
, setup_path("aggregate_schema.ldif"),
1307 {"SCHEMADN": names
.schemadn
})
1309 # Now register this container in the root of the forest
1310 msg
= ldb
.Message(ldb
.Dn(samdb
, names
.domaindn
))
1311 msg
["subRefs"] = ldb
.MessageElement(names
.configdn
, ldb
.FLAG_MOD_ADD
,
1315 samdb
.transaction_cancel()
1318 samdb
.transaction_commit()
1320 samdb
.transaction_start()
1322 samdb
.invocation_id
= invocationid
1324 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1325 if fill
== FILL_FULL
:
1326 logger
.info("Setting up sam.ldb configuration data")
1328 partitions_descr
= b64encode(get_config_partitions_descriptor(domainsid
))
1329 sites_descr
= b64encode(get_config_sites_descriptor(domainsid
))
1330 ntdsquotas_descr
= b64encode(get_config_ntds_quotas_descriptor(domainsid
))
1331 protected1_descr
= b64encode(get_config_delete_protected1_descriptor(domainsid
))
1332 protected1wd_descr
= b64encode(get_config_delete_protected1wd_descriptor(domainsid
))
1333 protected2_descr
= b64encode(get_config_delete_protected2_descriptor(domainsid
))
1335 setup_add_ldif(samdb
, setup_path("provision_configuration.ldif"), {
1336 "CONFIGDN": names
.configdn
,
1337 "NETBIOSNAME": names
.netbiosname
,
1338 "DEFAULTSITE": names
.sitename
,
1339 "DNSDOMAIN": names
.dnsdomain
,
1340 "DOMAIN": names
.domain
,
1341 "SCHEMADN": names
.schemadn
,
1342 "DOMAINDN": names
.domaindn
,
1343 "SERVERDN": names
.serverdn
,
1344 "FOREST_FUNCTIONALITY": str(forestFunctionality
),
1345 "DOMAIN_FUNCTIONALITY": str(domainFunctionality
),
1346 "NTDSQUOTAS_DESCRIPTOR": ntdsquotas_descr
,
1347 "LOSTANDFOUND_DESCRIPTOR": protected1wd_descr
,
1348 "SERVICES_DESCRIPTOR": protected1_descr
,
1349 "PHYSICALLOCATIONS_DESCRIPTOR": protected1wd_descr
,
1350 "FORESTUPDATES_DESCRIPTOR": protected1wd_descr
,
1351 "EXTENDEDRIGHTS_DESCRIPTOR": protected2_descr
,
1352 "PARTITIONS_DESCRIPTOR": partitions_descr
,
1353 "SITES_DESCRIPTOR": sites_descr
,
1356 logger
.info("Setting up display specifiers")
1357 display_specifiers_ldif
= read_ms_ldif(
1358 setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
1359 display_specifiers_ldif
= substitute_var(display_specifiers_ldif
,
1360 {"CONFIGDN": names
.configdn
})
1361 check_all_substituted(display_specifiers_ldif
)
1362 samdb
.add_ldif(display_specifiers_ldif
)
1364 logger
.info("Modifying display specifiers")
1365 setup_modify_ldif(samdb
,
1366 setup_path("provision_configuration_modify.ldif"), {
1367 "CONFIGDN": names
.configdn
,
1368 "DISPLAYSPECIFIERS_DESCRIPTOR": protected2_descr
1371 logger
.info("Adding users container")
1372 users_desc
= b64encode(get_domain_users_descriptor(domainsid
))
1373 setup_add_ldif(samdb
, setup_path("provision_users_add.ldif"), {
1374 "DOMAINDN": names
.domaindn
,
1375 "USERS_DESCRIPTOR": users_desc
1377 logger
.info("Modifying users container")
1378 setup_modify_ldif(samdb
, setup_path("provision_users_modify.ldif"), {
1379 "DOMAINDN": names
.domaindn
})
1380 logger
.info("Adding computers container")
1381 computers_desc
= b64encode(get_domain_computers_descriptor(domainsid
))
1382 setup_add_ldif(samdb
, setup_path("provision_computers_add.ldif"), {
1383 "DOMAINDN": names
.domaindn
,
1384 "COMPUTERS_DESCRIPTOR": computers_desc
1386 logger
.info("Modifying computers container")
1387 setup_modify_ldif(samdb
,
1388 setup_path("provision_computers_modify.ldif"), {
1389 "DOMAINDN": names
.domaindn
})
1390 logger
.info("Setting up sam.ldb data")
1391 infrastructure_desc
= b64encode(get_domain_infrastructure_descriptor(domainsid
))
1392 lostandfound_desc
= b64encode(get_domain_delete_protected2_descriptor(domainsid
))
1393 system_desc
= b64encode(get_domain_delete_protected1_descriptor(domainsid
))
1394 builtin_desc
= b64encode(get_domain_builtin_descriptor(domainsid
))
1395 controllers_desc
= b64encode(get_domain_controllers_descriptor(domainsid
))
1396 setup_add_ldif(samdb
, setup_path("provision.ldif"), {
1397 "CREATTIME": str(samba
.unix2nttime(int(time
.time()))),
1398 "DOMAINDN": names
.domaindn
,
1399 "NETBIOSNAME": names
.netbiosname
,
1400 "DEFAULTSITE": names
.sitename
,
1401 "CONFIGDN": names
.configdn
,
1402 "SERVERDN": names
.serverdn
,
1403 "RIDAVAILABLESTART": str(next_rid
+ 600),
1404 "POLICYGUID_DC": policyguid_dc
,
1405 "INFRASTRUCTURE_DESCRIPTOR": infrastructure_desc
,
1406 "LOSTANDFOUND_DESCRIPTOR": lostandfound_desc
,
1407 "SYSTEM_DESCRIPTOR": system_desc
,
1408 "BUILTIN_DESCRIPTOR": builtin_desc
,
1409 "DOMAIN_CONTROLLERS_DESCRIPTOR": controllers_desc
,
1412 # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
1413 if fill
== FILL_FULL
:
1414 setup_modify_ldif(samdb
,
1415 setup_path("provision_configuration_references.ldif"), {
1416 "CONFIGDN": names
.configdn
,
1417 "SCHEMADN": names
.schemadn
})
1419 logger
.info("Setting up well known security principals")
1420 protected1wd_descr
= b64encode(get_config_delete_protected1wd_descriptor(domainsid
))
1421 setup_add_ldif(samdb
, setup_path("provision_well_known_sec_princ.ldif"), {
1422 "CONFIGDN": names
.configdn
,
1423 "WELLKNOWNPRINCIPALS_DESCRIPTOR": protected1wd_descr
,
1426 if fill
== FILL_FULL
or fill
== FILL_SUBDOMAIN
:
1427 setup_modify_ldif(samdb
,
1428 setup_path("provision_basedn_references.ldif"),
1429 {"DOMAINDN": names
.domaindn
})
1431 logger
.info("Setting up sam.ldb users and groups")
1432 setup_add_ldif(samdb
, setup_path("provision_users.ldif"), {
1433 "DOMAINDN": names
.domaindn
,
1434 "DOMAINSID": str(domainsid
),
1435 "ADMINPASS_B64": b64encode(adminpass
.encode('utf-16-le')),
1436 "KRBTGTPASS_B64": b64encode(krbtgtpass
.encode('utf-16-le'))
1439 logger
.info("Setting up self join")
1440 setup_self_join(samdb
, admin_session_info
, names
=names
, fill
=fill
,
1441 invocationid
=invocationid
,
1442 dns_backend
=dns_backend
,
1444 machinepass
=machinepass
,
1445 domainsid
=domainsid
,
1448 policyguid
=policyguid
,
1449 policyguid_dc
=policyguid_dc
,
1450 domainControllerFunctionality
=domainControllerFunctionality
,
1453 ntds_dn
= "CN=NTDS Settings,%s" % names
.serverdn
1454 names
.ntdsguid
= samdb
.searchone(basedn
=ntds_dn
,
1455 attribute
="objectGUID", expression
="", scope
=ldb
.SCOPE_BASE
)
1456 assert isinstance(names
.ntdsguid
, str)
1458 samdb
.transaction_cancel()
1461 samdb
.transaction_commit()
1466 FILL_SUBDOMAIN
= "SUBDOMAIN"
1467 FILL_NT4SYNC
= "NT4SYNC"
1469 SYSVOL_ACL
= "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
1470 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)"
1471 SYSVOL_SERVICE
="sysvol"
1473 def set_dir_acl(path
, acl
, lp
, domsid
, use_ntvfs
, passdb
, service
=SYSVOL_SERVICE
):
1474 setntacl(lp
, path
, acl
, domsid
, use_ntvfs
=use_ntvfs
, skip_invalid_chown
=True, passdb
=passdb
, service
=service
)
1475 for root
, dirs
, files
in os
.walk(path
, topdown
=False):
1477 setntacl(lp
, os
.path
.join(root
, name
), acl
, domsid
,
1478 use_ntvfs
=use_ntvfs
, skip_invalid_chown
=True, passdb
=passdb
, service
=service
)
1480 setntacl(lp
, os
.path
.join(root
, name
), acl
, domsid
,
1481 use_ntvfs
=use_ntvfs
, skip_invalid_chown
=True, passdb
=passdb
, service
=service
)
1484 def set_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
, use_ntvfs
, passdb
):
1485 """Set ACL on the sysvol/<dnsname>/Policies folder and the policy
1488 :param sysvol: Physical path for the sysvol folder
1489 :param dnsdomain: The DNS name of the domain
1490 :param domainsid: The SID of the domain
1491 :param domaindn: The DN of the domain (ie. DC=...)
1492 :param samdb: An LDB object on the SAM db
1493 :param lp: an LP object
1496 # Set ACL for GPO root folder
1497 root_policy_path
= os
.path
.join(sysvol
, dnsdomain
, "Policies")
1498 setntacl(lp
, root_policy_path
, POLICIES_ACL
, str(domainsid
),
1499 use_ntvfs
=use_ntvfs
, skip_invalid_chown
=True, passdb
=passdb
, service
=SYSVOL_SERVICE
)
1501 res
= samdb
.search(base
="CN=Policies,CN=System,%s"%(domaindn),
1502 attrs
=["cn", "nTSecurityDescriptor"],
1503 expression
="", scope
=ldb
.SCOPE_ONELEVEL
)
1506 acl
= ndr_unpack(security
.descriptor
,
1507 str(policy
["nTSecurityDescriptor"])).as_sddl()
1508 policy_path
= getpolicypath(sysvol
, dnsdomain
, str(policy
["cn"]))
1509 set_dir_acl(policy_path
, dsacl2fsacl(acl
, domainsid
), lp
,
1510 str(domainsid
), use_ntvfs
,
1514 def setsysvolacl(samdb
, netlogon
, sysvol
, uid
, gid
, domainsid
, dnsdomain
,
1515 domaindn
, lp
, use_ntvfs
):
1516 """Set the ACL for the sysvol share and the subfolders
1518 :param samdb: An LDB object on the SAM db
1519 :param netlogon: Physical path for the netlogon folder
1520 :param sysvol: Physical path for the sysvol folder
1521 :param uid: The UID of the "Administrator" user
1522 :param gid: The GID of the "Domain adminstrators" group
1523 :param domainsid: The SID of the domain
1524 :param dnsdomain: The DNS name of the domain
1525 :param domaindn: The DN of the domain (ie. DC=...)
1530 # This will ensure that the smbd code we are running when setting ACLs
1531 # is initialised with the smb.conf
1532 s3conf
= s3param
.get_context()
1533 s3conf
.load(lp
.configfile
)
1534 # ensure we are using the right samba_dsdb passdb backend, no matter what
1535 s3conf
.set("passdb backend", "samba_dsdb:%s" % samdb
.url
)
1536 passdb
.reload_static_pdb()
1538 # ensure that we init the samba_dsdb backend, so the domain sid is
1539 # marked in secrets.tdb
1540 s4_passdb
= passdb
.PDB(s3conf
.get("passdb backend"))
1542 # now ensure everything matches correctly, to avoid wierd issues
1543 if passdb
.get_global_sam_sid() != domainsid
:
1544 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
))
1546 domain_info
= s4_passdb
.domain_info()
1547 if domain_info
["dom_sid"] != domainsid
:
1548 raise ProvisioningError('SID as seen by pdb_samba_dsdb [%s] does not match SID as seen by the provision script [%s]!' % (domain_info
["dom_sid"], domainsid
))
1550 if domain_info
["dns_domain"].upper() != dnsdomain
.upper():
1551 raise ProvisioningError('Realm as seen by pdb_samba_dsdb [%s] does not match Realm as seen by the provision script [%s]!' % (domain_info
["dns_domain"].upper(), dnsdomain
.upper()))
1556 os
.chown(sysvol
, -1, gid
)
1562 # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
1563 setntacl(lp
,sysvol
, SYSVOL_ACL
, str(domainsid
), use_ntvfs
=use_ntvfs
,
1564 skip_invalid_chown
=True, passdb
=s4_passdb
,
1565 service
=SYSVOL_SERVICE
)
1566 for root
, dirs
, files
in os
.walk(sysvol
, topdown
=False):
1568 if use_ntvfs
and canchown
:
1569 os
.chown(os
.path
.join(root
, name
), -1, gid
)
1570 setntacl(lp
, os
.path
.join(root
, name
), SYSVOL_ACL
, str(domainsid
),
1571 use_ntvfs
=use_ntvfs
, skip_invalid_chown
=True,
1572 passdb
=s4_passdb
, service
=SYSVOL_SERVICE
)
1574 if use_ntvfs
and canchown
:
1575 os
.chown(os
.path
.join(root
, name
), -1, gid
)
1576 setntacl(lp
, os
.path
.join(root
, name
), SYSVOL_ACL
, str(domainsid
),
1577 use_ntvfs
=use_ntvfs
, skip_invalid_chown
=True,
1578 passdb
=s4_passdb
, service
=SYSVOL_SERVICE
)
1580 # Set acls on Policy folder and policies folders
1581 set_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
, use_ntvfs
, passdb
=s4_passdb
)
1583 def acl_type(direct_db_access
):
1584 if direct_db_access
:
1589 def check_dir_acl(path
, acl
, lp
, domainsid
, direct_db_access
):
1590 fsacl
= getntacl(lp
, path
, direct_db_access
=direct_db_access
, service
=SYSVOL_SERVICE
)
1591 fsacl_sddl
= fsacl
.as_sddl(domainsid
)
1592 if fsacl_sddl
!= acl
:
1593 raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access
), path
, fsacl_sddl
, acl
))
1595 for root
, dirs
, files
in os
.walk(path
, topdown
=False):
1597 fsacl
= getntacl(lp
, os
.path
.join(root
, name
),
1598 direct_db_access
=direct_db_access
, service
=SYSVOL_SERVICE
)
1600 raise ProvisioningError('%s ACL on GPO file %s %s not found!' % (acl_type(direct_db_access
), os
.path
.join(root
, name
)))
1601 fsacl_sddl
= fsacl
.as_sddl(domainsid
)
1602 if fsacl_sddl
!= acl
:
1603 raise ProvisioningError('%s ACL on GPO file %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access
), os
.path
.join(root
, name
), fsacl_sddl
, acl
))
1606 fsacl
= getntacl(lp
, os
.path
.join(root
, name
),
1607 direct_db_access
=direct_db_access
, service
=SYSVOL_SERVICE
)
1609 raise ProvisioningError('%s ACL on GPO directory %s %s not found!' % (acl_type(direct_db_access
), os
.path
.join(root
, name
)))
1610 fsacl_sddl
= fsacl
.as_sddl(domainsid
)
1611 if fsacl_sddl
!= acl
:
1612 raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access
), os
.path
.join(root
, name
), fsacl_sddl
, acl
))
1615 def check_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
,
1617 """Set ACL on the sysvol/<dnsname>/Policies folder and the policy
1620 :param sysvol: Physical path for the sysvol folder
1621 :param dnsdomain: The DNS name of the domain
1622 :param domainsid: The SID of the domain
1623 :param domaindn: The DN of the domain (ie. DC=...)
1624 :param samdb: An LDB object on the SAM db
1625 :param lp: an LP object
1628 # Set ACL for GPO root folder
1629 root_policy_path
= os
.path
.join(sysvol
, dnsdomain
, "Policies")
1630 fsacl
= getntacl(lp
, root_policy_path
,
1631 direct_db_access
=direct_db_access
, service
=SYSVOL_SERVICE
)
1633 raise ProvisioningError('DB ACL on policy root %s %s not found!' % (acl_type(direct_db_access
), root_policy_path
))
1634 fsacl_sddl
= fsacl
.as_sddl(domainsid
)
1635 if fsacl_sddl
!= POLICIES_ACL
:
1636 raise ProvisioningError('%s ACL on policy root %s %s does not match expected value %s from provision' % (acl_type(direct_db_access
), root_policy_path
, fsacl_sddl
, fsacl
))
1637 res
= samdb
.search(base
="CN=Policies,CN=System,%s"%(domaindn),
1638 attrs
=["cn", "nTSecurityDescriptor"],
1639 expression
="", scope
=ldb
.SCOPE_ONELEVEL
)
1642 acl
= ndr_unpack(security
.descriptor
,
1643 str(policy
["nTSecurityDescriptor"])).as_sddl()
1644 policy_path
= getpolicypath(sysvol
, dnsdomain
, str(policy
["cn"]))
1645 check_dir_acl(policy_path
, dsacl2fsacl(acl
, domainsid
), lp
,
1646 domainsid
, direct_db_access
)
1649 def checksysvolacl(samdb
, netlogon
, sysvol
, domainsid
, dnsdomain
, domaindn
,
1651 """Set the ACL for the sysvol share and the subfolders
1653 :param samdb: An LDB object on the SAM db
1654 :param netlogon: Physical path for the netlogon folder
1655 :param sysvol: Physical path for the sysvol folder
1656 :param uid: The UID of the "Administrator" user
1657 :param gid: The GID of the "Domain adminstrators" group
1658 :param domainsid: The SID of the domain
1659 :param dnsdomain: The DNS name of the domain
1660 :param domaindn: The DN of the domain (ie. DC=...)
1663 # This will ensure that the smbd code we are running when setting ACLs is initialised with the smb.conf
1664 s3conf
= s3param
.get_context()
1665 s3conf
.load(lp
.configfile
)
1666 # ensure we are using the right samba_dsdb passdb backend, no matter what
1667 s3conf
.set("passdb backend", "samba_dsdb:%s" % samdb
.url
)
1668 # ensure that we init the samba_dsdb backend, so the domain sid is marked in secrets.tdb
1669 s4_passdb
= passdb
.PDB(s3conf
.get("passdb backend"))
1671 # now ensure everything matches correctly, to avoid wierd issues
1672 if passdb
.get_global_sam_sid() != domainsid
:
1673 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
))
1675 domain_info
= s4_passdb
.domain_info()
1676 if domain_info
["dom_sid"] != domainsid
:
1677 raise ProvisioningError('SID as seen by pdb_samba_dsdb [%s] does not match SID as seen by the provision script [%s]!' % (domain_info
["dom_sid"], domainsid
))
1679 if domain_info
["dns_domain"].upper() != dnsdomain
.upper():
1680 raise ProvisioningError('Realm as seen by pdb_samba_dsdb [%s] does not match Realm as seen by the provision script [%s]!' % (domain_info
["dns_domain"].upper(), dnsdomain
.upper()))
1682 # Ensure we can read this directly, and via the smbd VFS
1683 for direct_db_access
in [True, False]:
1684 # Check the SYSVOL_ACL on the sysvol folder and subfolder (first level)
1685 for dir_path
in [os
.path
.join(sysvol
, dnsdomain
), netlogon
]:
1686 fsacl
= getntacl(lp
, dir_path
, direct_db_access
=direct_db_access
, service
=SYSVOL_SERVICE
)
1688 raise ProvisioningError('%s ACL on sysvol directory %s not found!' % (acl_type(direct_db_access
), dir_path
))
1689 fsacl_sddl
= fsacl
.as_sddl(domainsid
)
1690 if fsacl_sddl
!= SYSVOL_ACL
:
1691 raise ProvisioningError('%s ACL on sysvol directory %s %s does not match expected value %s from provision' % (acl_type(direct_db_access
), dir_path
, fsacl_sddl
, SYSVOL_ACL
))
1693 # Check acls on Policy folder and policies folders
1694 check_gpos_acl(sysvol
, dnsdomain
, domainsid
, domaindn
, samdb
, lp
,
1698 def interface_ips_v4(lp
):
1699 """return only IPv4 IPs"""
1700 ips
= samba
.interface_ips(lp
, False)
1703 if i
.find(':') == -1:
1708 def interface_ips_v6(lp
):
1709 """return only IPv6 IPs"""
1710 ips
= samba
.interface_ips(lp
, False)
1713 if i
.find(':') != -1:
1718 def provision_fill(samdb
, secrets_ldb
, logger
, names
, paths
,
1719 domainsid
, schema
=None,
1720 targetdir
=None, samdb_fill
=FILL_FULL
,
1721 hostip
=None, hostip6
=None,
1722 next_rid
=1000, dc_rid
=None, adminpass
=None, krbtgtpass
=None,
1723 domainguid
=None, policyguid
=None, policyguid_dc
=None,
1724 invocationid
=None, machinepass
=None, ntdsguid
=None,
1725 dns_backend
=None, dnspass
=None,
1726 serverrole
=None, dom_for_fun_level
=None,
1727 am_rodc
=False, lp
=None, use_ntvfs
=False, skip_sysvolacl
=False):
1728 # create/adapt the group policy GUIDs
1729 # Default GUID for default policy are described at
1730 # "How Core Group Policy Works"
1731 # http://technet.microsoft.com/en-us/library/cc784268%28WS.10%29.aspx
1732 if policyguid
is None:
1733 policyguid
= DEFAULT_POLICY_GUID
1734 policyguid
= policyguid
.upper()
1735 if policyguid_dc
is None:
1736 policyguid_dc
= DEFAULT_DC_POLICY_GUID
1737 policyguid_dc
= policyguid_dc
.upper()
1739 if invocationid
is None:
1740 invocationid
= str(uuid
.uuid4())
1742 if krbtgtpass
is None:
1743 krbtgtpass
= samba
.generate_random_password(128, 255)
1744 if machinepass
is None:
1745 machinepass
= samba
.generate_random_password(128, 255)
1747 dnspass
= samba
.generate_random_password(128, 255)
1749 samdb
= fill_samdb(samdb
, lp
, names
, logger
=logger
,
1750 domainsid
=domainsid
, schema
=schema
, domainguid
=domainguid
,
1751 policyguid
=policyguid
, policyguid_dc
=policyguid_dc
,
1752 fill
=samdb_fill
, adminpass
=adminpass
, krbtgtpass
=krbtgtpass
,
1753 invocationid
=invocationid
, machinepass
=machinepass
,
1754 dns_backend
=dns_backend
, dnspass
=dnspass
,
1755 ntdsguid
=ntdsguid
, serverrole
=serverrole
,
1756 dom_for_fun_level
=dom_for_fun_level
, am_rodc
=am_rodc
,
1757 next_rid
=next_rid
, dc_rid
=dc_rid
)
1759 if serverrole
== "active directory domain controller":
1761 # Set up group policies (domain policy and domain controller
1763 create_default_gpo(paths
.sysvol
, names
.dnsdomain
, policyguid
,
1765 if not skip_sysvolacl
:
1766 setsysvolacl(samdb
, paths
.netlogon
, paths
.sysvol
, paths
.root_uid
,
1767 paths
.root_gid
, domainsid
, names
.dnsdomain
,
1768 names
.domaindn
, lp
, use_ntvfs
)
1770 logger
.info("Setting acl on sysvol skipped")
1772 secretsdb_self_join(secrets_ldb
, domain
=names
.domain
,
1773 realm
=names
.realm
, dnsdomain
=names
.dnsdomain
,
1774 netbiosname
=names
.netbiosname
, domainsid
=domainsid
,
1775 machinepass
=machinepass
, secure_channel_type
=SEC_CHAN_BDC
)
1777 # Now set up the right msDS-SupportedEncryptionTypes into the DB
1778 # In future, this might be determined from some configuration
1779 kerberos_enctypes
= str(ENC_ALL_TYPES
)
1782 msg
= ldb
.Message(ldb
.Dn(samdb
,
1783 samdb
.searchone("distinguishedName",
1784 expression
="samAccountName=%s$" % names
.netbiosname
,
1785 scope
=ldb
.SCOPE_SUBTREE
)))
1786 msg
["msDS-SupportedEncryptionTypes"] = ldb
.MessageElement(
1787 elements
=kerberos_enctypes
, flags
=ldb
.FLAG_MOD_REPLACE
,
1788 name
="msDS-SupportedEncryptionTypes")
1790 except ldb
.LdbError
, (enum
, estr
):
1791 if enum
!= ldb
.ERR_NO_SUCH_ATTRIBUTE
:
1792 # It might be that this attribute does not exist in this schema
1795 setup_ad_dns(samdb
, secrets_ldb
, domainsid
, names
, paths
, lp
, logger
,
1796 hostip
=hostip
, hostip6
=hostip6
, dns_backend
=dns_backend
,
1797 dnspass
=dnspass
, os_level
=dom_for_fun_level
,
1798 targetdir
=targetdir
, site
=DEFAULTSITE
)
1800 domainguid
= samdb
.searchone(basedn
=samdb
.get_default_basedn(),
1801 attribute
="objectGUID")
1802 assert isinstance(domainguid
, str)
1804 lastProvisionUSNs
= get_last_provision_usn(samdb
)
1805 maxUSN
= get_max_usn(samdb
, str(names
.rootdn
))
1806 if lastProvisionUSNs
is not None:
1807 update_provision_usn(samdb
, 0, maxUSN
, invocationid
, 1)
1809 set_provision_usn(samdb
, 0, maxUSN
, invocationid
)
1811 logger
.info("Setting up sam.ldb rootDSE marking as synchronized")
1812 setup_modify_ldif(samdb
, setup_path("provision_rootdse_modify.ldif"),
1813 { 'NTDSGUID' : names
.ntdsguid
})
1815 # fix any dangling GUIDs from the provision
1816 logger
.info("Fixing provision GUIDs")
1817 chk
= dbcheck(samdb
, samdb_schema
=samdb
, verbose
=False, fix
=True, yes
=True,
1819 samdb
.transaction_start()
1821 # a small number of GUIDs are missing because of ordering issues in the
1823 for schema_obj
in ['CN=Domain', 'CN=Organizational-Person', 'CN=Contact', 'CN=inetOrgPerson']:
1824 chk
.check_database(DN
="%s,%s" % (schema_obj
, names
.schemadn
),
1825 scope
=ldb
.SCOPE_BASE
,
1826 attrs
=['defaultObjectCategory'])
1827 chk
.check_database(DN
="CN=IP Security,CN=System,%s" % names
.domaindn
,
1828 scope
=ldb
.SCOPE_ONELEVEL
,
1829 attrs
=['ipsecOwnersReference',
1830 'ipsecFilterReference',
1831 'ipsecISAKMPReference',
1832 'ipsecNegotiationPolicyReference',
1833 'ipsecNFAReference'])
1835 samdb
.transaction_cancel()
1838 samdb
.transaction_commit()
1842 "ROLE_STANDALONE": "standalone server",
1843 "ROLE_DOMAIN_MEMBER": "member server",
1844 "ROLE_DOMAIN_BDC": "active directory domain controller",
1845 "ROLE_DOMAIN_PDC": "active directory domain controller",
1846 "dc": "active directory domain controller",
1847 "member": "member server",
1848 "domain controller": "active directory domain controller",
1849 "active directory domain controller": "active directory domain controller",
1850 "member server": "member server",
1851 "standalone": "standalone server",
1852 "standalone server": "standalone server",
1856 def sanitize_server_role(role
):
1857 """Sanitize a server role name.
1859 :param role: Server role
1860 :raise ValueError: If the role can not be interpreted
1861 :return: Sanitized server role (one of "member server",
1862 "active directory domain controller", "standalone server")
1865 return _ROLES_MAP
[role
]
1867 raise ValueError(role
)
1870 def provision_fake_ypserver(logger
, samdb
, domaindn
, netbiosname
, nisdomain
,
1872 """Create AD entries for the fake ypserver.
1874 This is needed for being able to manipulate posix attrs via ADUC.
1876 samdb
.transaction_start()
1878 logger
.info("Setting up fake yp server settings")
1879 setup_add_ldif(samdb
, setup_path("ypServ30.ldif"), {
1880 "DOMAINDN": domaindn
,
1881 "NETBIOSNAME": netbiosname
,
1882 "NISDOMAIN": nisdomain
,
1885 samdb
.transaction_cancel()
1888 samdb
.transaction_commit()
1891 def provision(logger
, session_info
, credentials
, smbconf
=None,
1892 targetdir
=None, samdb_fill
=FILL_FULL
, realm
=None, rootdn
=None,
1893 domaindn
=None, schemadn
=None, configdn
=None, serverdn
=None,
1894 domain
=None, hostname
=None, hostip
=None, hostip6
=None, domainsid
=None,
1895 next_rid
=1000, dc_rid
=None, adminpass
=None, ldapadminpass
=None,
1896 krbtgtpass
=None, domainguid
=None, policyguid
=None, policyguid_dc
=None,
1897 dns_backend
=None, dns_forwarder
=None, dnspass
=None,
1898 invocationid
=None, machinepass
=None, ntdsguid
=None,
1899 root
=None, nobody
=None, users
=None, backup
=None, aci
=None,
1900 serverrole
=None, dom_for_fun_level
=None, backend_type
=None,
1901 sitename
=None, ol_mmr_urls
=None, ol_olc
=None, slapd_path
=None,
1902 useeadb
=False, am_rodc
=False, lp
=None, use_ntvfs
=False,
1903 use_rfc2307
=False, maxuid
=None, maxgid
=None, skip_sysvolacl
=True,
1904 ldap_backend_forced_uri
=None, nosync
=False, ldap_dryrun_mode
=False, ldap_backend_extra_port
=None):
1907 :note: caution, this wipes all existing data!
1911 serverrole
= sanitize_server_role(serverrole
)
1913 raise ProvisioningError('server role (%s) should be one of "active directory domain controller", "member server", "standalone server"' % serverrole
)
1915 if ldapadminpass
is None:
1916 # Make a new, random password between Samba and it's LDAP server
1917 ldapadminpass
= samba
.generate_random_password(128, 255)
1919 if backend_type
is None:
1920 backend_type
= "ldb"
1922 if domainsid
is None:
1923 domainsid
= security
.random_sid()
1925 domainsid
= security
.dom_sid(domainsid
)
1927 root_uid
= findnss_uid([root
or "root"])
1928 nobody_uid
= findnss_uid([nobody
or "nobody"])
1929 users_gid
= findnss_gid([users
or "users", 'users', 'other', 'staff'])
1930 root_gid
= pwd
.getpwuid(root_uid
).pw_gid
1933 bind_gid
= findnss_gid(["bind", "named"])
1937 if targetdir
is not None:
1938 smbconf
= os
.path
.join(targetdir
, "etc", "smb.conf")
1939 elif smbconf
is None:
1940 smbconf
= samba
.param
.default_path()
1941 if not os
.path
.exists(os
.path
.dirname(smbconf
)):
1942 os
.makedirs(os
.path
.dirname(smbconf
))
1944 server_services
= []
1947 global_param
["idmap_ldb:use rfc2307"] = ["yes"]
1949 if dns_backend
!= "SAMBA_INTERNAL":
1950 server_services
.append("-dns")
1952 if dns_forwarder
is not None:
1953 global_param
["dns forwarder"] = [dns_forwarder
]
1956 server_services
.append("+smb")
1957 server_services
.append("-s3fs")
1958 global_param
["dcerpc endpoint servers"] = ["+winreg", "+srvsvc"]
1960 if len(server_services
) > 0:
1961 global_param
["server services"] = server_services
1963 # only install a new smb.conf if there isn't one there already
1964 if os
.path
.exists(smbconf
):
1965 # if Samba Team members can't figure out the weird errors
1966 # loading an empty smb.conf gives, then we need to be smarter.
1967 # Pretend it just didn't exist --abartlet
1968 f
= open(smbconf
, 'r')
1970 data
= f
.read().lstrip()
1973 if data
is None or data
== "":
1974 make_smbconf(smbconf
, hostname
, domain
, realm
,
1975 targetdir
, serverrole
=serverrole
,
1976 eadb
=useeadb
, use_ntvfs
=use_ntvfs
,
1977 lp
=lp
, global_param
=global_param
)
1979 make_smbconf(smbconf
, hostname
, domain
, realm
, targetdir
,
1980 serverrole
=serverrole
,
1981 eadb
=useeadb
, use_ntvfs
=use_ntvfs
, lp
=lp
, global_param
=global_param
)
1984 lp
= samba
.param
.LoadParm()
1986 names
= guess_names(lp
=lp
, hostname
=hostname
, domain
=domain
,
1987 dnsdomain
=realm
, serverrole
=serverrole
, domaindn
=domaindn
,
1988 configdn
=configdn
, schemadn
=schemadn
, serverdn
=serverdn
,
1989 sitename
=sitename
, rootdn
=rootdn
, domain_names_forced
=(samdb_fill
== FILL_DRS
))
1990 paths
= provision_paths_from_lp(lp
, names
.dnsdomain
)
1992 paths
.bind_gid
= bind_gid
1993 paths
.root_uid
= root_uid
;
1994 paths
.root_gid
= root_gid
1997 logger
.info("Looking up IPv4 addresses")
1998 hostips
= interface_ips_v4(lp
)
1999 if len(hostips
) > 0:
2001 if len(hostips
) > 1:
2002 logger
.warning("More than one IPv4 address found. Using %s",
2004 if hostip
== "127.0.0.1":
2007 logger
.warning("No IPv4 address will be assigned")
2010 logger
.info("Looking up IPv6 addresses")
2011 hostips
= interface_ips_v6(lp
)
2013 hostip6
= hostips
[0]
2014 if len(hostips
) > 1:
2015 logger
.warning("More than one IPv6 address found. Using %s", hostip6
)
2017 logger
.warning("No IPv6 address will be assigned")
2019 names
.hostip
= hostip
2020 names
.hostip6
= hostip6
2022 if serverrole
is None:
2023 serverrole
= lp
.get("server role")
2025 if not os
.path
.exists(paths
.private_dir
):
2026 os
.mkdir(paths
.private_dir
)
2027 if not os
.path
.exists(os
.path
.join(paths
.private_dir
, "tls")):
2028 os
.mkdir(os
.path
.join(paths
.private_dir
, "tls"))
2029 if not os
.path
.exists(paths
.state_dir
):
2030 os
.mkdir(paths
.state_dir
)
2032 if paths
.sysvol
and not os
.path
.exists(paths
.sysvol
):
2033 os
.makedirs(paths
.sysvol
, 0775)
2035 if not use_ntvfs
and serverrole
== "active directory domain controller":
2036 s3conf
= s3param
.get_context()
2037 s3conf
.load(lp
.configfile
)
2039 if paths
.sysvol
is None:
2040 raise MissingShareError("sysvol", paths
.smbconf
)
2042 file = tempfile
.NamedTemporaryFile(dir=os
.path
.abspath(paths
.sysvol
))
2045 smbd
.set_simple_acl(file.name
, 0755, root_gid
)
2047 if not smbd
.have_posix_acls():
2048 # This clue is only strictly correct for RPM and
2049 # Debian-like Linux systems, but hopefully other users
2050 # will get enough clue from it.
2051 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.")
2053 raise ProvisioningError("Your filesystem or build does not support posix ACLs, which s3fs requires. Try the mounting the filesystem with the 'acl' option.")
2055 smbd
.chown(file.name
, root_uid
, root_gid
)
2057 raise ProvisioningError("Unable to chown a file on your filesystem. You may not be running provision as root.")
2061 ldapi_url
= "ldapi://%s" % urllib
.quote(paths
.s4_ldapi_path
, safe
="")
2063 schema
= Schema(domainsid
, invocationid
=invocationid
,
2064 schemadn
=names
.schemadn
)
2066 if backend_type
== "ldb":
2067 provision_backend
= LDBBackend(backend_type
, paths
=paths
,
2068 lp
=lp
, credentials
=credentials
,
2069 names
=names
, logger
=logger
)
2070 elif backend_type
== "existing":
2071 # If support for this is ever added back, then the URI will need to be
2073 provision_backend
= ExistingBackend(backend_type
, paths
=paths
,
2074 lp
=lp
, credentials
=credentials
,
2075 names
=names
, logger
=logger
,
2076 ldap_backend_forced_uri
=ldap_backend_forced_uri
)
2077 elif backend_type
== "fedora-ds":
2078 provision_backend
= FDSBackend(backend_type
, paths
=paths
,
2079 lp
=lp
, credentials
=credentials
,
2080 names
=names
, logger
=logger
, domainsid
=domainsid
,
2081 schema
=schema
, hostname
=hostname
, ldapadminpass
=ldapadminpass
,
2082 slapd_path
=slapd_path
,
2084 elif backend_type
== "openldap":
2085 provision_backend
= OpenLDAPBackend(backend_type
, paths
=paths
,
2086 lp
=lp
, credentials
=credentials
,
2087 names
=names
, logger
=logger
, domainsid
=domainsid
,
2088 schema
=schema
, hostname
=hostname
, ldapadminpass
=ldapadminpass
,
2089 slapd_path
=slapd_path
, ol_mmr_urls
=ol_mmr_urls
,
2090 ldap_backend_extra_port
=ldap_backend_extra_port
,
2091 ldap_dryrun_mode
=ldap_dryrun_mode
, nosync
=nosync
,
2092 ldap_backend_forced_uri
=ldap_backend_forced_uri
)
2094 raise ValueError("Unknown LDAP backend type selected")
2096 provision_backend
.init()
2097 provision_backend
.start()
2099 # only install a new shares config db if there is none
2100 if not os
.path
.exists(paths
.shareconf
):
2101 logger
.info("Setting up share.ldb")
2102 share_ldb
= Ldb(paths
.shareconf
, session_info
=session_info
, lp
=lp
)
2103 share_ldb
.load_ldif_file_add(setup_path("share.ldif"))
2105 logger
.info("Setting up secrets.ldb")
2106 secrets_ldb
= setup_secretsdb(paths
,
2107 session_info
=session_info
,
2108 backend_credentials
=provision_backend
.secrets_credentials
, lp
=lp
)
2111 logger
.info("Setting up the registry")
2112 setup_registry(paths
.hklm
, session_info
, lp
=lp
)
2114 logger
.info("Setting up the privileges database")
2115 setup_privileges(paths
.privilege
, session_info
, lp
=lp
)
2117 logger
.info("Setting up idmap db")
2118 idmap
= setup_idmapdb(paths
.idmapdb
, session_info
=session_info
, lp
=lp
)
2120 setup_name_mappings(idmap
, sid
=str(domainsid
),
2121 root_uid
=root_uid
, nobody_uid
=nobody_uid
,
2122 users_gid
=users_gid
, root_gid
=root_gid
)
2124 logger
.info("Setting up SAM db")
2125 samdb
= setup_samdb(paths
.samdb
, session_info
,
2126 provision_backend
, lp
, names
, logger
=logger
,
2127 serverrole
=serverrole
,
2128 schema
=schema
, fill
=samdb_fill
, am_rodc
=am_rodc
)
2130 if serverrole
== "active directory domain controller":
2131 if paths
.netlogon
is None:
2132 raise MissingShareError("netlogon", paths
.smbconf
)
2134 if paths
.sysvol
is None:
2135 raise MissingShareError("sysvol", paths
.smbconf
)
2137 if not os
.path
.isdir(paths
.netlogon
):
2138 os
.makedirs(paths
.netlogon
, 0755)
2140 if adminpass
is None:
2141 adminpass
= samba
.generate_random_password(12, 32)
2142 adminpass_generated
= True
2144 adminpass
= unicode(adminpass
, 'utf-8')
2145 adminpass_generated
= False
2147 if samdb_fill
== FILL_FULL
:
2148 provision_fill(samdb
, secrets_ldb
, logger
, names
, paths
,
2149 schema
=schema
, targetdir
=targetdir
, samdb_fill
=samdb_fill
,
2150 hostip
=hostip
, hostip6
=hostip6
, domainsid
=domainsid
,
2151 next_rid
=next_rid
, dc_rid
=dc_rid
, adminpass
=adminpass
,
2152 krbtgtpass
=krbtgtpass
, domainguid
=domainguid
,
2153 policyguid
=policyguid
, policyguid_dc
=policyguid_dc
,
2154 invocationid
=invocationid
, machinepass
=machinepass
,
2155 ntdsguid
=ntdsguid
, dns_backend
=dns_backend
,
2156 dnspass
=dnspass
, serverrole
=serverrole
,
2157 dom_for_fun_level
=dom_for_fun_level
, am_rodc
=am_rodc
,
2158 lp
=lp
, use_ntvfs
=use_ntvfs
,
2159 skip_sysvolacl
=skip_sysvolacl
)
2161 create_krb5_conf(paths
.krb5conf
,
2162 dnsdomain
=names
.dnsdomain
, hostname
=names
.hostname
,
2164 logger
.info("A Kerberos configuration suitable for Samba 4 has been "
2165 "generated at %s", paths
.krb5conf
)
2167 if serverrole
== "active directory domain controller":
2168 create_dns_update_list(lp
, logger
, paths
)
2170 backend_result
= provision_backend
.post_setup()
2171 provision_backend
.shutdown()
2174 secrets_ldb
.transaction_cancel()
2177 # Now commit the secrets.ldb to disk
2178 secrets_ldb
.transaction_commit()
2180 # the commit creates the dns.keytab, now chown it
2181 dns_keytab_path
= os
.path
.join(paths
.private_dir
, paths
.dns_keytab
)
2182 if os
.path
.isfile(dns_keytab_path
) and paths
.bind_gid
is not None:
2184 os
.chmod(dns_keytab_path
, 0640)
2185 os
.chown(dns_keytab_path
, -1, paths
.bind_gid
)
2187 if not os
.environ
.has_key('SAMBA_SELFTEST'):
2188 logger
.info("Failed to chown %s to bind gid %u",
2189 dns_keytab_path
, paths
.bind_gid
)
2191 result
= ProvisionResult()
2192 result
.server_role
= serverrole
2193 result
.domaindn
= domaindn
2194 result
.paths
= paths
2195 result
.names
= names
2197 result
.samdb
= samdb
2198 result
.idmap
= idmap
2199 result
.domainsid
= str(domainsid
)
2201 if samdb_fill
== FILL_FULL
:
2202 result
.adminpass_generated
= adminpass_generated
2203 result
.adminpass
= adminpass
2205 result
.adminpass_generated
= False
2206 result
.adminpass
= None
2208 result
.backend_result
= backend_result
2211 provision_fake_ypserver(logger
=logger
, samdb
=samdb
,
2212 domaindn
=names
.domaindn
, netbiosname
=names
.netbiosname
,
2213 nisdomain
=names
.domain
.lower(), maxuid
=maxuid
, maxgid
=maxgid
)
2218 def provision_become_dc(smbconf
=None, targetdir
=None,
2219 realm
=None, rootdn
=None, domaindn
=None, schemadn
=None, configdn
=None,
2220 serverdn
=None, domain
=None, hostname
=None, domainsid
=None,
2221 adminpass
=None, krbtgtpass
=None, domainguid
=None, policyguid
=None,
2222 policyguid_dc
=None, invocationid
=None, machinepass
=None, dnspass
=None,
2223 dns_backend
=None, root
=None, nobody
=None, users
=None,
2224 backup
=None, serverrole
=None, ldap_backend
=None,
2225 ldap_backend_type
=None, sitename
=None, debuglevel
=1, use_ntvfs
=False):
2227 logger
= logging
.getLogger("provision")
2228 samba
.set_debug_level(debuglevel
)
2230 res
= provision(logger
, system_session(), None,
2231 smbconf
=smbconf
, targetdir
=targetdir
, samdb_fill
=FILL_DRS
,
2232 realm
=realm
, rootdn
=rootdn
, domaindn
=domaindn
, schemadn
=schemadn
,
2233 configdn
=configdn
, serverdn
=serverdn
, domain
=domain
,
2234 hostname
=hostname
, hostip
=None, domainsid
=domainsid
,
2235 machinepass
=machinepass
,
2236 serverrole
="active directory domain controller",
2237 sitename
=sitename
, dns_backend
=dns_backend
, dnspass
=dnspass
,
2238 use_ntvfs
=use_ntvfs
)
2239 res
.lp
.set("debuglevel", str(debuglevel
))
2243 def create_krb5_conf(path
, dnsdomain
, hostname
, realm
):
2244 """Write out a file containing zone statements suitable for inclusion in a
2245 named.conf file (including GSS-TSIG configuration).
2247 :param path: Path of the new named.conf file.
2248 :param dnsdomain: DNS Domain name
2249 :param hostname: Local hostname
2250 :param realm: Realm name
2252 setup_file(setup_path("krb5.conf"), path
, {
2253 "DNSDOMAIN": dnsdomain
,
2254 "HOSTNAME": hostname
,
2259 class ProvisioningError(Exception):
2260 """A generic provision error."""
2262 def __init__(self
, value
):
2266 return "ProvisioningError: " + self
.value
2269 class InvalidNetbiosName(Exception):
2270 """A specified name was not a valid NetBIOS name."""
2272 def __init__(self
, name
):
2273 super(InvalidNetbiosName
, self
).__init
__(
2274 "The name '%r' is not a valid NetBIOS name" % name
)
2277 class MissingShareError(ProvisioningError
):
2279 def __init__(self
, name
, smbconf
):
2280 super(MissingShareError
, self
).__init
__(
2281 "Existing smb.conf does not have a [%s] share, but you are "
2282 "configuring a DC. Please remove %s or add the share manually." %