2 # Copyright Andrew Tridgell 2010
3 # Copyright Andrew Bartlett 2010
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 """Joining a domain."""
21 from samba
.auth
import system_session
22 from samba
.samdb
import SamDB
23 from samba
import gensec
, Ldb
, drs_utils
24 import ldb
, samba
, sys
, uuid
25 from samba
.ndr
import ndr_pack
26 from samba
.dcerpc
import security
, drsuapi
, misc
, nbt
, lsa
, drsblobs
27 from samba
.credentials
import Credentials
, DONT_USE_KERBEROS
28 from samba
.provision
import secretsdb_self_join
, provision
, provision_fill
, FILL_DRS
, FILL_SUBDOMAIN
29 from samba
.schema
import Schema
30 from samba
.net
import Net
31 from samba
.provision
.sambadns
import setup_bind9_dns
37 # this makes debugging easier
38 talloc
.enable_null_tracking()
40 class DCJoinException(Exception):
42 def __init__(self
, msg
):
43 super(DCJoinException
, self
).__init
__("Can't join, error: %s" % msg
)
46 class dc_join(object):
47 '''perform a DC join'''
49 def __init__(ctx
, server
=None, creds
=None, lp
=None, site
=None,
50 netbios_name
=None, targetdir
=None, domain
=None,
51 machinepass
=None, use_ntvfs
=False, dns_backend
=None,
52 promote_existing
=False):
56 ctx
.netbios_name
= netbios_name
57 ctx
.targetdir
= targetdir
58 ctx
.use_ntvfs
= use_ntvfs
59 if dns_backend
is None:
60 ctx
.dns_backend
= "NONE"
62 ctx
.dns_backend
= dns_backend
64 ctx
.promote_existing
= promote_existing
65 ctx
.promote_from_dn
= None
70 ctx
.creds
.set_gensec_features(creds
.get_gensec_features() | gensec
.FEATURE_SEAL
)
71 ctx
.net
= Net(creds
=ctx
.creds
, lp
=ctx
.lp
)
73 if server
is not None:
76 print("Finding a writeable DC for domain '%s'" % domain
)
77 ctx
.server
= ctx
.find_dc(domain
)
78 print("Found DC %s" % ctx
.server
)
80 ctx
.samdb
= SamDB(url
="ldap://%s" % ctx
.server
,
81 session_info
=system_session(),
82 credentials
=ctx
.creds
, lp
=ctx
.lp
)
85 ctx
.samdb
.search(scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["dn"])
86 except ldb
.LdbError
, (enum
, estr
):
87 raise DCJoinException(estr
)
90 ctx
.myname
= netbios_name
91 ctx
.samname
= "%s$" % ctx
.myname
92 ctx
.base_dn
= str(ctx
.samdb
.get_default_basedn())
93 ctx
.root_dn
= str(ctx
.samdb
.get_root_basedn())
94 ctx
.schema_dn
= str(ctx
.samdb
.get_schema_basedn())
95 ctx
.config_dn
= str(ctx
.samdb
.get_config_basedn())
96 ctx
.domsid
= ctx
.samdb
.get_domain_sid()
97 ctx
.domain_name
= ctx
.get_domain_name()
98 ctx
.forest_domain_name
= ctx
.get_forest_domain_name()
99 ctx
.invocation_id
= misc
.GUID(str(uuid
.uuid4()))
101 ctx
.dc_ntds_dn
= ctx
.samdb
.get_dsServiceName()
102 ctx
.dc_dnsHostName
= ctx
.get_dnsHostName()
103 ctx
.behavior_version
= ctx
.get_behavior_version()
105 if machinepass
is not None:
106 ctx
.acct_pass
= machinepass
108 ctx
.acct_pass
= samba
.generate_random_password(32, 40)
110 # work out the DNs of all the objects we will be adding
111 ctx
.server_dn
= "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (ctx
.myname
, ctx
.site
, ctx
.config_dn
)
112 ctx
.ntds_dn
= "CN=NTDS Settings,%s" % ctx
.server_dn
113 topology_base
= "CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System,%s" % ctx
.base_dn
114 if ctx
.dn_exists(topology_base
):
115 ctx
.topology_dn
= "CN=%s,%s" % (ctx
.myname
, topology_base
)
117 ctx
.topology_dn
= None
119 ctx
.dnsdomain
= ctx
.samdb
.domain_dns_name()
120 ctx
.dnsforest
= ctx
.samdb
.forest_dns_name()
121 ctx
.dnshostname
= "%s.%s" % (ctx
.myname
, ctx
.dnsdomain
)
123 ctx
.realm
= ctx
.dnsdomain
125 ctx
.acct_dn
= "CN=%s,OU=Domain Controllers,%s" % (ctx
.myname
, ctx
.base_dn
)
129 ctx
.SPNs
= [ "HOST/%s" % ctx
.myname
,
130 "HOST/%s" % ctx
.dnshostname
,
131 "GC/%s/%s" % (ctx
.dnshostname
, ctx
.dnsforest
) ]
133 # these elements are optional
134 ctx
.never_reveal_sid
= None
135 ctx
.reveal_sid
= None
136 ctx
.connection_dn
= None
141 ctx
.subdomain
= False
143 def del_noerror(ctx
, dn
, recursive
=False):
146 res
= ctx
.samdb
.search(base
=dn
, scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["dn"])
150 ctx
.del_noerror(r
.dn
, recursive
=True)
153 print "Deleted %s" % dn
157 def cleanup_old_join(ctx
):
158 '''remove any DNs from a previous join'''
160 # find the krbtgt link
161 print("checking sAMAccountName")
165 res
= ctx
.samdb
.search(base
=ctx
.samdb
.get_default_basedn(),
166 expression
='sAMAccountName=%s' % ldb
.binary_encode(ctx
.samname
),
167 attrs
=["msDS-krbTgtLink"])
169 ctx
.del_noerror(res
[0].dn
, recursive
=True)
170 if ctx
.connection_dn
is not None:
171 ctx
.del_noerror(ctx
.connection_dn
)
172 if ctx
.krbtgt_dn
is not None:
173 ctx
.del_noerror(ctx
.krbtgt_dn
)
174 ctx
.del_noerror(ctx
.ntds_dn
)
175 ctx
.del_noerror(ctx
.server_dn
, recursive
=True)
177 ctx
.del_noerror(ctx
.topology_dn
)
179 ctx
.del_noerror(ctx
.partition_dn
)
181 ctx
.new_krbtgt_dn
= res
[0]["msDS-Krbtgtlink"][0]
182 ctx
.del_noerror(ctx
.new_krbtgt_dn
)
185 binding_options
= "sign"
186 lsaconn
= lsa
.lsarpc("ncacn_ip_tcp:%s[%s]" % (ctx
.server
, binding_options
),
189 objectAttr
= lsa
.ObjectAttribute()
190 objectAttr
.sec_qos
= lsa
.QosInfo()
192 pol_handle
= lsaconn
.OpenPolicy2(''.decode('utf-8'),
193 objectAttr
, security
.SEC_FLAG_MAXIMUM_ALLOWED
)
196 name
.string
= ctx
.realm
197 info
= lsaconn
.QueryTrustedDomainInfoByName(pol_handle
, name
, lsa
.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO
)
199 lsaconn
.DeleteTrustedDomain(pol_handle
, info
.info_ex
.sid
)
202 name
.string
= ctx
.forest_domain_name
203 info
= lsaconn
.QueryTrustedDomainInfoByName(pol_handle
, name
, lsa
.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO
)
205 lsaconn
.DeleteTrustedDomain(pol_handle
, info
.info_ex
.sid
)
210 def promote_possible(ctx
):
211 '''confirm that the account is just a bare NT4 BDC or a member server, so can be safely promoted'''
213 # This shouldn't happen
214 raise Exception("Can not promote into a subdomain")
216 res
= ctx
.samdb
.search(base
=ctx
.samdb
.get_default_basedn(),
217 expression
='sAMAccountName=%s' % ldb
.binary_encode(ctx
.samname
),
218 attrs
=["msDS-krbTgtLink", "userAccountControl", "serverReferenceBL", "rIDSetReferences"])
220 raise Exception("Could not find domain member account '%s' to promote to a DC, use 'samba-tool domain join' instead'" % ctx
.samname
)
221 if "msDS-krbTgtLink" in res
[0] or "serverReferenceBL" in res
[0] or "rIDSetReferences" in res
[0]:
222 raise Exception("Account '%s' appears to be an active DC, use 'samba-tool domain join' if you must re-create this account" % ctx
.samname
)
223 if (int(res
[0]["userAccountControl"][0]) & (samba
.dsdb
.UF_WORKSTATION_TRUST_ACCOUNT|samba
.dsdb
.UF_SERVER_TRUST_ACCOUNT
) == 0):
224 raise Exception("Account %s is not a domain member or a bare NT4 BDC, use 'samba-tool domain join' instead'" % ctx
.samname
)
226 ctx
.promote_from_dn
= res
[0].dn
229 def find_dc(ctx
, domain
):
230 '''find a writeable DC for the given domain'''
232 ctx
.cldap_ret
= ctx
.net
.finddc(domain
=domain
, flags
=nbt
.NBT_SERVER_LDAP | nbt
.NBT_SERVER_DS | nbt
.NBT_SERVER_WRITABLE
)
234 raise Exception("Failed to find a writeable DC for domain '%s'" % domain
)
235 if ctx
.cldap_ret
.client_site
is not None and ctx
.cldap_ret
.client_site
!= "":
236 ctx
.site
= ctx
.cldap_ret
.client_site
237 return ctx
.cldap_ret
.pdc_dns_name
240 def get_behavior_version(ctx
):
241 res
= ctx
.samdb
.search(base
=ctx
.base_dn
, scope
=ldb
.SCOPE_BASE
, attrs
=["msDS-Behavior-Version"])
242 if "msDS-Behavior-Version" in res
[0]:
243 return int(res
[0]["msDS-Behavior-Version"][0])
245 return samba
.dsdb
.DS_DOMAIN_FUNCTION_2000
247 def get_dnsHostName(ctx
):
248 res
= ctx
.samdb
.search(base
="", scope
=ldb
.SCOPE_BASE
, attrs
=["dnsHostName"])
249 return res
[0]["dnsHostName"][0]
251 def get_domain_name(ctx
):
252 '''get netbios name of the domain from the partitions record'''
253 partitions_dn
= ctx
.samdb
.get_partitions_dn()
254 res
= ctx
.samdb
.search(base
=partitions_dn
, scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["nETBIOSName"],
255 expression
='ncName=%s' % ctx
.samdb
.get_default_basedn())
256 return res
[0]["nETBIOSName"][0]
258 def get_forest_domain_name(ctx
):
259 '''get netbios name of the domain from the partitions record'''
260 partitions_dn
= ctx
.samdb
.get_partitions_dn()
261 res
= ctx
.samdb
.search(base
=partitions_dn
, scope
=ldb
.SCOPE_ONELEVEL
, attrs
=["nETBIOSName"],
262 expression
='ncName=%s' % ctx
.samdb
.get_root_basedn())
263 return res
[0]["nETBIOSName"][0]
265 def get_parent_partition_dn(ctx
):
266 '''get the parent domain partition DN from parent DNS name'''
267 res
= ctx
.samdb
.search(base
=ctx
.config_dn
, attrs
=[],
268 expression
='(&(objectclass=crossRef)(dnsRoot=%s)(systemFlags:%s:=%u))' %
269 (ctx
.parent_dnsdomain
, ldb
.OID_COMPARATOR_AND
, samba
.dsdb
.SYSTEM_FLAG_CR_NTDS_DOMAIN
))
270 return str(res
[0].dn
)
272 def get_naming_master(ctx
):
273 '''get the parent domain partition DN from parent DNS name'''
274 res
= ctx
.samdb
.search(base
='CN=Partitions,%s' % ctx
.config_dn
, attrs
=['fSMORoleOwner'],
275 scope
=ldb
.SCOPE_BASE
, controls
=["extended_dn:1:1"])
276 if not 'fSMORoleOwner' in res
[0]:
277 raise DCJoinException("Can't find naming master on partition DN %s" % ctx
.partition_dn
)
278 master_guid
= str(misc
.GUID(ldb
.Dn(ctx
.samdb
, res
[0]['fSMORoleOwner'][0]).get_extended_component('GUID')))
279 master_host
= '%s._msdcs.%s' % (master_guid
, ctx
.dnsforest
)
283 '''get the SID of the connected user. Only works with w2k8 and later,
284 so only used for RODC join'''
285 res
= ctx
.samdb
.search(base
="", scope
=ldb
.SCOPE_BASE
, attrs
=["tokenGroups"])
286 binsid
= res
[0]["tokenGroups"][0]
287 return ctx
.samdb
.schema_format_value("objectSID", binsid
)
289 def dn_exists(ctx
, dn
):
290 '''check if a DN exists'''
292 res
= ctx
.samdb
.search(base
=dn
, scope
=ldb
.SCOPE_BASE
, attrs
=[])
293 except ldb
.LdbError
, (enum
, estr
):
294 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
299 def add_krbtgt_account(ctx
):
300 '''RODCs need a special krbtgt account'''
301 print "Adding %s" % ctx
.krbtgt_dn
303 "dn" : ctx
.krbtgt_dn
,
304 "objectclass" : "user",
305 "useraccountcontrol" : str(samba
.dsdb
.UF_NORMAL_ACCOUNT |
306 samba
.dsdb
.UF_ACCOUNTDISABLE
),
307 "showinadvancedviewonly" : "TRUE",
308 "description" : "krbtgt for %s" % ctx
.samname
}
309 ctx
.samdb
.add(rec
, ["rodc_join:1:1"])
311 # now we need to search for the samAccountName attribute on the krbtgt DN,
312 # as this will have been magically set to the krbtgt number
313 res
= ctx
.samdb
.search(base
=ctx
.krbtgt_dn
, scope
=ldb
.SCOPE_BASE
, attrs
=["samAccountName"])
314 ctx
.krbtgt_name
= res
[0]["samAccountName"][0]
316 print "Got krbtgt_name=%s" % ctx
.krbtgt_name
319 m
.dn
= ldb
.Dn(ctx
.samdb
, ctx
.acct_dn
)
320 m
["msDS-krbTgtLink"] = ldb
.MessageElement(ctx
.krbtgt_dn
,
321 ldb
.FLAG_MOD_REPLACE
, "msDS-krbTgtLink")
324 ctx
.new_krbtgt_dn
= "CN=%s,CN=Users,%s" % (ctx
.krbtgt_name
, ctx
.base_dn
)
325 print "Renaming %s to %s" % (ctx
.krbtgt_dn
, ctx
.new_krbtgt_dn
)
326 ctx
.samdb
.rename(ctx
.krbtgt_dn
, ctx
.new_krbtgt_dn
)
328 def drsuapi_connect(ctx
):
329 '''make a DRSUAPI connection to the naming master'''
330 binding_options
= "seal"
331 if int(ctx
.lp
.get("log level")) >= 4:
332 binding_options
+= ",print"
333 binding_string
= "ncacn_ip_tcp:%s[%s]" % (ctx
.server
, binding_options
)
334 ctx
.drsuapi
= drsuapi
.drsuapi(binding_string
, ctx
.lp
, ctx
.creds
)
335 (ctx
.drsuapi_handle
, ctx
.bind_supported_extensions
) = drs_utils
.drs_DsBind(ctx
.drsuapi
)
337 def create_tmp_samdb(ctx
):
338 '''create a temporary samdb object for schema queries'''
339 ctx
.tmp_schema
= Schema(security
.dom_sid(ctx
.domsid
),
340 schemadn
=ctx
.schema_dn
)
341 ctx
.tmp_samdb
= SamDB(session_info
=system_session(), url
=None, auto_connect
=False,
342 credentials
=ctx
.creds
, lp
=ctx
.lp
, global_schema
=False,
344 ctx
.tmp_samdb
.set_schema(ctx
.tmp_schema
)
346 def build_DsReplicaAttribute(ctx
, attrname
, attrvalue
):
347 '''build a DsReplicaAttributeCtr object'''
348 r
= drsuapi
.DsReplicaAttribute()
349 r
.attid
= ctx
.tmp_samdb
.get_attid_from_lDAPDisplayName(attrname
)
353 def DsAddEntry(ctx
, recs
):
354 '''add a record via the DRSUAPI DsAddEntry call'''
355 if ctx
.drsuapi
is None:
356 ctx
.drsuapi_connect()
357 if ctx
.tmp_samdb
is None:
358 ctx
.create_tmp_samdb()
362 id = drsuapi
.DsReplicaObjectIdentifier()
369 if not isinstance(rec
[a
], list):
373 rattr
= ctx
.tmp_samdb
.dsdb_DsReplicaAttribute(ctx
.tmp_samdb
, a
, v
)
376 attribute_ctr
= drsuapi
.DsReplicaAttributeCtr()
377 attribute_ctr
.num_attributes
= len(attrs
)
378 attribute_ctr
.attributes
= attrs
380 object = drsuapi
.DsReplicaObject()
381 object.identifier
= id
382 object.attribute_ctr
= attribute_ctr
384 list_object
= drsuapi
.DsReplicaObjectListItem()
385 list_object
.object = object
386 objects
.append(list_object
)
388 req2
= drsuapi
.DsAddEntryRequest2()
389 req2
.first_object
= objects
[0]
390 prev
= req2
.first_object
391 for o
in objects
[1:]:
395 (level
, ctr
) = ctx
.drsuapi
.DsAddEntry(ctx
.drsuapi_handle
, 2, req2
)
397 if ctr
.dir_err
!= drsuapi
.DRSUAPI_DIRERR_OK
:
398 print("DsAddEntry failed with dir_err %u" % ctr
.dir_err
)
399 raise RuntimeError("DsAddEntry failed")
400 if ctr
.extended_err
!= (0, 'WERR_OK'):
401 print("DsAddEntry failed with status %s info %s" % (ctr
.extended_err
))
402 raise RuntimeError("DsAddEntry failed")
405 raise RuntimeError("expected err_ver 1, got %u" % ctr
.err_ver
)
406 if ctr
.err_data
.status
!= (0, 'WERR_OK'):
407 print("DsAddEntry failed with status %s info %s" % (ctr
.err_data
.status
,
408 ctr
.err_data
.info
.extended_err
))
409 raise RuntimeError("DsAddEntry failed")
410 if ctr
.err_data
.dir_err
!= drsuapi
.DRSUAPI_DIRERR_OK
:
411 print("DsAddEntry failed with dir_err %u" % ctr
.err_data
.dir_err
)
412 raise RuntimeError("DsAddEntry failed")
416 def join_add_ntdsdsa(ctx
):
417 '''add the ntdsdsa object'''
418 # FIXME: the partition (NC) assignment has to be made dynamic
419 print "Adding %s" % ctx
.ntds_dn
422 "objectclass" : "nTDSDSA",
423 "systemFlags" : str(samba
.dsdb
.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
),
424 "dMDLocation" : ctx
.schema_dn
}
426 nc_list
= [ ctx
.base_dn
, ctx
.config_dn
, ctx
.schema_dn
]
428 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2003
:
429 rec
["msDS-Behavior-Version"] = str(samba
.dsdb
.DS_DOMAIN_FUNCTION_2008_R2
)
431 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2003
:
432 rec
["msDS-HasDomainNCs"] = ctx
.base_dn
435 rec
["objectCategory"] = "CN=NTDS-DSA-RO,%s" % ctx
.schema_dn
436 rec
["msDS-HasFullReplicaNCs"] = ctx
.nc_list
437 rec
["options"] = "37"
438 ctx
.samdb
.add(rec
, ["rodc_join:1:1"])
440 rec
["objectCategory"] = "CN=NTDS-DSA,%s" % ctx
.schema_dn
441 rec
["HasMasterNCs"] = nc_list
442 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2003
:
443 rec
["msDS-HasMasterNCs"] = ctx
.nc_list
445 rec
["invocationId"] = ndr_pack(ctx
.invocation_id
)
446 ctx
.DsAddEntry([rec
])
448 # find the GUID of our NTDS DN
449 res
= ctx
.samdb
.search(base
=ctx
.ntds_dn
, scope
=ldb
.SCOPE_BASE
, attrs
=["objectGUID"])
450 ctx
.ntds_guid
= misc
.GUID(ctx
.samdb
.schema_format_value("objectGUID", res
[0]["objectGUID"][0]))
452 def join_add_objects(ctx
):
453 '''add the various objects needed for the join'''
455 print "Adding %s" % ctx
.acct_dn
458 "objectClass": "computer",
459 "displayname": ctx
.samname
,
460 "samaccountname" : ctx
.samname
,
461 "userAccountControl" : str(ctx
.userAccountControl | samba
.dsdb
.UF_ACCOUNTDISABLE
),
462 "dnshostname" : ctx
.dnshostname
}
463 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2008
:
464 rec
['msDS-SupportedEncryptionTypes'] = str(samba
.dsdb
.ENC_ALL_TYPES
)
465 elif ctx
.promote_existing
:
466 rec
['msDS-SupportedEncryptionTypes'] = []
468 rec
["managedby"] = ctx
.managedby
469 elif ctx
.promote_existing
:
470 rec
["managedby"] = []
472 if ctx
.never_reveal_sid
:
473 rec
["msDS-NeverRevealGroup"] = ctx
.never_reveal_sid
474 elif ctx
.promote_existing
:
475 rec
["msDS-NeverRevealGroup"] = []
478 rec
["msDS-RevealOnDemandGroup"] = ctx
.reveal_sid
479 elif ctx
.promote_existing
:
480 rec
["msDS-RevealOnDemandGroup"] = []
482 if ctx
.promote_existing
:
483 if ctx
.promote_from_dn
!= ctx
.acct_dn
:
484 ctx
.samdb
.rename(ctx
.promote_from_dn
, ctx
.acct_dn
)
485 ctx
.samdb
.modify(ldb
.Message
.from_dict(ctx
.samdb
, rec
, ldb
.FLAG_MOD_REPLACE
))
490 ctx
.add_krbtgt_account()
492 print "Adding %s" % ctx
.server_dn
495 "objectclass" : "server",
496 # windows uses 50000000 decimal for systemFlags. A windows hex/decimal mixup bug?
497 "systemFlags" : str(samba
.dsdb
.SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
498 samba
.dsdb
.SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE |
499 samba
.dsdb
.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
),
500 # windows seems to add the dnsHostName later
501 "dnsHostName" : ctx
.dnshostname
}
504 rec
["serverReference"] = ctx
.acct_dn
509 # the rest is done after replication
513 ctx
.join_add_ntdsdsa()
515 if ctx
.connection_dn
is not None:
516 print "Adding %s" % ctx
.connection_dn
518 "dn" : ctx
.connection_dn
,
519 "objectclass" : "nTDSConnection",
520 "enabledconnection" : "TRUE",
522 "fromServer" : ctx
.dc_ntds_dn
}
526 print "Adding SPNs to %s" % ctx
.acct_dn
528 m
.dn
= ldb
.Dn(ctx
.samdb
, ctx
.acct_dn
)
529 for i
in range(len(ctx
.SPNs
)):
530 ctx
.SPNs
[i
] = ctx
.SPNs
[i
].replace("$NTDSGUID", str(ctx
.ntds_guid
))
531 m
["servicePrincipalName"] = ldb
.MessageElement(ctx
.SPNs
,
532 ldb
.FLAG_MOD_REPLACE
,
533 "servicePrincipalName")
536 # The account password set operation should normally be done over
537 # LDAP. Windows 2000 DCs however allow this only with SSL
538 # connections which are hard to set up and otherwise refuse with
539 # ERR_UNWILLING_TO_PERFORM. In this case we fall back to libnet
541 print "Setting account password for %s" % ctx
.samname
543 ctx
.samdb
.setpassword("(&(objectClass=user)(sAMAccountName=%s))"
544 % ldb
.binary_encode(ctx
.samname
),
546 force_change_at_next_login
=False,
547 username
=ctx
.samname
)
548 except ldb
.LdbError
, (num
, _
):
549 if num
!= ldb
.ERR_UNWILLING_TO_PERFORM
:
551 ctx
.net
.set_password(account_name
=ctx
.samname
,
552 domain_name
=ctx
.domain_name
,
553 newpassword
=ctx
.acct_pass
)
555 res
= ctx
.samdb
.search(base
=ctx
.acct_dn
, scope
=ldb
.SCOPE_BASE
,
556 attrs
=["msDS-KeyVersionNumber"])
557 if "msDS-KeyVersionNumber" in res
[0]:
558 ctx
.key_version_number
= int(res
[0]["msDS-KeyVersionNumber"][0])
560 ctx
.key_version_number
= None
562 print("Enabling account")
564 m
.dn
= ldb
.Dn(ctx
.samdb
, ctx
.acct_dn
)
565 m
["userAccountControl"] = ldb
.MessageElement(str(ctx
.userAccountControl
),
566 ldb
.FLAG_MOD_REPLACE
,
567 "userAccountControl")
570 def join_add_objects2(ctx
):
571 '''add the various objects needed for the join, for subdomains post replication'''
573 print "Adding %s" % ctx
.partition_dn
574 # NOTE: windows sends a ntSecurityDescriptor here, we
577 "dn" : ctx
.partition_dn
,
578 "objectclass" : "crossRef",
579 "objectCategory" : "CN=Cross-Ref,%s" % ctx
.schema_dn
,
580 "nCName" : ctx
.base_dn
,
581 "nETBIOSName" : ctx
.domain_name
,
582 "dnsRoot": ctx
.dnsdomain
,
583 "trustParent" : ctx
.parent_partition_dn
,
584 "systemFlags" : str(samba
.dsdb
.SYSTEM_FLAG_CR_NTDS_NC|samba
.dsdb
.SYSTEM_FLAG_CR_NTDS_DOMAIN
)}
585 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2003
:
586 rec
["msDS-Behavior-Version"] = str(ctx
.behavior_version
)
590 "objectclass" : "nTDSDSA",
591 "systemFlags" : str(samba
.dsdb
.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
),
592 "dMDLocation" : ctx
.schema_dn
}
594 nc_list
= [ ctx
.base_dn
, ctx
.config_dn
, ctx
.schema_dn
]
596 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2003
:
597 rec2
["msDS-Behavior-Version"] = str(ctx
.behavior_version
)
599 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2003
:
600 rec2
["msDS-HasDomainNCs"] = ctx
.base_dn
602 rec2
["objectCategory"] = "CN=NTDS-DSA,%s" % ctx
.schema_dn
603 rec2
["HasMasterNCs"] = nc_list
604 if ctx
.behavior_version
>= samba
.dsdb
.DS_DOMAIN_FUNCTION_2003
:
605 rec2
["msDS-HasMasterNCs"] = ctx
.nc_list
606 rec2
["options"] = "1"
607 rec2
["invocationId"] = ndr_pack(ctx
.invocation_id
)
609 objects
= ctx
.DsAddEntry([rec
, rec2
])
610 if len(objects
) != 2:
611 raise DCJoinException("Expected 2 objects from DsAddEntry")
613 ctx
.ntds_guid
= objects
[1].guid
615 print("Replicating partition DN")
616 ctx
.repl
.replicate(ctx
.partition_dn
,
617 misc
.GUID("00000000-0000-0000-0000-000000000000"),
619 exop
=drsuapi
.DRSUAPI_EXOP_REPL_OBJ
,
620 replica_flags
=drsuapi
.DRSUAPI_DRS_WRIT_REP
)
622 print("Replicating NTDS DN")
623 ctx
.repl
.replicate(ctx
.ntds_dn
,
624 misc
.GUID("00000000-0000-0000-0000-000000000000"),
626 exop
=drsuapi
.DRSUAPI_EXOP_REPL_OBJ
,
627 replica_flags
=drsuapi
.DRSUAPI_DRS_WRIT_REP
)
629 def join_provision(ctx
):
630 '''provision the local SAM'''
632 print "Calling bare provision"
634 logger
= logging
.getLogger("provision")
635 logger
.addHandler(logging
.StreamHandler(sys
.stdout
))
636 smbconf
= ctx
.lp
.configfile
638 presult
= provision(logger
, system_session(), None, smbconf
=smbconf
,
639 targetdir
=ctx
.targetdir
, samdb_fill
=FILL_DRS
, realm
=ctx
.realm
,
640 rootdn
=ctx
.root_dn
, domaindn
=ctx
.base_dn
,
641 schemadn
=ctx
.schema_dn
, configdn
=ctx
.config_dn
,
642 serverdn
=ctx
.server_dn
, domain
=ctx
.domain_name
,
643 hostname
=ctx
.myname
, domainsid
=ctx
.domsid
,
644 machinepass
=ctx
.acct_pass
, serverrole
="domain controller",
645 sitename
=ctx
.site
, lp
=ctx
.lp
, ntdsguid
=ctx
.ntds_guid
,
646 use_ntvfs
=ctx
.use_ntvfs
, dns_backend
=ctx
.dns_backend
)
647 print "Provision OK for domain DN %s" % presult
.domaindn
648 ctx
.local_samdb
= presult
.samdb
650 ctx
.paths
= presult
.paths
651 ctx
.names
= presult
.names
653 def join_provision_own_domain(ctx
):
654 '''provision the local SAM'''
656 # we now operate exclusively on the local database, which
657 # we need to reopen in order to get the newly created schema
658 print("Reconnecting to local samdb")
659 ctx
.samdb
= SamDB(url
=ctx
.local_samdb
.url
,
660 session_info
=system_session(),
661 lp
=ctx
.local_samdb
.lp
,
663 ctx
.samdb
.set_invocation_id(str(ctx
.invocation_id
))
664 ctx
.local_samdb
= ctx
.samdb
666 print("Finding domain GUID from ncName")
667 res
= ctx
.local_samdb
.search(base
=ctx
.partition_dn
, scope
=ldb
.SCOPE_BASE
, attrs
=['ncName'],
668 controls
=["extended_dn:1:1"])
669 domguid
= str(misc
.GUID(ldb
.Dn(ctx
.samdb
, res
[0]['ncName'][0]).get_extended_component('GUID')))
670 print("Got domain GUID %s" % domguid
)
672 print("Calling own domain provision")
674 logger
= logging
.getLogger("provision")
675 logger
.addHandler(logging
.StreamHandler(sys
.stdout
))
677 secrets_ldb
= Ldb(ctx
.paths
.secrets
, session_info
=system_session(), lp
=ctx
.lp
)
679 presult
= provision_fill(ctx
.local_samdb
, secrets_ldb
,
680 logger
, ctx
.names
, ctx
.paths
, domainsid
=security
.dom_sid(ctx
.domsid
),
682 targetdir
=ctx
.targetdir
, samdb_fill
=FILL_SUBDOMAIN
,
683 machinepass
=ctx
.acct_pass
, serverrole
="domain controller",
684 lp
=ctx
.lp
, hostip
=ctx
.names
.hostip
, hostip6
=ctx
.names
.hostip6
,
685 dns_backend
=ctx
.dns_backend
)
686 print("Provision OK for domain %s" % ctx
.names
.dnsdomain
)
688 def join_replicate(ctx
):
689 '''replicate the SAM'''
691 print "Starting replication"
692 ctx
.local_samdb
.transaction_start()
694 source_dsa_invocation_id
= misc
.GUID(ctx
.samdb
.get_invocation_id())
695 if ctx
.ntds_guid
is None:
696 print("Using DS_BIND_GUID_W2K3")
697 destination_dsa_guid
= misc
.GUID(drsuapi
.DRSUAPI_DS_BIND_GUID_W2K3
)
699 destination_dsa_guid
= ctx
.ntds_guid
702 repl_creds
= Credentials()
703 repl_creds
.guess(ctx
.lp
)
704 repl_creds
.set_kerberos_state(DONT_USE_KERBEROS
)
705 repl_creds
.set_username(ctx
.samname
)
706 repl_creds
.set_password(ctx
.acct_pass
)
708 repl_creds
= ctx
.creds
710 binding_options
= "seal"
711 if int(ctx
.lp
.get("log level")) >= 5:
712 binding_options
+= ",print"
713 repl
= drs_utils
.drs_Replicate(
714 "ncacn_ip_tcp:%s[%s]" % (ctx
.server
, binding_options
),
715 ctx
.lp
, repl_creds
, ctx
.local_samdb
)
717 repl
.replicate(ctx
.schema_dn
, source_dsa_invocation_id
,
718 destination_dsa_guid
, schema
=True, rodc
=ctx
.RODC
,
719 replica_flags
=ctx
.replica_flags
)
720 repl
.replicate(ctx
.config_dn
, source_dsa_invocation_id
,
721 destination_dsa_guid
, rodc
=ctx
.RODC
,
722 replica_flags
=ctx
.replica_flags
)
723 if not ctx
.subdomain
:
724 # Replicate first the critical object for the basedn
725 if not ctx
.domain_replica_flags
& drsuapi
.DRSUAPI_DRS_CRITICAL_ONLY
:
726 print "Replicating critical objects from the base DN of the domain"
727 ctx
.domain_replica_flags |
= drsuapi
.DRSUAPI_DRS_CRITICAL_ONLY | drsuapi
.DRSUAPI_DRS_GET_ANC
728 repl
.replicate(ctx
.base_dn
, source_dsa_invocation_id
,
729 destination_dsa_guid
, rodc
=ctx
.RODC
,
730 replica_flags
=ctx
.domain_replica_flags
)
731 ctx
.domain_replica_flags ^
= drsuapi
.DRSUAPI_DRS_CRITICAL_ONLY | drsuapi
.DRSUAPI_DRS_GET_ANC
733 ctx
.domain_replica_flags |
= drsuapi
.DRSUAPI_DRS_GET_ANC
734 repl
.replicate(ctx
.base_dn
, source_dsa_invocation_id
,
735 destination_dsa_guid
, rodc
=ctx
.RODC
,
736 replica_flags
=ctx
.domain_replica_flags
)
738 if 'DC=DomainDnsZones,%s' % ctx
.base_dn
in ctx
.nc_list
:
739 repl
.replicate('DC=DomainDnsZones,%s' % ctx
.base_dn
, source_dsa_invocation_id
,
740 destination_dsa_guid
, rodc
=ctx
.RODC
,
741 replica_flags
=ctx
.replica_flags
)
743 if 'DC=ForestDnsZones,%s' % ctx
.root_dn
in ctx
.nc_list
:
744 repl
.replicate('DC=ForestDnsZones,%s' % ctx
.root_dn
, source_dsa_invocation_id
,
745 destination_dsa_guid
, rodc
=ctx
.RODC
,
746 replica_flags
=ctx
.replica_flags
)
749 repl
.replicate(ctx
.acct_dn
, source_dsa_invocation_id
,
750 destination_dsa_guid
,
751 exop
=drsuapi
.DRSUAPI_EXOP_REPL_SECRET
, rodc
=True)
752 repl
.replicate(ctx
.new_krbtgt_dn
, source_dsa_invocation_id
,
753 destination_dsa_guid
,
754 exop
=drsuapi
.DRSUAPI_EXOP_REPL_SECRET
, rodc
=True)
756 ctx
.source_dsa_invocation_id
= source_dsa_invocation_id
757 ctx
.destination_dsa_guid
= destination_dsa_guid
759 print "Committing SAM database"
761 ctx
.local_samdb
.transaction_cancel()
764 ctx
.local_samdb
.transaction_commit()
766 def send_DsReplicaUpdateRefs(ctx
, dn
):
767 r
= drsuapi
.DsReplicaUpdateRefsRequest1()
768 r
.naming_context
= drsuapi
.DsReplicaObjectIdentifier()
769 r
.naming_context
.dn
= str(dn
)
770 r
.naming_context
.guid
= misc
.GUID("00000000-0000-0000-0000-000000000000")
771 r
.naming_context
.sid
= security
.dom_sid("S-0-0")
772 r
.dest_dsa_guid
= ctx
.ntds_guid
773 r
.dest_dsa_dns_name
= "%s._msdcs.%s" % (str(ctx
.ntds_guid
), ctx
.dnsforest
)
774 r
.options
= drsuapi
.DRSUAPI_DRS_ADD_REF | drsuapi
.DRSUAPI_DRS_DEL_REF
776 r
.options |
= drsuapi
.DRSUAPI_DRS_WRIT_REP
779 ctx
.drsuapi
.DsReplicaUpdateRefs(ctx
.drsuapi_handle
, 1, r
)
781 def join_finalise(ctx
):
782 '''finalise the join, mark us synchronised and setup secrets db'''
784 logger
= logging
.getLogger("provision")
785 logger
.addHandler(logging
.StreamHandler(sys
.stdout
))
787 print "Sending DsReplicateUpdateRefs for all the partitions"
788 for nc
in ctx
.full_nc_list
:
789 ctx
.send_DsReplicaUpdateRefs(nc
)
792 print "Setting RODC invocationId"
793 ctx
.local_samdb
.set_invocation_id(str(ctx
.invocation_id
))
794 ctx
.local_samdb
.set_opaque_integer("domainFunctionality",
795 ctx
.behavior_version
)
797 m
.dn
= ldb
.Dn(ctx
.local_samdb
, "%s" % ctx
.ntds_dn
)
798 m
["invocationId"] = ldb
.MessageElement(ndr_pack(ctx
.invocation_id
),
799 ldb
.FLAG_MOD_REPLACE
,
801 ctx
.local_samdb
.modify(m
)
803 # Note: as RODC the invocationId is only stored
804 # on the RODC itself, the other DCs never see it.
806 # Thats is why we fix up the replPropertyMetaData stamp
807 # for the 'invocationId' attribute, we need to change
808 # the 'version' to '0', this is what windows 2008r2 does as RODC
810 # This means if the object on a RWDC ever gets a invocationId
811 # attribute, it will have version '1' (or higher), which will
812 # will overwrite the RODC local value.
813 ctx
.local_samdb
.set_attribute_replmetadata_version(m
.dn
,
817 print "Setting isSynchronized and dsServiceName"
819 m
.dn
= ldb
.Dn(ctx
.local_samdb
, '@ROOTDSE')
820 m
["isSynchronized"] = ldb
.MessageElement("TRUE", ldb
.FLAG_MOD_REPLACE
, "isSynchronized")
821 m
["dsServiceName"] = ldb
.MessageElement("<GUID=%s>" % str(ctx
.ntds_guid
),
822 ldb
.FLAG_MOD_REPLACE
, "dsServiceName")
823 ctx
.local_samdb
.modify(m
)
828 secrets_ldb
= Ldb(ctx
.paths
.secrets
, session_info
=system_session(), lp
=ctx
.lp
)
830 print "Setting up secrets database"
831 secretsdb_self_join(secrets_ldb
, domain
=ctx
.domain_name
,
833 dnsdomain
=ctx
.dnsdomain
,
834 netbiosname
=ctx
.myname
,
835 domainsid
=security
.dom_sid(ctx
.domsid
),
836 machinepass
=ctx
.acct_pass
,
837 secure_channel_type
=ctx
.secure_channel_type
,
838 key_version_number
=ctx
.key_version_number
)
840 if ctx
.dns_backend
.startswith("BIND9_"):
841 dnspass
= samba
.generate_random_password(128, 255)
843 setup_bind9_dns(ctx
.local_samdb
, secrets_ldb
, security
.dom_sid(ctx
.domsid
),
844 ctx
.names
, ctx
.paths
, ctx
.lp
, logger
,
845 dns_backend
=ctx
.dns_backend
,
846 dnspass
=dnspass
, os_level
=ctx
.behavior_version
,
847 targetdir
=ctx
.targetdir
)
849 def join_setup_trusts(ctx
):
850 '''provision the local SAM'''
852 def arcfour_encrypt(key
, data
):
853 from Crypto
.Cipher
import ARC4
855 return c
.encrypt(data
)
857 def string_to_array(string
):
858 blob
= [0] * len(string
)
860 for i
in range(len(string
)):
861 blob
[i
] = ord(string
[i
])
865 print "Setup domain trusts with server %s" % ctx
.server
866 binding_options
= "" # why doesn't signing work here? w2k8r2 claims no session key
867 lsaconn
= lsa
.lsarpc("ncacn_np:%s[%s]" % (ctx
.server
, binding_options
),
870 objectAttr
= lsa
.ObjectAttribute()
871 objectAttr
.sec_qos
= lsa
.QosInfo()
873 pol_handle
= lsaconn
.OpenPolicy2(''.decode('utf-8'),
874 objectAttr
, security
.SEC_FLAG_MAXIMUM_ALLOWED
)
876 info
= lsa
.TrustDomainInfoInfoEx()
877 info
.domain_name
.string
= ctx
.dnsdomain
878 info
.netbios_name
.string
= ctx
.domain_name
879 info
.sid
= security
.dom_sid(ctx
.domsid
)
880 info
.trust_direction
= lsa
.LSA_TRUST_DIRECTION_INBOUND | lsa
.LSA_TRUST_DIRECTION_OUTBOUND
881 info
.trust_type
= lsa
.LSA_TRUST_TYPE_UPLEVEL
882 info
.trust_attributes
= lsa
.LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
885 oldname
= lsa
.String()
886 oldname
.string
= ctx
.dnsdomain
887 oldinfo
= lsaconn
.QueryTrustedDomainInfoByName(pol_handle
, oldname
,
888 lsa
.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO
)
889 print("Removing old trust record for %s (SID %s)" % (ctx
.dnsdomain
, oldinfo
.info_ex
.sid
))
890 lsaconn
.DeleteTrustedDomain(pol_handle
, oldinfo
.info_ex
.sid
)
894 password_blob
= string_to_array(ctx
.trustdom_pass
.encode('utf-16-le'))
896 clear_value
= drsblobs
.AuthInfoClear()
897 clear_value
.size
= len(password_blob
)
898 clear_value
.password
= password_blob
900 clear_authentication_information
= drsblobs
.AuthenticationInformation()
901 clear_authentication_information
.LastUpdateTime
= samba
.unix2nttime(int(time
.time()))
902 clear_authentication_information
.AuthType
= lsa
.TRUST_AUTH_TYPE_CLEAR
903 clear_authentication_information
.AuthInfo
= clear_value
905 authentication_information_array
= drsblobs
.AuthenticationInformationArray()
906 authentication_information_array
.count
= 1
907 authentication_information_array
.array
= [clear_authentication_information
]
909 outgoing
= drsblobs
.trustAuthInOutBlob()
911 outgoing
.current
= authentication_information_array
913 trustpass
= drsblobs
.trustDomainPasswords()
914 confounder
= [3] * 512
917 confounder
[i
] = random
.randint(0, 255)
919 trustpass
.confounder
= confounder
921 trustpass
.outgoing
= outgoing
922 trustpass
.incoming
= outgoing
924 trustpass_blob
= ndr_pack(trustpass
)
926 encrypted_trustpass
= arcfour_encrypt(lsaconn
.session_key
, trustpass_blob
)
928 auth_blob
= lsa
.DATA_BUF2()
929 auth_blob
.size
= len(encrypted_trustpass
)
930 auth_blob
.data
= string_to_array(encrypted_trustpass
)
932 auth_info
= lsa
.TrustDomainInfoAuthInfoInternal()
933 auth_info
.auth_blob
= auth_blob
935 trustdom_handle
= lsaconn
.CreateTrustedDomainEx2(pol_handle
,
938 security
.SEC_STD_DELETE
)
941 "dn" : "cn=%s,cn=system,%s" % (ctx
.dnsforest
, ctx
.base_dn
),
942 "objectclass" : "trustedDomain",
943 "trustType" : str(info
.trust_type
),
944 "trustAttributes" : str(info
.trust_attributes
),
945 "trustDirection" : str(info
.trust_direction
),
946 "flatname" : ctx
.forest_domain_name
,
947 "trustPartner" : ctx
.dnsforest
,
948 "trustAuthIncoming" : ndr_pack(outgoing
),
949 "trustAuthOutgoing" : ndr_pack(outgoing
)
951 ctx
.local_samdb
.add(rec
)
954 "dn" : "cn=%s$,cn=users,%s" % (ctx
.forest_domain_name
, ctx
.base_dn
),
955 "objectclass" : "user",
956 "userAccountControl" : str(samba
.dsdb
.UF_INTERDOMAIN_TRUST_ACCOUNT
),
957 "clearTextPassword" : ctx
.trustdom_pass
.encode('utf-16-le')
959 ctx
.local_samdb
.add(rec
)
963 ctx
.nc_list
= [ ctx
.config_dn
, ctx
.schema_dn
]
964 ctx
.full_nc_list
= [ctx
.base_dn
, ctx
.config_dn
, ctx
.schema_dn
]
966 if not ctx
.subdomain
:
967 ctx
.nc_list
+= [ctx
.base_dn
]
968 if ctx
.dns_backend
!= "NONE":
969 ctx
.nc_list
+= ['DC=DomainDnsZones,%s' % ctx
.base_dn
]
971 if ctx
.dns_backend
!= "NONE":
972 ctx
.full_nc_list
+= ['DC=DomainDnsZones,%s' % ctx
.base_dn
]
973 ctx
.full_nc_list
+= ['DC=ForestDnsZones,%s' % ctx
.root_dn
]
974 ctx
.nc_list
+= ['DC=ForestDnsZones,%s' % ctx
.root_dn
]
976 if ctx
.promote_existing
:
977 ctx
.promote_possible()
979 ctx
.cleanup_old_join()
982 ctx
.join_add_objects()
986 ctx
.join_add_objects2()
987 ctx
.join_provision_own_domain()
988 ctx
.join_setup_trusts()
991 print "Join failed - cleaning up"
992 ctx
.cleanup_old_join()
996 def join_RODC(server
=None, creds
=None, lp
=None, site
=None, netbios_name
=None,
997 targetdir
=None, domain
=None, domain_critical_only
=False,
998 machinepass
=None, use_ntvfs
=False, dns_backend
=None,
999 promote_existing
=False):
1000 """join as a RODC"""
1002 ctx
= dc_join(server
, creds
, lp
, site
, netbios_name
, targetdir
, domain
,
1003 machinepass
, use_ntvfs
, dns_backend
, promote_existing
)
1005 lp
.set("workgroup", ctx
.domain_name
)
1006 print("workgroup is %s" % ctx
.domain_name
)
1008 lp
.set("realm", ctx
.realm
)
1009 print("realm is %s" % ctx
.realm
)
1011 ctx
.krbtgt_dn
= "CN=krbtgt_%s,CN=Users,%s" % (ctx
.myname
, ctx
.base_dn
)
1013 # setup some defaults for accounts that should be replicated to this RODC
1014 ctx
.never_reveal_sid
= [ "<SID=%s-%s>" % (ctx
.domsid
, security
.DOMAIN_RID_RODC_DENY
),
1015 "<SID=%s>" % security
.SID_BUILTIN_ADMINISTRATORS
,
1016 "<SID=%s>" % security
.SID_BUILTIN_SERVER_OPERATORS
,
1017 "<SID=%s>" % security
.SID_BUILTIN_BACKUP_OPERATORS
,
1018 "<SID=%s>" % security
.SID_BUILTIN_ACCOUNT_OPERATORS
]
1019 ctx
.reveal_sid
= "<SID=%s-%s>" % (ctx
.domsid
, security
.DOMAIN_RID_RODC_ALLOW
)
1021 mysid
= ctx
.get_mysid()
1022 admin_dn
= "<SID=%s>" % mysid
1023 ctx
.managedby
= admin_dn
1025 ctx
.userAccountControl
= (samba
.dsdb
.UF_WORKSTATION_TRUST_ACCOUNT |
1026 samba
.dsdb
.UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |
1027 samba
.dsdb
.UF_PARTIAL_SECRETS_ACCOUNT
)
1029 ctx
.SPNs
.extend([ "RestrictedKrbHost/%s" % ctx
.myname
,
1030 "RestrictedKrbHost/%s" % ctx
.dnshostname
])
1032 ctx
.connection_dn
= "CN=RODC Connection (FRS),%s" % ctx
.ntds_dn
1033 ctx
.secure_channel_type
= misc
.SEC_CHAN_RODC
1035 ctx
.replica_flags
= (drsuapi
.DRSUAPI_DRS_INIT_SYNC |
1036 drsuapi
.DRSUAPI_DRS_PER_SYNC |
1037 drsuapi
.DRSUAPI_DRS_GET_ANC |
1038 drsuapi
.DRSUAPI_DRS_NEVER_SYNCED |
1039 drsuapi
.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING |
1040 drsuapi
.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP
)
1041 ctx
.domain_replica_flags
= ctx
.replica_flags
1042 if domain_critical_only
:
1043 ctx
.domain_replica_flags |
= drsuapi
.DRSUAPI_DRS_CRITICAL_ONLY
1048 print "Joined domain %s (SID %s) as an RODC" % (ctx
.domain_name
, ctx
.domsid
)
1051 def join_DC(server
=None, creds
=None, lp
=None, site
=None, netbios_name
=None,
1052 targetdir
=None, domain
=None, domain_critical_only
=False,
1053 machinepass
=None, use_ntvfs
=False, dns_backend
=None,
1054 promote_existing
=False):
1056 ctx
= dc_join(server
, creds
, lp
, site
, netbios_name
, targetdir
, domain
,
1057 machinepass
, use_ntvfs
, dns_backend
, promote_existing
)
1059 lp
.set("workgroup", ctx
.domain_name
)
1060 print("workgroup is %s" % ctx
.domain_name
)
1062 lp
.set("realm", ctx
.realm
)
1063 print("realm is %s" % ctx
.realm
)
1065 ctx
.userAccountControl
= samba
.dsdb
.UF_SERVER_TRUST_ACCOUNT | samba
.dsdb
.UF_TRUSTED_FOR_DELEGATION
1067 ctx
.SPNs
.append('E3514235-4B06-11D1-AB04-00C04FC2DCD2/$NTDSGUID/%s' % ctx
.dnsdomain
)
1068 ctx
.secure_channel_type
= misc
.SEC_CHAN_BDC
1070 ctx
.replica_flags
= (drsuapi
.DRSUAPI_DRS_WRIT_REP |
1071 drsuapi
.DRSUAPI_DRS_INIT_SYNC |
1072 drsuapi
.DRSUAPI_DRS_PER_SYNC |
1073 drsuapi
.DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS |
1074 drsuapi
.DRSUAPI_DRS_NEVER_SYNCED
)
1075 ctx
.domain_replica_flags
= ctx
.replica_flags
1076 if domain_critical_only
:
1077 ctx
.domain_replica_flags |
= drsuapi
.DRSUAPI_DRS_CRITICAL_ONLY
1080 print "Joined domain %s (SID %s) as a DC" % (ctx
.domain_name
, ctx
.domsid
)
1082 def join_subdomain(server
=None, creds
=None, lp
=None, site
=None, netbios_name
=None,
1083 targetdir
=None, parent_domain
=None, dnsdomain
=None, netbios_domain
=None,
1084 machinepass
=None, use_ntvfs
=False, dns_backend
=None):
1086 ctx
= dc_join(server
, creds
, lp
, site
, netbios_name
, targetdir
, parent_domain
,
1087 machinepass
, use_ntvfs
, dns_backend
)
1088 ctx
.subdomain
= True
1089 ctx
.parent_domain_name
= ctx
.domain_name
1090 ctx
.domain_name
= netbios_domain
1091 ctx
.realm
= dnsdomain
1092 ctx
.parent_dnsdomain
= ctx
.dnsdomain
1093 ctx
.parent_partition_dn
= ctx
.get_parent_partition_dn()
1094 ctx
.dnsdomain
= dnsdomain
1095 ctx
.partition_dn
= "CN=%s,CN=Partitions,%s" % (ctx
.domain_name
, ctx
.config_dn
)
1096 ctx
.naming_master
= ctx
.get_naming_master()
1097 if ctx
.naming_master
!= ctx
.server
:
1098 print("Reconnecting to naming master %s" % ctx
.naming_master
)
1099 ctx
.server
= ctx
.naming_master
1100 ctx
.samdb
= SamDB(url
="ldap://%s" % ctx
.server
,
1101 session_info
=system_session(),
1102 credentials
=ctx
.creds
, lp
=ctx
.lp
)
1104 ctx
.base_dn
= samba
.dn_from_dns_name(dnsdomain
)
1105 ctx
.domsid
= str(security
.random_sid())
1107 ctx
.dnshostname
= "%s.%s" % (ctx
.myname
, ctx
.dnsdomain
)
1108 ctx
.trustdom_pass
= samba
.generate_random_password(128, 128)
1110 ctx
.userAccountControl
= samba
.dsdb
.UF_SERVER_TRUST_ACCOUNT | samba
.dsdb
.UF_TRUSTED_FOR_DELEGATION
1112 ctx
.SPNs
.append('E3514235-4B06-11D1-AB04-00C04FC2DCD2/$NTDSGUID/%s' % ctx
.dnsdomain
)
1113 ctx
.secure_channel_type
= misc
.SEC_CHAN_BDC
1115 ctx
.replica_flags
= (drsuapi
.DRSUAPI_DRS_WRIT_REP |
1116 drsuapi
.DRSUAPI_DRS_INIT_SYNC |
1117 drsuapi
.DRSUAPI_DRS_PER_SYNC |
1118 drsuapi
.DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS |
1119 drsuapi
.DRSUAPI_DRS_NEVER_SYNCED
)
1120 ctx
.domain_replica_flags
= ctx
.replica_flags
1123 print "Created domain %s (SID %s) as a DC" % (ctx
.domain_name
, ctx
.domsid
)