dcesrv_core: better fault codes dcesrv_auth_prepare_auth3()
[Samba.git] / python / samba / netcmd / domain / trust.py
blob0784fa5e28220207bc5cf619b3a0600fb3de6cd4
1 # domain management - domain trust
3 # Copyright Matthias Dieter Wallnoefer 2009
4 # Copyright Andrew Kroeger 2009
5 # Copyright Jelmer Vernooij 2007-2012
6 # Copyright Giampaolo Lauria 2011
7 # Copyright Matthieu Patou <mat@matws.net> 2011
8 # Copyright Andrew Bartlett 2008-2015
9 # Copyright Stefan Metzmacher 2012
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 import ctypes
26 from getpass import getpass
28 import ldb
29 import samba.getopt as options
30 import samba.ntacls
31 from samba import NTSTATUSError, ntstatus, werror
32 from samba.auth import system_session
33 from samba.dcerpc import drsblobs, lsa, nbt, netlogon, security
34 from samba.net import Net
35 from samba.netcmd import Command, CommandError, Option, SuperCommand
36 from samba.samdb import SamDB
37 from samba.lsa_utils import OpenPolicyFallback, CreateTrustedDomainFallback
40 class LocalDCCredentialsOptions(options.CredentialsOptions):
41 def __init__(self, parser):
42 options.CredentialsOptions.__init__(self, parser, special_name="local-dc")
45 class DomainTrustCommand(Command):
46 """List domain trusts."""
48 def __init__(self):
49 Command.__init__(self)
50 self.local_lp = None
52 self.local_server = None
53 self.local_binding_string = None
54 self.local_creds = None
56 self.remote_server = None
57 self.remote_binding_string = None
58 self.remote_creds = None
60 def _uint32(self, v):
61 return ctypes.c_uint32(v).value
63 def check_runtime_error(self, runtime, val):
64 if runtime is None:
65 return False
67 err32 = self._uint32(runtime.args[0])
68 if err32 == val:
69 return True
71 return False
73 class LocalRuntimeError(CommandError):
74 def __init__(exception_self, self, runtime, message):
75 err32 = self._uint32(runtime.args[0])
76 errstr = runtime.args[1]
77 msg = "LOCAL_DC[%s]: %s - ERROR(0x%08X) - %s" % (
78 self.local_server, message, err32, errstr)
79 CommandError.__init__(exception_self, msg)
81 class RemoteRuntimeError(CommandError):
82 def __init__(exception_self, self, runtime, message):
83 err32 = self._uint32(runtime.args[0])
84 errstr = runtime.args[1]
85 msg = "REMOTE_DC[%s]: %s - ERROR(0x%08X) - %s" % (
86 self.remote_server, message, err32, errstr)
87 CommandError.__init__(exception_self, msg)
89 class LocalLdbError(CommandError):
90 def __init__(exception_self, self, ldb_error, message):
91 errval = ldb_error.args[0]
92 errstr = ldb_error.args[1]
93 msg = "LOCAL_DC[%s]: %s - ERROR(%d) - %s" % (
94 self.local_server, message, errval, errstr)
95 CommandError.__init__(exception_self, msg)
97 def setup_local_server(self, sambaopts, localdcopts):
98 if self.local_server is not None:
99 return self.local_server
101 lp = sambaopts.get_loadparm()
103 local_server = localdcopts.ipaddress
104 if local_server is None:
105 server_role = lp.server_role()
106 if server_role != "ROLE_ACTIVE_DIRECTORY_DC":
107 raise CommandError("Invalid server_role %s" % (server_role))
108 local_server = lp.get('netbios name')
109 local_transport = "ncalrpc"
110 local_binding_options = ""
111 local_binding_options += ",auth_type=ncalrpc_as_system"
112 local_ldap_url = None
113 local_creds = None
114 else:
115 local_transport = "ncacn_np"
116 local_binding_options = ""
117 local_ldap_url = "ldap://%s" % local_server
118 local_creds = localdcopts.get_credentials(lp)
120 self.local_lp = lp
122 self.local_server = local_server
123 self.local_binding_string = "%s:%s[%s]" % (local_transport, local_server, local_binding_options)
124 self.local_ldap_url = local_ldap_url
125 self.local_creds = local_creds
126 return self.local_server
128 def new_local_lsa_connection(self):
129 return lsa.lsarpc(self.local_binding_string, self.local_lp, self.local_creds)
131 def new_local_netlogon_connection(self):
132 return netlogon.netlogon(self.local_binding_string, self.local_lp, self.local_creds)
134 def new_local_ldap_connection(self):
135 return SamDB(url=self.local_ldap_url,
136 session_info=system_session(),
137 credentials=self.local_creds,
138 lp=self.local_lp)
140 def setup_remote_server(self, credopts, domain,
141 require_pdc=True,
142 require_writable=True):
144 if require_pdc:
145 assert require_writable
147 if self.remote_server is not None:
148 return self.remote_server
150 self.remote_server = "__unknown__remote_server__.%s" % domain
151 assert self.local_server is not None
153 remote_creds = credopts.get_credentials(self.local_lp)
154 remote_server = credopts.ipaddress
155 remote_binding_options = ""
157 # TODO: we should also support NT4 domains
158 # we could use local_netlogon.netr_DsRGetDCNameEx2() with the remote domain name
159 # and delegate NBT or CLDAP to the local netlogon server
160 try:
161 remote_net = Net(remote_creds, self.local_lp, server=remote_server)
162 remote_flags = nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS
163 if require_writable:
164 remote_flags |= nbt.NBT_SERVER_WRITABLE
165 if require_pdc:
166 remote_flags |= nbt.NBT_SERVER_PDC
167 remote_info = remote_net.finddc(flags=remote_flags, domain=domain, address=remote_server)
168 except NTSTATUSError as error:
169 raise CommandError("Failed to find a writeable DC for domain '%s': %s" %
170 (domain, error.args[1]))
171 except Exception:
172 raise CommandError("Failed to find a writeable DC for domain '%s'" % domain)
173 flag_map = {
174 nbt.NBT_SERVER_PDC: "PDC",
175 nbt.NBT_SERVER_GC: "GC",
176 nbt.NBT_SERVER_LDAP: "LDAP",
177 nbt.NBT_SERVER_DS: "DS",
178 nbt.NBT_SERVER_KDC: "KDC",
179 nbt.NBT_SERVER_TIMESERV: "TIMESERV",
180 nbt.NBT_SERVER_CLOSEST: "CLOSEST",
181 nbt.NBT_SERVER_WRITABLE: "WRITABLE",
182 nbt.NBT_SERVER_GOOD_TIMESERV: "GOOD_TIMESERV",
183 nbt.NBT_SERVER_NDNC: "NDNC",
184 nbt.NBT_SERVER_SELECT_SECRET_DOMAIN_6: "SELECT_SECRET_DOMAIN_6",
185 nbt.NBT_SERVER_FULL_SECRET_DOMAIN_6: "FULL_SECRET_DOMAIN_6",
186 nbt.NBT_SERVER_ADS_WEB_SERVICE: "ADS_WEB_SERVICE",
187 nbt.NBT_SERVER_DS_8: "DS_8",
188 nbt.NBT_SERVER_DS_9: "DS_9",
189 nbt.NBT_SERVER_DS_10: "DS_10",
190 nbt.NBT_SERVER_HAS_DNS_NAME: "HAS_DNS_NAME",
191 nbt.NBT_SERVER_IS_DEFAULT_NC: "IS_DEFAULT_NC",
192 nbt.NBT_SERVER_FOREST_ROOT: "FOREST_ROOT",
194 server_type_string = self.generic_bitmap_to_string(flag_map,
195 remote_info.server_type, names_only=True)
196 self.outf.write("RemoteDC Netbios[%s] DNS[%s] ServerType[%s]\n" % (
197 remote_info.pdc_name,
198 remote_info.pdc_dns_name,
199 server_type_string))
201 self.remote_server = remote_info.pdc_dns_name
202 self.remote_binding_string = "ncacn_np:%s[%s]" % (self.remote_server, remote_binding_options)
203 self.remote_creds = remote_creds
204 return self.remote_server
206 def new_remote_lsa_connection(self):
207 return lsa.lsarpc(self.remote_binding_string, self.local_lp, self.remote_creds)
209 def new_remote_netlogon_connection(self):
210 return netlogon.netlogon(self.remote_binding_string, self.local_lp, self.remote_creds)
212 def get_lsa_info(self, conn, policy_access):
213 in_version = 1
214 in_revision_info1 = lsa.revision_info1()
215 in_revision_info1.revision = 1
216 in_revision_info1.supported_features = (
217 lsa.LSA_FEATURE_TDO_AUTH_INFO_AES_CIPHER
220 out_version, out_revision_info1, policy = OpenPolicyFallback(
221 conn,
222 b''.decode('utf-8'),
223 in_version,
224 in_revision_info1,
225 policy_access
228 info = conn.QueryInfoPolicy2(policy, lsa.LSA_POLICY_INFO_DNS)
230 return (policy, out_version, out_revision_info1, info)
232 def get_netlogon_dc_unc(self, conn, server, domain):
233 try:
234 info = conn.netr_DsRGetDCNameEx2(server,
235 None, 0, None, None, None,
236 netlogon.DS_RETURN_DNS_NAME)
237 return info.dc_unc
238 except RuntimeError:
239 return conn.netr_GetDcName(server, domain)
241 def get_netlogon_dc_info(self, conn, server):
242 info = conn.netr_DsRGetDCNameEx2(server,
243 None, 0, None, None, None,
244 netlogon.DS_RETURN_DNS_NAME)
245 return info
247 def netr_DomainTrust_to_name(self, t):
248 if t.trust_type == lsa.LSA_TRUST_TYPE_DOWNLEVEL:
249 return t.netbios_name
251 return t.dns_name
253 def netr_DomainTrust_to_type(self, a, t):
254 primary = None
255 primary_parent = None
256 for _t in a:
257 if _t.trust_flags & netlogon.NETR_TRUST_FLAG_PRIMARY:
258 primary = _t
259 if not _t.trust_flags & netlogon.NETR_TRUST_FLAG_TREEROOT:
260 primary_parent = a[_t.parent_index]
261 break
263 if t.trust_flags & netlogon.NETR_TRUST_FLAG_IN_FOREST:
264 if t is primary_parent:
265 return "Parent"
267 if t.trust_flags & netlogon.NETR_TRUST_FLAG_TREEROOT:
268 return "TreeRoot"
270 parent = a[t.parent_index]
271 if parent is primary:
272 return "Child"
274 return "Shortcut"
276 if t.trust_attributes & lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE:
277 return "Forest"
279 return "External"
281 def netr_DomainTrust_to_transitive(self, t):
282 if t.trust_flags & netlogon.NETR_TRUST_FLAG_IN_FOREST:
283 return "Yes"
285 if t.trust_attributes & lsa.LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE:
286 return "No"
288 if t.trust_attributes & lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE:
289 return "Yes"
291 return "No"
293 def netr_DomainTrust_to_direction(self, t):
294 if t.trust_flags & netlogon.NETR_TRUST_FLAG_INBOUND and \
295 t.trust_flags & netlogon.NETR_TRUST_FLAG_OUTBOUND:
296 return "BOTH"
298 if t.trust_flags & netlogon.NETR_TRUST_FLAG_INBOUND:
299 return "INCOMING"
301 if t.trust_flags & netlogon.NETR_TRUST_FLAG_OUTBOUND:
302 return "OUTGOING"
304 return "INVALID"
306 def generic_enum_to_string(self, e_dict, v, names_only=False):
307 try:
308 w = e_dict[v]
309 except KeyError:
310 v32 = self._uint32(v)
311 w = "__unknown__%08X__" % v32
313 r = "0x%x (%s)" % (v, w)
314 return r
316 def generic_bitmap_to_string(self, b_dict, v, names_only=False):
318 s = []
320 c = v
321 for b in sorted(b_dict.keys()):
322 if not (c & b):
323 continue
324 c &= ~b
325 s += [b_dict[b]]
327 if c != 0:
328 c32 = self._uint32(c)
329 s += ["__unknown_%08X__" % c32]
331 w = ",".join(s)
332 if names_only:
333 return w
334 r = "0x%x (%s)" % (v, w)
335 return r
337 def trustType_string(self, v):
338 types = {
339 lsa.LSA_TRUST_TYPE_DOWNLEVEL: "DOWNLEVEL",
340 lsa.LSA_TRUST_TYPE_UPLEVEL: "UPLEVEL",
341 lsa.LSA_TRUST_TYPE_MIT: "MIT",
342 lsa.LSA_TRUST_TYPE_DCE: "DCE",
344 return self.generic_enum_to_string(types, v)
346 def trustDirection_string(self, v):
347 directions = {
348 lsa.LSA_TRUST_DIRECTION_INBOUND |
349 lsa.LSA_TRUST_DIRECTION_OUTBOUND: "BOTH",
350 lsa.LSA_TRUST_DIRECTION_INBOUND: "INBOUND",
351 lsa.LSA_TRUST_DIRECTION_OUTBOUND: "OUTBOUND",
353 return self.generic_enum_to_string(directions, v)
355 def trustAttributes_string(self, v):
356 attributes = {
357 lsa.LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE: "NON_TRANSITIVE",
358 lsa.LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY: "UPLEVEL_ONLY",
359 lsa.LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN: "QUARANTINED_DOMAIN",
360 lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE: "FOREST_TRANSITIVE",
361 lsa.LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION: "CROSS_ORGANIZATION",
362 lsa.LSA_TRUST_ATTRIBUTE_WITHIN_FOREST: "WITHIN_FOREST",
363 lsa.LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL: "TREAT_AS_EXTERNAL",
364 lsa.LSA_TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION: "USES_RC4_ENCRYPTION",
366 return self.generic_bitmap_to_string(attributes, v)
368 def kerb_EncTypes_string(self, v):
369 enctypes = {
370 security.KERB_ENCTYPE_DES_CBC_CRC: "DES_CBC_CRC",
371 security.KERB_ENCTYPE_DES_CBC_MD5: "DES_CBC_MD5",
372 security.KERB_ENCTYPE_RC4_HMAC_MD5: "RC4_HMAC_MD5",
373 security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96: "AES128_CTS_HMAC_SHA1_96",
374 security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96: "AES256_CTS_HMAC_SHA1_96",
375 security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK: "AES256_CTS_HMAC_SHA1_96-SK",
376 security.KERB_ENCTYPE_FAST_SUPPORTED: "FAST_SUPPORTED",
377 security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED: "COMPOUND_IDENTITY_SUPPORTED",
378 security.KERB_ENCTYPE_CLAIMS_SUPPORTED: "CLAIMS_SUPPORTED",
379 security.KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED: "RESOURCE_SID_COMPRESSION_DISABLED",
381 return self.generic_bitmap_to_string(enctypes, v)
383 def entry_tln_status(self, e_flags, ):
384 if e_flags == 0:
385 return "Status[Enabled]"
387 flags = {
388 lsa.LSA_TLN_DISABLED_NEW: "Disabled-New",
389 lsa.LSA_TLN_DISABLED_ADMIN: "Disabled",
390 lsa.LSA_TLN_DISABLED_CONFLICT: "Disabled-Conflicting",
392 return "Status[%s]" % self.generic_bitmap_to_string(flags, e_flags, names_only=True)
394 def entry_dom_status(self, e_flags):
395 if e_flags == 0:
396 return "Status[Enabled]"
398 flags = {
399 lsa.LSA_SID_DISABLED_ADMIN: "Disabled-SID",
400 lsa.LSA_SID_DISABLED_CONFLICT: "Disabled-SID-Conflicting",
401 lsa.LSA_NB_DISABLED_ADMIN: "Disabled-NB",
402 lsa.LSA_NB_DISABLED_CONFLICT: "Disabled-NB-Conflicting",
404 return "Status[%s]" % self.generic_bitmap_to_string(flags, e_flags, names_only=True)
406 def write_forest_trust_info(self, fti, tln=None, collisions=None):
407 if tln is not None:
408 tln_string = " TDO[%s]" % tln
409 else:
410 tln_string = ""
412 self.outf.write("Namespaces[%d]%s:\n" % (
413 len(fti.entries), tln_string))
415 for i, e in enumerate(fti.entries):
417 flags = e.flags
418 collision_string = ""
420 if collisions is not None:
421 for c in collisions.entries:
422 if c.index != i:
423 continue
424 flags = c.flags
425 collision_string = " Collision[%s]" % (c.name.string)
427 d = e.forest_trust_data
428 if e.type == lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
429 self.outf.write("TLN: %-32s DNS[*.%s]%s\n" % (
430 self.entry_tln_status(flags),
431 d.string, collision_string))
432 elif e.type == lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
433 self.outf.write("TLN_EX: %-29s DNS[*.%s]\n" % (
434 "", d.string))
435 elif e.type == lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
436 self.outf.write("DOM: %-32s DNS[%s] Netbios[%s] SID[%s]%s\n" % (
437 self.entry_dom_status(flags),
438 d.dns_domain_name.string,
439 d.netbios_domain_name.string,
440 d.domain_sid, collision_string))
441 return
444 class cmd_domain_trust_list(DomainTrustCommand):
445 """List domain trusts."""
447 synopsis = "%prog [options]"
449 takes_optiongroups = {
450 "sambaopts": options.SambaOptions,
451 "versionopts": options.VersionOptions,
452 "localdcopts": LocalDCCredentialsOptions,
455 takes_options = [
458 def run(self, sambaopts=None, versionopts=None, localdcopts=None):
460 local_server = self.setup_local_server(sambaopts, localdcopts)
461 try:
462 local_netlogon = self.new_local_netlogon_connection()
463 except RuntimeError as error:
464 raise self.LocalRuntimeError(self, error, "failed to connect netlogon server")
466 try:
467 local_netlogon_trusts = \
468 local_netlogon.netr_DsrEnumerateDomainTrusts(local_server,
469 netlogon.NETR_TRUST_FLAG_IN_FOREST |
470 netlogon.NETR_TRUST_FLAG_OUTBOUND |
471 netlogon.NETR_TRUST_FLAG_INBOUND)
472 except RuntimeError as error:
473 if self.check_runtime_error(error, werror.WERR_RPC_S_PROCNUM_OUT_OF_RANGE):
474 # TODO: we could implement a fallback to lsa.EnumTrustDom()
475 raise CommandError("LOCAL_DC[%s]: netr_DsrEnumerateDomainTrusts not supported." % (
476 local_server))
477 raise self.LocalRuntimeError(self, error, "netr_DsrEnumerateDomainTrusts failed")
479 a = local_netlogon_trusts.array
480 for t in a:
481 if t.trust_flags & netlogon.NETR_TRUST_FLAG_PRIMARY:
482 continue
483 self.outf.write("%-14s %-15s %-19s %s\n" % (
484 "Type[%s]" % self.netr_DomainTrust_to_type(a, t),
485 "Transitive[%s]" % self.netr_DomainTrust_to_transitive(t),
486 "Direction[%s]" % self.netr_DomainTrust_to_direction(t),
487 "Name[%s]" % self.netr_DomainTrust_to_name(t)))
488 return
491 class cmd_domain_trust_show(DomainTrustCommand):
492 """Show trusted domain details."""
494 synopsis = "%prog NAME [options]"
496 takes_optiongroups = {
497 "sambaopts": options.SambaOptions,
498 "versionopts": options.VersionOptions,
499 "localdcopts": LocalDCCredentialsOptions,
502 takes_options = [
505 takes_args = ["domain"]
507 def run(self, domain, sambaopts=None, versionopts=None, localdcopts=None):
509 self.setup_local_server(sambaopts, localdcopts)
510 try:
511 local_lsa = self.new_local_lsa_connection()
512 except RuntimeError as error:
513 raise self.LocalRuntimeError(self, error, "failed to connect lsa server")
515 try:
516 local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
518 local_policy,
519 local_version,
520 local_revision_info1,
521 local_lsa_info
522 ) = self.get_lsa_info(local_lsa, local_policy_access)
523 except RuntimeError as error:
524 raise self.LocalRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
526 self.outf.write("LocalDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
527 local_lsa_info.name.string,
528 local_lsa_info.dns_domain.string,
529 local_lsa_info.sid))
531 lsaString = lsa.String()
532 lsaString.string = domain
533 try:
534 local_tdo_full = \
535 local_lsa.QueryTrustedDomainInfoByName(local_policy,
536 lsaString,
537 lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
538 local_tdo_info = local_tdo_full.info_ex
539 local_tdo_posix = local_tdo_full.posix_offset
540 except NTSTATUSError as error:
541 if self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
542 raise CommandError("trusted domain object does not exist for domain [%s]" % domain)
544 raise self.LocalRuntimeError(self, error, "QueryTrustedDomainInfoByName(FULL_INFO) failed")
546 try:
547 local_tdo_enctypes = \
548 local_lsa.QueryTrustedDomainInfoByName(local_policy,
549 lsaString,
550 lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES)
551 except NTSTATUSError as error:
552 if self.check_runtime_error(error, ntstatus.NT_STATUS_INVALID_PARAMETER):
553 error = None
554 if self.check_runtime_error(error, ntstatus.NT_STATUS_INVALID_INFO_CLASS):
555 error = None
557 if error is not None:
558 raise self.LocalRuntimeError(self, error,
559 "QueryTrustedDomainInfoByName(SUPPORTED_ENCRYPTION_TYPES) failed")
561 local_tdo_enctypes = lsa.TrustDomainInfoSupportedEncTypes()
562 local_tdo_enctypes.enc_types = 0
564 try:
565 local_tdo_forest = None
566 if local_tdo_info.trust_attributes & lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE:
567 local_tdo_forest = \
568 local_lsa.lsaRQueryForestTrustInformation(local_policy,
569 lsaString,
570 lsa.LSA_FOREST_TRUST_DOMAIN_INFO)
571 except RuntimeError as error:
572 if self.check_runtime_error(error, ntstatus.NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE):
573 error = None
574 if self.check_runtime_error(error, ntstatus.NT_STATUS_NOT_FOUND):
575 error = None
576 if error is not None:
577 raise self.LocalRuntimeError(self, error, "lsaRQueryForestTrustInformation failed")
579 local_tdo_forest = lsa.ForestTrustInformation()
580 local_tdo_forest.count = 0
581 local_tdo_forest.entries = []
583 self.outf.write("TrustedDomain:\n\n")
584 self.outf.write("NetbiosName: %s\n" % local_tdo_info.netbios_name.string)
585 if local_tdo_info.netbios_name.string != local_tdo_info.domain_name.string:
586 self.outf.write("DnsName: %s\n" % local_tdo_info.domain_name.string)
587 self.outf.write("SID: %s\n" % local_tdo_info.sid)
588 self.outf.write("Type: %s\n" % self.trustType_string(local_tdo_info.trust_type))
589 self.outf.write("Direction: %s\n" % self.trustDirection_string(local_tdo_info.trust_direction))
590 self.outf.write("Attributes: %s\n" % self.trustAttributes_string(local_tdo_info.trust_attributes))
591 posix_offset_u32 = ctypes.c_uint32(local_tdo_posix.posix_offset).value
592 posix_offset_i32 = ctypes.c_int32(local_tdo_posix.posix_offset).value
593 self.outf.write("PosixOffset: 0x%08X (%d)\n" % (posix_offset_u32, posix_offset_i32))
594 self.outf.write("kerb_EncTypes: %s\n" % self.kerb_EncTypes_string(local_tdo_enctypes.enc_types))
596 if local_tdo_info.trust_attributes & lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE:
597 self.write_forest_trust_info(local_tdo_forest,
598 tln=local_tdo_info.domain_name.string)
600 return
602 class cmd_domain_trust_modify(DomainTrustCommand):
603 """Show trusted domain details."""
605 synopsis = "%prog NAME [options]"
607 takes_optiongroups = {
608 "sambaopts": options.SambaOptions,
609 "versionopts": options.VersionOptions,
610 "localdcopts": LocalDCCredentialsOptions,
613 takes_options = [
614 Option("--use-aes-keys", action="store_true",
615 help="The trust uses AES kerberos keys.",
616 dest='use_aes_keys',
617 default=None),
618 Option("--no-aes-keys", action="store_true",
619 help="The trust does not have any support for AES kerberos keys.",
620 dest='disable_aes_keys',
621 default=None),
622 Option("--raw-kerb-enctypes", action="store",
623 help="The raw kerberos enctype bits",
624 dest='kerb_enctypes',
625 default=None),
628 takes_args = ["domain"]
630 def run(self, domain, sambaopts=None, versionopts=None, localdcopts=None,
631 disable_aes_keys=None, use_aes_keys=None, kerb_enctypes=None):
633 num_modifications = 0
635 enctype_args = 0
636 if kerb_enctypes is not None:
637 enctype_args += 1
638 if use_aes_keys is not None:
639 enctype_args += 1
640 if disable_aes_keys is not None:
641 enctype_args += 1
642 if enctype_args > 1:
643 raise CommandError("--no-aes-keys, --use-aes-keys and --raw-kerb-enctypes are mutually exclusive")
644 if enctype_args == 1:
645 num_modifications += 1
647 if num_modifications == 0:
648 raise CommandError("modification arguments are required, try --help")
650 self.setup_local_server(sambaopts, localdcopts)
651 try:
652 local_lsa = self.new_local_lsa_connection()
653 except RuntimeError as error:
654 raise self.LocalRuntimeError(self, error, "failed to connect to lsa server")
656 try:
657 local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
659 local_policy,
660 local_version,
661 local_revision_info1,
662 local_lsa_info
663 ) = self.get_lsa_info(local_lsa, local_policy_access)
664 except RuntimeError as error:
665 raise self.LocalRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
667 self.outf.write("LocalDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
668 local_lsa_info.name.string,
669 local_lsa_info.dns_domain.string,
670 local_lsa_info.sid))
672 if enctype_args == 1:
673 lsaString = lsa.String()
674 lsaString.string = domain
676 try:
677 local_tdo_enctypes = \
678 local_lsa.QueryTrustedDomainInfoByName(local_policy,
679 lsaString,
680 lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES)
681 except NTSTATUSError as error:
682 if self.check_runtime_error(error, ntstatus.NT_STATUS_INVALID_PARAMETER):
683 error = None
684 if self.check_runtime_error(error, ntstatus.NT_STATUS_INVALID_INFO_CLASS):
685 error = None
687 if error is not None:
688 raise self.LocalRuntimeError(self, error,
689 "QueryTrustedDomainInfoByName(SUPPORTED_ENCRYPTION_TYPES) failed")
691 local_tdo_enctypes = lsa.TrustDomainInfoSupportedEncTypes()
692 local_tdo_enctypes.enc_types = 0
694 self.outf.write("Old kerb_EncTypes: %s\n" % self.kerb_EncTypes_string(local_tdo_enctypes.enc_types))
696 enc_types = lsa.TrustDomainInfoSupportedEncTypes()
697 if kerb_enctypes is not None:
698 enc_types.enc_types = int(kerb_enctypes, base=0)
699 elif use_aes_keys is not None:
700 enc_types.enc_types = security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
701 enc_types.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
702 elif disable_aes_keys is not None:
703 # CVE-2022-37966: Trust objects are no longer assumed to support
704 # RC4, so we must indicate support explicitly.
705 enc_types.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5
706 else:
707 raise CommandError("Internal error should be checked above")
709 if enc_types.enc_types != local_tdo_enctypes.enc_types:
710 try:
711 local_tdo_enctypes = \
712 local_lsa.SetTrustedDomainInfoByName(local_policy,
713 lsaString,
714 lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES,
715 enc_types)
716 self.outf.write("New kerb_EncTypes: %s\n" % self.kerb_EncTypes_string(enc_types.enc_types))
717 except NTSTATUSError as error:
718 if error is not None:
719 raise self.LocalRuntimeError(self, error,
720 "SetTrustedDomainInfoByName(SUPPORTED_ENCRYPTION_TYPES) failed")
721 else:
722 self.outf.write("No kerb_EncTypes update needed\n")
724 return
726 class cmd_domain_trust_create(DomainTrustCommand):
727 """Create a domain or forest trust."""
729 synopsis = "%prog DOMAIN [options]"
731 takes_optiongroups = {
732 "sambaopts": options.SambaOptions,
733 "versionopts": options.VersionOptions,
734 "credopts": options.CredentialsOptions,
735 "localdcopts": LocalDCCredentialsOptions,
738 takes_options = [
739 Option("--type", type="choice", metavar="TYPE",
740 choices=["external", "forest"],
741 help="The type of the trust: 'external' or 'forest'.",
742 dest='trust_type',
743 default="external"),
744 Option("--direction", type="choice", metavar="DIRECTION",
745 choices=["incoming", "outgoing", "both"],
746 help="The trust direction: 'incoming', 'outgoing' or 'both'.",
747 dest='trust_direction',
748 default="both"),
749 Option("--create-location", type="choice", metavar="LOCATION",
750 choices=["local", "both"],
751 help="Where to create the trusted domain object: 'local' or 'both'.",
752 dest='create_location',
753 default="both"),
754 Option("--cross-organisation", action="store_true",
755 help="The related domains does not belong to the same organisation.",
756 dest='cross_organisation',
757 default=False),
758 Option("--quarantined", type="choice", metavar="yes|no",
759 choices=["yes", "no", None],
760 help="Special SID filtering rules are applied to the trust. "
761 "With --type=external the default is yes. "
762 "With --type=forest the default is no.",
763 dest='quarantined_arg',
764 default=None),
765 Option("--not-transitive", action="store_true",
766 help="The forest trust is not transitive.",
767 dest='not_transitive',
768 default=False),
769 Option("--treat-as-external", action="store_true",
770 help="The treat the forest trust as external.",
771 dest='treat_as_external',
772 default=False),
773 Option("--no-aes-keys", action="store_false",
774 help="The trust does not use AES kerberos keys.",
775 dest='use_aes_keys',
776 default=True),
777 Option("--skip-validation", action="store_false",
778 help="Skip validation of the trust.",
779 dest='validate',
780 default=True),
783 takes_args = ["domain"]
785 def run(self, domain, sambaopts=None, localdcopts=None, credopts=None, versionopts=None,
786 trust_type=None, trust_direction=None, create_location=None,
787 cross_organisation=False, quarantined_arg=None,
788 not_transitive=False, treat_as_external=False,
789 use_aes_keys=False, validate=True):
791 lsaString = lsa.String()
793 quarantined = False
794 if quarantined_arg is None:
795 if trust_type == 'external':
796 quarantined = True
797 elif quarantined_arg == 'yes':
798 quarantined = True
800 if trust_type != 'forest':
801 if not_transitive:
802 raise CommandError("--not-transitive requires --type=forest")
803 if treat_as_external:
804 raise CommandError("--treat-as-external requires --type=forest")
806 enc_types = lsa.TrustDomainInfoSupportedEncTypes()
807 if use_aes_keys:
808 enc_types.enc_types = security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
809 enc_types.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
810 else:
811 # CVE-2022-37966: Trust objects are no longer assumed to support
812 # RC4, so we must indicate support explicitly.
813 enc_types.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5
815 local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
816 local_policy_access |= lsa.LSA_POLICY_TRUST_ADMIN
817 local_policy_access |= lsa.LSA_POLICY_CREATE_SECRET
819 local_trust_info = lsa.TrustDomainInfoInfoEx()
820 local_trust_info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL
821 local_trust_info.trust_direction = 0
822 if trust_direction == "both":
823 local_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_INBOUND
824 local_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_OUTBOUND
825 elif trust_direction == "incoming":
826 local_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_INBOUND
827 elif trust_direction == "outgoing":
828 local_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_OUTBOUND
829 local_trust_info.trust_attributes = 0
830 if cross_organisation:
831 local_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION
832 if quarantined:
833 local_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
834 if trust_type == "forest":
835 local_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
836 if not_transitive:
837 local_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
838 if treat_as_external:
839 local_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL
841 def get_password(name):
842 password = None
843 while True:
844 if password is not None and password != '':
845 return password
846 password = getpass("New %s Password: " % name)
847 passwordverify = getpass("Retype %s Password: " % name)
848 if not password == passwordverify:
849 password = None
850 self.outf.write("Sorry, passwords do not match.\n")
852 incoming_secret = None
853 outgoing_secret = None
854 remote_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
855 if create_location == "local":
856 if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_INBOUND:
857 incoming_password = get_password("Incoming Trust")
858 incoming_secret = list(incoming_password.encode('utf-16-le'))
859 if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
860 outgoing_password = get_password("Outgoing Trust")
861 outgoing_secret = list(outgoing_password.encode('utf-16-le'))
863 remote_trust_info = None
864 else:
865 # We use 240 random bytes.
866 # Windows uses 28 or 240 random bytes. I guess it's
867 # based on the trust type external vs. forest.
869 # The initial trust password can be up to 512 bytes
870 # while the versioned passwords used for periodic updates
871 # can only be up to 498 bytes, as netr_ServerPasswordSet2()
872 # needs to pass the NL_PASSWORD_VERSION structure within the
873 # 512 bytes and a 2 bytes confounder is required.
875 def random_trust_secret(length):
876 pw = samba.generate_random_machine_password(length // 2, length // 2)
877 return list(pw.encode('utf-16-le'))
879 if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_INBOUND:
880 incoming_secret = random_trust_secret(240)
881 if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
882 outgoing_secret = random_trust_secret(240)
884 remote_policy_access |= lsa.LSA_POLICY_TRUST_ADMIN
885 remote_policy_access |= lsa.LSA_POLICY_CREATE_SECRET
887 remote_trust_info = lsa.TrustDomainInfoInfoEx()
888 remote_trust_info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL
889 remote_trust_info.trust_direction = 0
890 if trust_direction == "both":
891 remote_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_INBOUND
892 remote_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_OUTBOUND
893 elif trust_direction == "incoming":
894 remote_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_OUTBOUND
895 elif trust_direction == "outgoing":
896 remote_trust_info.trust_direction |= lsa.LSA_TRUST_DIRECTION_INBOUND
897 remote_trust_info.trust_attributes = 0
898 if cross_organisation:
899 remote_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION
900 if quarantined:
901 remote_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
902 if trust_type == "forest":
903 remote_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
904 if not_transitive:
905 remote_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
906 if treat_as_external:
907 remote_trust_info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL
909 local_server = self.setup_local_server(sambaopts, localdcopts)
910 try:
911 local_lsa = self.new_local_lsa_connection()
912 except RuntimeError as error:
913 raise self.LocalRuntimeError(self, error, "failed to connect lsa server")
915 try:
917 local_policy,
918 local_version,
919 local_revision_info1,
920 local_lsa_info
921 ) = self.get_lsa_info(local_lsa, local_policy_access)
922 except RuntimeError as error:
923 raise self.LocalRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
925 self.outf.write("LocalDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
926 local_lsa_info.name.string,
927 local_lsa_info.dns_domain.string,
928 local_lsa_info.sid))
930 try:
931 remote_server = self.setup_remote_server(credopts, domain)
932 except RuntimeError as error:
933 raise self.RemoteRuntimeError(self, error, "failed to locate remote server")
935 try:
936 remote_lsa = self.new_remote_lsa_connection()
937 except RuntimeError as error:
938 raise self.RemoteRuntimeError(self, error, "failed to connect lsa server")
940 try:
942 remote_policy,
943 remote_version,
944 remote_revision_info1,
945 remote_lsa_info
946 ) = self.get_lsa_info(remote_lsa, remote_policy_access)
947 except RuntimeError as error:
948 raise self.RemoteRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
950 self.outf.write("RemoteDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
951 remote_lsa_info.name.string,
952 remote_lsa_info.dns_domain.string,
953 remote_lsa_info.sid))
955 local_trust_info.domain_name.string = remote_lsa_info.dns_domain.string
956 local_trust_info.netbios_name.string = remote_lsa_info.name.string
957 local_trust_info.sid = remote_lsa_info.sid
959 if remote_trust_info:
960 remote_trust_info.domain_name.string = local_lsa_info.dns_domain.string
961 remote_trust_info.netbios_name.string = local_lsa_info.name.string
962 remote_trust_info.sid = local_lsa_info.sid
964 try:
965 lsaString.string = local_trust_info.domain_name.string
966 local_lsa.QueryTrustedDomainInfoByName(local_policy,
967 lsaString,
968 lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
969 raise CommandError("TrustedDomain %s already exist'" % lsaString.string)
970 except NTSTATUSError as error:
971 if not self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
972 raise self.LocalRuntimeError(self, error,
973 "QueryTrustedDomainInfoByName(%s, FULL_INFO) failed" % (
974 lsaString.string))
976 try:
977 lsaString.string = local_trust_info.netbios_name.string
978 local_lsa.QueryTrustedDomainInfoByName(local_policy,
979 lsaString,
980 lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
981 raise CommandError("TrustedDomain %s already exist'" % lsaString.string)
982 except NTSTATUSError as error:
983 if not self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
984 raise self.LocalRuntimeError(self, error,
985 "QueryTrustedDomainInfoByName(%s, FULL_INFO) failed" % (
986 lsaString.string))
988 if remote_trust_info:
989 try:
990 lsaString.string = remote_trust_info.domain_name.string
991 remote_lsa.QueryTrustedDomainInfoByName(remote_policy,
992 lsaString,
993 lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
994 raise CommandError("TrustedDomain %s already exist'" % lsaString.string)
995 except NTSTATUSError as error:
996 if not self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
997 raise self.RemoteRuntimeError(self, error,
998 "QueryTrustedDomainInfoByName(%s, FULL_INFO) failed" % (
999 lsaString.string))
1001 try:
1002 lsaString.string = remote_trust_info.netbios_name.string
1003 remote_lsa.QueryTrustedDomainInfoByName(remote_policy,
1004 lsaString,
1005 lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
1006 raise CommandError("TrustedDomain %s already exist'" % lsaString.string)
1007 except NTSTATUSError as error:
1008 if not self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
1009 raise self.RemoteRuntimeError(self, error,
1010 "QueryTrustedDomainInfoByName(%s, FULL_INFO) failed" % (
1011 lsaString.string))
1013 try:
1014 local_netlogon = self.new_local_netlogon_connection()
1015 except RuntimeError as error:
1016 raise self.LocalRuntimeError(self, error, "failed to connect netlogon server")
1018 try:
1019 local_netlogon_info = self.get_netlogon_dc_info(local_netlogon, local_server)
1020 except RuntimeError as error:
1021 raise self.LocalRuntimeError(self, error, "failed to get netlogon dc info")
1023 if remote_trust_info:
1024 try:
1025 remote_netlogon = self.new_remote_netlogon_connection()
1026 except RuntimeError as error:
1027 raise self.RemoteRuntimeError(self, error, "failed to connect netlogon server")
1029 try:
1030 remote_netlogon_dc_unc = self.get_netlogon_dc_unc(remote_netlogon,
1031 remote_server, domain)
1032 except RuntimeError as error:
1033 raise self.RemoteRuntimeError(self, error, "failed to get netlogon dc info")
1035 def generate_AuthInOutBlob(secret, update_time):
1036 if secret is None:
1037 blob = drsblobs.trustAuthInOutBlob()
1038 blob.count = 0
1040 return blob
1042 clear = drsblobs.AuthInfoClear()
1043 clear.size = len(secret)
1044 clear.password = secret
1046 info = drsblobs.AuthenticationInformation()
1047 info.LastUpdateTime = samba.unix2nttime(update_time)
1048 info.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR
1049 info.AuthInfo = clear
1051 array = drsblobs.AuthenticationInformationArray()
1052 array.count = 1
1053 array.array = [info]
1055 blob = drsblobs.trustAuthInOutBlob()
1056 blob.count = 1
1057 blob.current = array
1059 return blob
1061 update_time = samba.current_unix_time()
1062 incoming_blob = generate_AuthInOutBlob(incoming_secret, update_time)
1063 outgoing_blob = generate_AuthInOutBlob(outgoing_secret, update_time)
1065 local_tdo_handle = None
1066 remote_tdo_handle = None
1068 try:
1069 if remote_trust_info:
1070 self.outf.write("Creating remote TDO.\n")
1071 current_request = {"location": "remote", "name": "CreateTrustedDomainEx2"}
1072 remote_tdo_handle = CreateTrustedDomainFallback(
1073 remote_lsa,
1074 remote_policy,
1075 remote_trust_info,
1076 lsa.LSA_TRUSTED_DOMAIN_ALL_ACCESS,
1077 remote_version,
1078 remote_revision_info1,
1079 outgoing_blob,
1080 incoming_blob
1082 self.outf.write("Remote TDO created.\n")
1083 if enc_types:
1084 self.outf.write("Setting supported encryption types on remote TDO.\n")
1085 current_request = {"location": "remote", "name": "SetInformationTrustedDomain"}
1086 remote_lsa.SetInformationTrustedDomain(remote_tdo_handle,
1087 lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES,
1088 enc_types)
1090 self.outf.write("Creating local TDO.\n")
1091 current_request = {"location": "local", "name": "CreateTrustedDomainEx2"}
1092 local_tdo_handle = CreateTrustedDomainFallback(
1093 local_lsa,
1094 local_policy,
1095 local_trust_info,
1096 lsa.LSA_TRUSTED_DOMAIN_ALL_ACCESS,
1097 local_version,
1098 local_revision_info1,
1099 incoming_blob,
1100 outgoing_blob
1102 self.outf.write("Local TDO created\n")
1103 if enc_types:
1104 self.outf.write("Setting supported encryption types on local TDO.\n")
1105 current_request = {"location": "local", "name": "SetInformationTrustedDomain"}
1106 local_lsa.SetInformationTrustedDomain(local_tdo_handle,
1107 lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES,
1108 enc_types)
1109 except RuntimeError as error:
1110 self.outf.write("Error: %s failed %sly - cleaning up\n" % (
1111 current_request['name'], current_request['location']))
1112 if remote_tdo_handle:
1113 self.outf.write("Deleting remote TDO.\n")
1114 remote_lsa.DeleteObject(remote_tdo_handle)
1115 remote_tdo_handle = None
1116 if local_tdo_handle:
1117 self.outf.write("Deleting local TDO.\n")
1118 local_lsa.DeleteObject(local_tdo_handle)
1119 local_tdo_handle = None
1120 if current_request['location'] == "remote":
1121 raise self.RemoteRuntimeError(self, error, "%s" % (
1122 current_request['name']))
1123 raise self.LocalRuntimeError(self, error, "%s" % (
1124 current_request['name']))
1126 if validate:
1127 if local_trust_info.trust_attributes & lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE:
1128 self.outf.write("Setup local forest trust information...\n")
1129 try:
1130 # get all information about the remote trust
1131 # this triggers netr_GetForestTrustInformation to the remote domain
1132 # and lsaRSetForestTrustInformation() locally, but new top level
1133 # names are disabled by default.
1134 local_forest_info = \
1135 local_netlogon.netr_DsRGetForestTrustInformation(local_netlogon_info.dc_unc,
1136 remote_lsa_info.dns_domain.string,
1137 netlogon.DS_GFTI_UPDATE_TDO)
1138 except RuntimeError as error:
1139 raise self.LocalRuntimeError(self, error, "netr_DsRGetForestTrustInformation() failed")
1141 try:
1142 # here we try to enable all top level names
1143 local_forest_collision = \
1144 local_lsa.lsaRSetForestTrustInformation(local_policy,
1145 remote_lsa_info.dns_domain,
1146 lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
1147 local_forest_info,
1149 except RuntimeError as error:
1150 raise self.LocalRuntimeError(self, error, "lsaRSetForestTrustInformation() failed")
1152 self.write_forest_trust_info(local_forest_info,
1153 tln=remote_lsa_info.dns_domain.string,
1154 collisions=local_forest_collision)
1156 if remote_trust_info:
1157 self.outf.write("Setup remote forest trust information...\n")
1158 try:
1159 # get all information about the local trust (from the perspective of the remote domain)
1160 # this triggers netr_GetForestTrustInformation to our domain.
1161 # and lsaRSetForestTrustInformation() remotely, but new top level
1162 # names are disabled by default.
1163 remote_forest_info = \
1164 remote_netlogon.netr_DsRGetForestTrustInformation(remote_netlogon_dc_unc,
1165 local_lsa_info.dns_domain.string,
1166 netlogon.DS_GFTI_UPDATE_TDO)
1167 except RuntimeError as error:
1168 raise self.RemoteRuntimeError(self, error, "netr_DsRGetForestTrustInformation() failed")
1170 try:
1171 # here we try to enable all top level names
1172 remote_forest_collision = \
1173 remote_lsa.lsaRSetForestTrustInformation(remote_policy,
1174 local_lsa_info.dns_domain,
1175 lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
1176 remote_forest_info,
1178 except RuntimeError as error:
1179 raise self.RemoteRuntimeError(self, error, "lsaRSetForestTrustInformation() failed")
1181 self.write_forest_trust_info(remote_forest_info,
1182 tln=local_lsa_info.dns_domain.string,
1183 collisions=remote_forest_collision)
1185 if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
1186 self.outf.write("Validating outgoing trust...\n")
1187 try:
1188 local_trust_verify = local_netlogon.netr_LogonControl2Ex(local_netlogon_info.dc_unc,
1189 netlogon.NETLOGON_CONTROL_TC_VERIFY,
1191 remote_lsa_info.dns_domain.string)
1192 except RuntimeError as error:
1193 raise self.LocalRuntimeError(self, error, "NETLOGON_CONTROL_TC_VERIFY failed")
1195 local_trust_status = self._uint32(local_trust_verify.pdc_connection_status[0])
1196 local_conn_status = self._uint32(local_trust_verify.tc_connection_status[0])
1198 if local_trust_verify.flags & netlogon.NETLOGON_VERIFY_STATUS_RETURNED:
1199 local_validation = "LocalValidation: DC[%s] CONNECTION[%s] TRUST[%s] VERIFY_STATUS_RETURNED" % (
1200 local_trust_verify.trusted_dc_name,
1201 local_trust_verify.tc_connection_status[1],
1202 local_trust_verify.pdc_connection_status[1])
1203 else:
1204 local_validation = "LocalValidation: DC[%s] CONNECTION[%s] TRUST[%s]" % (
1205 local_trust_verify.trusted_dc_name,
1206 local_trust_verify.tc_connection_status[1],
1207 local_trust_verify.pdc_connection_status[1])
1209 if local_trust_status != werror.WERR_SUCCESS or local_conn_status != werror.WERR_SUCCESS:
1210 raise CommandError(local_validation)
1211 else:
1212 self.outf.write("OK: %s\n" % local_validation)
1214 if remote_trust_info:
1215 if remote_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
1216 self.outf.write("Validating incoming trust...\n")
1217 try:
1218 remote_trust_verify = \
1219 remote_netlogon.netr_LogonControl2Ex(remote_netlogon_dc_unc,
1220 netlogon.NETLOGON_CONTROL_TC_VERIFY,
1222 local_lsa_info.dns_domain.string)
1223 except RuntimeError as error:
1224 raise self.RemoteRuntimeError(self, error, "NETLOGON_CONTROL_TC_VERIFY failed")
1226 remote_trust_status = self._uint32(remote_trust_verify.pdc_connection_status[0])
1227 remote_conn_status = self._uint32(remote_trust_verify.tc_connection_status[0])
1229 if remote_trust_verify.flags & netlogon.NETLOGON_VERIFY_STATUS_RETURNED:
1230 remote_validation = "RemoteValidation: DC[%s] CONNECTION[%s] TRUST[%s] VERIFY_STATUS_RETURNED" % (
1231 remote_trust_verify.trusted_dc_name,
1232 remote_trust_verify.tc_connection_status[1],
1233 remote_trust_verify.pdc_connection_status[1])
1234 else:
1235 remote_validation = "RemoteValidation: DC[%s] CONNECTION[%s] TRUST[%s]" % (
1236 remote_trust_verify.trusted_dc_name,
1237 remote_trust_verify.tc_connection_status[1],
1238 remote_trust_verify.pdc_connection_status[1])
1240 if remote_trust_status != werror.WERR_SUCCESS or remote_conn_status != werror.WERR_SUCCESS:
1241 raise CommandError(remote_validation)
1242 else:
1243 self.outf.write("OK: %s\n" % remote_validation)
1245 if remote_tdo_handle is not None:
1246 try:
1247 remote_lsa.Close(remote_tdo_handle)
1248 except RuntimeError:
1249 pass
1250 remote_tdo_handle = None
1251 if local_tdo_handle is not None:
1252 try:
1253 local_lsa.Close(local_tdo_handle)
1254 except RuntimeError:
1255 pass
1256 local_tdo_handle = None
1258 self.outf.write("Success.\n")
1259 return
1262 class cmd_domain_trust_delete(DomainTrustCommand):
1263 """Delete a domain trust."""
1265 synopsis = "%prog DOMAIN [options]"
1267 takes_optiongroups = {
1268 "sambaopts": options.SambaOptions,
1269 "versionopts": options.VersionOptions,
1270 "credopts": options.CredentialsOptions,
1271 "localdcopts": LocalDCCredentialsOptions,
1274 takes_options = [
1275 Option("--delete-location", type="choice", metavar="LOCATION",
1276 choices=["local", "both"],
1277 help="Where to delete the trusted domain object: 'local' or 'both'.",
1278 dest='delete_location',
1279 default="both"),
1282 takes_args = ["domain"]
1284 def run(self, domain, sambaopts=None, localdcopts=None, credopts=None, versionopts=None,
1285 delete_location=None):
1287 local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
1288 local_policy_access |= lsa.LSA_POLICY_TRUST_ADMIN
1289 local_policy_access |= lsa.LSA_POLICY_CREATE_SECRET
1291 if delete_location == "local":
1292 remote_policy_access = None
1293 else:
1294 remote_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
1295 remote_policy_access |= lsa.LSA_POLICY_TRUST_ADMIN
1296 remote_policy_access |= lsa.LSA_POLICY_CREATE_SECRET
1298 self.setup_local_server(sambaopts, localdcopts)
1299 try:
1300 local_lsa = self.new_local_lsa_connection()
1301 except RuntimeError as error:
1302 raise self.LocalRuntimeError(self, error, "failed to connect lsa server")
1304 try:
1306 local_policy,
1307 local_version,
1308 local_revision_info1,
1309 local_lsa_info
1310 ) = self.get_lsa_info(local_lsa, local_policy_access)
1311 except RuntimeError as error:
1312 raise self.LocalRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
1314 self.outf.write("LocalDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
1315 local_lsa_info.name.string,
1316 local_lsa_info.dns_domain.string,
1317 local_lsa_info.sid))
1319 local_tdo_info = None
1320 local_tdo_handle = None
1321 remote_tdo_info = None
1322 remote_tdo_handle = None
1324 lsaString = lsa.String()
1325 try:
1326 lsaString.string = domain
1327 local_tdo_info = local_lsa.QueryTrustedDomainInfoByName(local_policy,
1328 lsaString, lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX)
1329 except NTSTATUSError as error:
1330 if self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
1331 raise CommandError("Failed to find trust for domain '%s'" % domain)
1332 raise self.RemoteRuntimeError(self, error, "failed to locate remote server")
1334 if remote_policy_access is not None:
1335 try:
1336 self.setup_remote_server(credopts, domain)
1337 except RuntimeError as error:
1338 raise self.RemoteRuntimeError(self, error, "failed to locate remote server")
1340 try:
1341 remote_lsa = self.new_remote_lsa_connection()
1342 except RuntimeError as error:
1343 raise self.RemoteRuntimeError(self, error, "failed to connect lsa server")
1345 try:
1347 remote_policy,
1348 remote_version,
1349 remote_revision_info1,
1350 remote_lsa_info
1351 ) = self.get_lsa_info(remote_lsa, remote_policy_access)
1352 except RuntimeError as error:
1353 raise self.RemoteRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
1355 self.outf.write("RemoteDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
1356 remote_lsa_info.name.string,
1357 remote_lsa_info.dns_domain.string,
1358 remote_lsa_info.sid))
1360 if remote_lsa_info.sid != local_tdo_info.sid or \
1361 remote_lsa_info.name.string != local_tdo_info.netbios_name.string or \
1362 remote_lsa_info.dns_domain.string != local_tdo_info.domain_name.string:
1363 raise CommandError("LocalTDO inconsistent: Netbios[%s] DNS[%s] SID[%s]" % (
1364 local_tdo_info.netbios_name.string,
1365 local_tdo_info.domain_name.string,
1366 local_tdo_info.sid))
1368 try:
1369 lsaString.string = local_lsa_info.dns_domain.string
1370 remote_tdo_info = \
1371 remote_lsa.QueryTrustedDomainInfoByName(remote_policy,
1372 lsaString,
1373 lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX)
1374 except NTSTATUSError as error:
1375 if not self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
1376 raise self.RemoteRuntimeError(self, error, "QueryTrustedDomainInfoByName(%s)" % (
1377 lsaString.string))
1379 if remote_tdo_info is not None:
1380 if local_lsa_info.sid != remote_tdo_info.sid or \
1381 local_lsa_info.name.string != remote_tdo_info.netbios_name.string or \
1382 local_lsa_info.dns_domain.string != remote_tdo_info.domain_name.string:
1383 raise CommandError("RemoteTDO inconsistent: Netbios[%s] DNS[%s] SID[%s]" % (
1384 remote_tdo_info.netbios_name.string,
1385 remote_tdo_info.domain_name.string,
1386 remote_tdo_info.sid))
1388 if local_tdo_info is not None:
1389 try:
1390 lsaString.string = local_tdo_info.domain_name.string
1391 local_tdo_handle = \
1392 local_lsa.OpenTrustedDomainByName(local_policy,
1393 lsaString,
1394 security.SEC_STD_DELETE)
1395 except RuntimeError as error:
1396 raise self.LocalRuntimeError(self, error, "OpenTrustedDomainByName(%s)" % (
1397 lsaString.string))
1399 local_lsa.DeleteObject(local_tdo_handle)
1400 local_tdo_handle = None
1402 if remote_tdo_info is not None:
1403 try:
1404 lsaString.string = remote_tdo_info.domain_name.string
1405 remote_tdo_handle = \
1406 remote_lsa.OpenTrustedDomainByName(remote_policy,
1407 lsaString,
1408 security.SEC_STD_DELETE)
1409 except RuntimeError as error:
1410 raise self.RemoteRuntimeError(self, error, "OpenTrustedDomainByName(%s)" % (
1411 lsaString.string))
1413 if remote_tdo_handle is not None:
1414 try:
1415 remote_lsa.DeleteObject(remote_tdo_handle)
1416 remote_tdo_handle = None
1417 self.outf.write("RemoteTDO deleted.\n")
1418 except RuntimeError as error:
1419 self.outf.write("%s\n" % self.RemoteRuntimeError(self, error, "DeleteObject() failed"))
1421 return
1424 class cmd_domain_trust_validate(DomainTrustCommand):
1425 """Validate a domain trust."""
1427 synopsis = "%prog DOMAIN [options]"
1429 takes_optiongroups = {
1430 "sambaopts": options.SambaOptions,
1431 "versionopts": options.VersionOptions,
1432 "credopts": options.CredentialsOptions,
1433 "localdcopts": LocalDCCredentialsOptions,
1436 takes_options = [
1437 Option("--validate-location", type="choice", metavar="LOCATION",
1438 choices=["local", "both"],
1439 help="Where to validate the trusted domain object: 'local' or 'both'.",
1440 dest='validate_location',
1441 default="both"),
1444 takes_args = ["domain"]
1446 def run(self, domain, sambaopts=None, versionopts=None, credopts=None, localdcopts=None,
1447 validate_location=None):
1449 local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
1451 local_server = self.setup_local_server(sambaopts, localdcopts)
1452 try:
1453 local_lsa = self.new_local_lsa_connection()
1454 except RuntimeError as error:
1455 raise self.LocalRuntimeError(self, error, "failed to connect lsa server")
1457 try:
1459 local_policy,
1460 local_version,
1461 local_revision_info1,
1462 local_lsa_info
1463 ) = self.get_lsa_info(local_lsa, local_policy_access)
1464 except RuntimeError as error:
1465 raise self.LocalRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
1467 self.outf.write("LocalDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
1468 local_lsa_info.name.string,
1469 local_lsa_info.dns_domain.string,
1470 local_lsa_info.sid))
1472 try:
1473 lsaString = lsa.String()
1474 lsaString.string = domain
1475 local_tdo_info = \
1476 local_lsa.QueryTrustedDomainInfoByName(local_policy,
1477 lsaString,
1478 lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX)
1479 except NTSTATUSError as error:
1480 if self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
1481 raise CommandError("trusted domain object does not exist for domain [%s]" % domain)
1483 raise self.LocalRuntimeError(self, error, "QueryTrustedDomainInfoByName(INFO_EX) failed")
1485 self.outf.write("LocalTDO Netbios[%s] DNS[%s] SID[%s]\n" % (
1486 local_tdo_info.netbios_name.string,
1487 local_tdo_info.domain_name.string,
1488 local_tdo_info.sid))
1490 try:
1491 local_netlogon = self.new_local_netlogon_connection()
1492 except RuntimeError as error:
1493 raise self.LocalRuntimeError(self, error, "failed to connect netlogon server")
1495 try:
1496 local_trust_verify = \
1497 local_netlogon.netr_LogonControl2Ex(local_server,
1498 netlogon.NETLOGON_CONTROL_TC_VERIFY,
1500 local_tdo_info.domain_name.string)
1501 except RuntimeError as error:
1502 raise self.LocalRuntimeError(self, error, "NETLOGON_CONTROL_TC_VERIFY failed")
1504 local_trust_status = self._uint32(local_trust_verify.pdc_connection_status[0])
1505 local_conn_status = self._uint32(local_trust_verify.tc_connection_status[0])
1507 if local_trust_verify.flags & netlogon.NETLOGON_VERIFY_STATUS_RETURNED:
1508 local_validation = "LocalValidation: DC[%s] CONNECTION[%s] TRUST[%s] VERIFY_STATUS_RETURNED" % (
1509 local_trust_verify.trusted_dc_name,
1510 local_trust_verify.tc_connection_status[1],
1511 local_trust_verify.pdc_connection_status[1])
1512 else:
1513 local_validation = "LocalValidation: DC[%s] CONNECTION[%s] TRUST[%s]" % (
1514 local_trust_verify.trusted_dc_name,
1515 local_trust_verify.tc_connection_status[1],
1516 local_trust_verify.pdc_connection_status[1])
1518 if local_trust_status != werror.WERR_SUCCESS or local_conn_status != werror.WERR_SUCCESS:
1519 raise CommandError(local_validation)
1520 else:
1521 self.outf.write("OK: %s\n" % local_validation)
1523 try:
1524 server = local_trust_verify.trusted_dc_name.replace('\\', '')
1525 domain_and_server = "%s\\%s" % (local_tdo_info.domain_name.string, server)
1526 local_trust_rediscover = \
1527 local_netlogon.netr_LogonControl2Ex(local_server,
1528 netlogon.NETLOGON_CONTROL_REDISCOVER,
1530 domain_and_server)
1531 except RuntimeError as error:
1532 raise self.LocalRuntimeError(self, error, "NETLOGON_CONTROL_REDISCOVER failed")
1534 local_conn_status = self._uint32(local_trust_rediscover.tc_connection_status[0])
1535 local_rediscover = "LocalRediscover: DC[%s] CONNECTION[%s]" % (
1536 local_trust_rediscover.trusted_dc_name,
1537 local_trust_rediscover.tc_connection_status[1])
1539 if local_conn_status != werror.WERR_SUCCESS:
1540 raise CommandError(local_rediscover)
1541 else:
1542 self.outf.write("OK: %s\n" % local_rediscover)
1544 if validate_location != "local":
1545 try:
1546 remote_server = self.setup_remote_server(credopts, domain, require_pdc=False)
1547 except RuntimeError as error:
1548 raise self.RemoteRuntimeError(self, error, "failed to locate remote server")
1550 try:
1551 remote_netlogon = self.new_remote_netlogon_connection()
1552 except RuntimeError as error:
1553 raise self.RemoteRuntimeError(self, error, "failed to connect netlogon server")
1555 try:
1556 remote_trust_verify = \
1557 remote_netlogon.netr_LogonControl2Ex(remote_server,
1558 netlogon.NETLOGON_CONTROL_TC_VERIFY,
1560 local_lsa_info.dns_domain.string)
1561 except RuntimeError as error:
1562 raise self.RemoteRuntimeError(self, error, "NETLOGON_CONTROL_TC_VERIFY failed")
1564 remote_trust_status = self._uint32(remote_trust_verify.pdc_connection_status[0])
1565 remote_conn_status = self._uint32(remote_trust_verify.tc_connection_status[0])
1567 if remote_trust_verify.flags & netlogon.NETLOGON_VERIFY_STATUS_RETURNED:
1568 remote_validation = "RemoteValidation: DC[%s] CONNECTION[%s] TRUST[%s] VERIFY_STATUS_RETURNED" % (
1569 remote_trust_verify.trusted_dc_name,
1570 remote_trust_verify.tc_connection_status[1],
1571 remote_trust_verify.pdc_connection_status[1])
1572 else:
1573 remote_validation = "RemoteValidation: DC[%s] CONNECTION[%s] TRUST[%s]" % (
1574 remote_trust_verify.trusted_dc_name,
1575 remote_trust_verify.tc_connection_status[1],
1576 remote_trust_verify.pdc_connection_status[1])
1578 if remote_trust_status != werror.WERR_SUCCESS or remote_conn_status != werror.WERR_SUCCESS:
1579 raise CommandError(remote_validation)
1580 else:
1581 self.outf.write("OK: %s\n" % remote_validation)
1583 try:
1584 server = remote_trust_verify.trusted_dc_name.replace('\\', '')
1585 domain_and_server = "%s\\%s" % (local_lsa_info.dns_domain.string, server)
1586 remote_trust_rediscover = \
1587 remote_netlogon.netr_LogonControl2Ex(remote_server,
1588 netlogon.NETLOGON_CONTROL_REDISCOVER,
1590 domain_and_server)
1591 except RuntimeError as error:
1592 raise self.RemoteRuntimeError(self, error, "NETLOGON_CONTROL_REDISCOVER failed")
1594 remote_conn_status = self._uint32(remote_trust_rediscover.tc_connection_status[0])
1596 remote_rediscover = "RemoteRediscover: DC[%s] CONNECTION[%s]" % (
1597 remote_trust_rediscover.trusted_dc_name,
1598 remote_trust_rediscover.tc_connection_status[1])
1600 if remote_conn_status != werror.WERR_SUCCESS:
1601 raise CommandError(remote_rediscover)
1602 else:
1603 self.outf.write("OK: %s\n" % remote_rediscover)
1605 return
1608 class cmd_domain_trust_namespaces(DomainTrustCommand):
1609 """Manage forest trust namespaces."""
1611 synopsis = "%prog [DOMAIN] [options]"
1613 takes_optiongroups = {
1614 "sambaopts": options.SambaOptions,
1615 "versionopts": options.VersionOptions,
1616 "localdcopts": LocalDCCredentialsOptions,
1619 takes_options = [
1620 Option("--refresh", type="choice", metavar="check|store",
1621 choices=["check", "store", None],
1622 help="List and maybe store refreshed forest trust information: 'check' or 'store'.",
1623 dest='refresh',
1624 default=None),
1625 Option("--enable-all", action="store_true",
1626 help="Try to update disabled entries, not allowed with --refresh=check.",
1627 dest='enable_all',
1628 default=False),
1629 Option("--enable-tln", action="append", metavar='DNSDOMAIN',
1630 help="Enable a top level name entry. Can be specified multiple times.",
1631 dest='enable_tln',
1632 default=[]),
1633 Option("--disable-tln", action="append", metavar='DNSDOMAIN',
1634 help="Disable a top level name entry. Can be specified multiple times.",
1635 dest='disable_tln',
1636 default=[]),
1637 Option("--add-tln-ex", action="append", metavar='DNSDOMAIN',
1638 help="Add a top level exclusion entry. Can be specified multiple times.",
1639 dest='add_tln_ex',
1640 default=[]),
1641 Option("--delete-tln-ex", action="append", metavar='DNSDOMAIN',
1642 help="Delete a top level exclusion entry. Can be specified multiple times.",
1643 dest='delete_tln_ex',
1644 default=[]),
1645 Option("--enable-nb", action="append", metavar='NETBIOSDOMAIN',
1646 help="Enable a netbios name in a domain entry. Can be specified multiple times.",
1647 dest='enable_nb',
1648 default=[]),
1649 Option("--disable-nb", action="append", metavar='NETBIOSDOMAIN',
1650 help="Disable a netbios name in a domain entry. Can be specified multiple times.",
1651 dest='disable_nb',
1652 default=[]),
1653 Option("--enable-sid", action="append", metavar='DOMAINSID',
1654 help="Enable a SID in a domain entry. Can be specified multiple times.",
1655 dest='enable_sid_str',
1656 default=[]),
1657 Option("--disable-sid", action="append", metavar='DOMAINSID',
1658 help="Disable a SID in a domain entry. Can be specified multiple times.",
1659 dest='disable_sid_str',
1660 default=[]),
1661 Option("--add-upn-suffix", action="append", metavar='DNSDOMAIN',
1662 help="Add a new uPNSuffixes attribute for the local forest. Can be specified multiple times.",
1663 dest='add_upn',
1664 default=[]),
1665 Option("--delete-upn-suffix", action="append", metavar='DNSDOMAIN',
1666 help="Delete an existing uPNSuffixes attribute of the local forest. Can be specified multiple times.",
1667 dest='delete_upn',
1668 default=[]),
1669 Option("--add-spn-suffix", action="append", metavar='DNSDOMAIN',
1670 help="Add a new msDS-SPNSuffixes attribute for the local forest. Can be specified multiple times.",
1671 dest='add_spn',
1672 default=[]),
1673 Option("--delete-spn-suffix", action="append", metavar='DNSDOMAIN',
1674 help="Delete an existing msDS-SPNSuffixes attribute of the local forest. Can be specified multiple times.",
1675 dest='delete_spn',
1676 default=[]),
1679 takes_args = ["domain?"]
1681 def run(self, domain=None, sambaopts=None, localdcopts=None, versionopts=None,
1682 refresh=None, enable_all=False,
1683 enable_tln=None, disable_tln=None, add_tln_ex=None, delete_tln_ex=None,
1684 enable_sid_str=None, disable_sid_str=None, enable_nb=None, disable_nb=None,
1685 add_upn=None, delete_upn=None, add_spn=None, delete_spn=None):
1687 if enable_tln is None:
1688 enable_tln = []
1689 if disable_tln is None:
1690 disable_tln = []
1691 if add_tln_ex is None:
1692 add_tln_ex = []
1693 if delete_tln_ex is None:
1694 delete_tln_ex = []
1695 if enable_sid_str is None:
1696 enable_sid_str = []
1697 if disable_sid_str is None:
1698 disable_sid_str = []
1699 if enable_nb is None:
1700 enable_nb = []
1701 if disable_nb is None:
1702 disable_nb = []
1703 if add_upn is None:
1704 add_upn = []
1705 if delete_upn is None:
1706 delete_upn = []
1707 if add_spn is None:
1708 add_spn = []
1709 if delete_spn is None:
1710 delete_spn = []
1712 require_update = False
1714 if domain is None:
1715 if refresh == "store":
1716 raise CommandError("--refresh=%s not allowed without DOMAIN" % refresh)
1718 if enable_all:
1719 raise CommandError("--enable-all not allowed without DOMAIN")
1721 if len(enable_tln) > 0:
1722 raise CommandError("--enable-tln not allowed without DOMAIN")
1723 if len(disable_tln) > 0:
1724 raise CommandError("--disable-tln not allowed without DOMAIN")
1726 if len(add_tln_ex) > 0:
1727 raise CommandError("--add-tln-ex not allowed without DOMAIN")
1728 if len(delete_tln_ex) > 0:
1729 raise CommandError("--delete-tln-ex not allowed without DOMAIN")
1731 if len(enable_nb) > 0:
1732 raise CommandError("--enable-nb not allowed without DOMAIN")
1733 if len(disable_nb) > 0:
1734 raise CommandError("--disable-nb not allowed without DOMAIN")
1736 if len(enable_sid_str) > 0:
1737 raise CommandError("--enable-sid not allowed without DOMAIN")
1738 if len(disable_sid_str) > 0:
1739 raise CommandError("--disable-sid not allowed without DOMAIN")
1741 if len(add_upn) > 0:
1742 for n in add_upn:
1743 if not n.startswith("*."):
1744 continue
1745 raise CommandError("value[%s] specified for --add-upn-suffix should not include with '*.'" % n)
1746 require_update = True
1747 if len(delete_upn) > 0:
1748 for n in delete_upn:
1749 if not n.startswith("*."):
1750 continue
1751 raise CommandError("value[%s] specified for --delete-upn-suffix should not include with '*.'" % n)
1752 require_update = True
1753 for a in add_upn:
1754 for d in delete_upn:
1755 if a.lower() != d.lower():
1756 continue
1757 raise CommandError("value[%s] specified for --add-upn-suffix and --delete-upn-suffix" % a)
1759 if len(add_spn) > 0:
1760 for n in add_spn:
1761 if not n.startswith("*."):
1762 continue
1763 raise CommandError("value[%s] specified for --add-spn-suffix should not include with '*.'" % n)
1764 require_update = True
1765 if len(delete_spn) > 0:
1766 for n in delete_spn:
1767 if not n.startswith("*."):
1768 continue
1769 raise CommandError("value[%s] specified for --delete-spn-suffix should not include with '*.'" % n)
1770 require_update = True
1771 for a in add_spn:
1772 for d in delete_spn:
1773 if a.lower() != d.lower():
1774 continue
1775 raise CommandError("value[%s] specified for --add-spn-suffix and --delete-spn-suffix" % a)
1776 else:
1777 if len(add_upn) > 0:
1778 raise CommandError("--add-upn-suffix not allowed together with DOMAIN")
1779 if len(delete_upn) > 0:
1780 raise CommandError("--delete-upn-suffix not allowed together with DOMAIN")
1781 if len(add_spn) > 0:
1782 raise CommandError("--add-spn-suffix not allowed together with DOMAIN")
1783 if len(delete_spn) > 0:
1784 raise CommandError("--delete-spn-suffix not allowed together with DOMAIN")
1786 if refresh is not None:
1787 if refresh == "store":
1788 require_update = True
1790 if enable_all and refresh != "store":
1791 raise CommandError("--enable-all not allowed together with --refresh=%s" % refresh)
1793 if len(enable_tln) > 0:
1794 raise CommandError("--enable-tln not allowed together with --refresh")
1795 if len(disable_tln) > 0:
1796 raise CommandError("--disable-tln not allowed together with --refresh")
1798 if len(add_tln_ex) > 0:
1799 raise CommandError("--add-tln-ex not allowed together with --refresh")
1800 if len(delete_tln_ex) > 0:
1801 raise CommandError("--delete-tln-ex not allowed together with --refresh")
1803 if len(enable_nb) > 0:
1804 raise CommandError("--enable-nb not allowed together with --refresh")
1805 if len(disable_nb) > 0:
1806 raise CommandError("--disable-nb not allowed together with --refresh")
1808 if len(enable_sid_str) > 0:
1809 raise CommandError("--enable-sid not allowed together with --refresh")
1810 if len(disable_sid_str) > 0:
1811 raise CommandError("--disable-sid not allowed together with --refresh")
1812 else:
1813 if enable_all:
1814 require_update = True
1816 if len(enable_tln) > 0:
1817 raise CommandError("--enable-tln not allowed together with --enable-all")
1819 if len(enable_nb) > 0:
1820 raise CommandError("--enable-nb not allowed together with --enable-all")
1822 if len(enable_sid_str) > 0:
1823 raise CommandError("--enable-sid not allowed together with --enable-all")
1825 if len(enable_tln) > 0:
1826 require_update = True
1827 if len(disable_tln) > 0:
1828 require_update = True
1829 for e in enable_tln:
1830 for d in disable_tln:
1831 if e.lower() != d.lower():
1832 continue
1833 raise CommandError("value[%s] specified for --enable-tln and --disable-tln" % e)
1835 if len(add_tln_ex) > 0:
1836 for n in add_tln_ex:
1837 if not n.startswith("*."):
1838 continue
1839 raise CommandError("value[%s] specified for --add-tln-ex should not include with '*.'" % n)
1840 require_update = True
1841 if len(delete_tln_ex) > 0:
1842 for n in delete_tln_ex:
1843 if not n.startswith("*."):
1844 continue
1845 raise CommandError("value[%s] specified for --delete-tln-ex should not include with '*.'" % n)
1846 require_update = True
1847 for a in add_tln_ex:
1848 for d in delete_tln_ex:
1849 if a.lower() != d.lower():
1850 continue
1851 raise CommandError("value[%s] specified for --add-tln-ex and --delete-tln-ex" % a)
1853 if len(enable_nb) > 0:
1854 require_update = True
1855 if len(disable_nb) > 0:
1856 require_update = True
1857 for e in enable_nb:
1858 for d in disable_nb:
1859 if e.upper() != d.upper():
1860 continue
1861 raise CommandError("value[%s] specified for --enable-nb and --disable-nb" % e)
1863 enable_sid = []
1864 for s in enable_sid_str:
1865 try:
1866 sid = security.dom_sid(s)
1867 except (ValueError, TypeError):
1868 raise CommandError("value[%s] specified for --enable-sid is not a valid SID" % s)
1869 enable_sid.append(sid)
1870 disable_sid = []
1871 for s in disable_sid_str:
1872 try:
1873 sid = security.dom_sid(s)
1874 except (ValueError, TypeError):
1875 raise CommandError("value[%s] specified for --disable-sid is not a valid SID" % s)
1876 disable_sid.append(sid)
1877 if len(enable_sid) > 0:
1878 require_update = True
1879 if len(disable_sid) > 0:
1880 require_update = True
1881 for e in enable_sid:
1882 for d in disable_sid:
1883 if e != d:
1884 continue
1885 raise CommandError("value[%s] specified for --enable-sid and --disable-sid" % e)
1887 local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
1888 if require_update:
1889 local_policy_access |= lsa.LSA_POLICY_TRUST_ADMIN
1891 local_server = self.setup_local_server(sambaopts, localdcopts)
1892 try:
1893 local_lsa = self.new_local_lsa_connection()
1894 except RuntimeError as error:
1895 raise self.LocalRuntimeError(self, error, "failed to connect lsa server")
1897 try:
1899 local_policy,
1900 local_version,
1901 local_revision_info1,
1902 local_lsa_info
1903 ) = self.get_lsa_info(local_lsa, local_policy_access)
1904 except RuntimeError as error:
1905 raise self.LocalRuntimeError(self, error, "failed to query LSA_POLICY_INFO_DNS")
1907 self.outf.write("LocalDomain Netbios[%s] DNS[%s] SID[%s]\n" % (
1908 local_lsa_info.name.string,
1909 local_lsa_info.dns_domain.string,
1910 local_lsa_info.sid))
1912 if domain is None:
1913 try:
1914 local_netlogon = self.new_local_netlogon_connection()
1915 except RuntimeError as error:
1916 raise self.LocalRuntimeError(self, error, "failed to connect netlogon server")
1918 try:
1919 local_netlogon_info = self.get_netlogon_dc_info(local_netlogon, local_server)
1920 except RuntimeError as error:
1921 raise self.LocalRuntimeError(self, error, "failed to get netlogon dc info")
1923 if local_netlogon_info.domain_name != local_netlogon_info.forest_name:
1924 raise CommandError("The local domain [%s] is not the forest root [%s]" % (
1925 local_netlogon_info.domain_name,
1926 local_netlogon_info.forest_name))
1928 try:
1929 # get all information about our own forest
1930 own_forest_info = local_netlogon.netr_DsRGetForestTrustInformation(local_netlogon_info.dc_unc,
1931 None, 0)
1932 except RuntimeError as error:
1933 if self.check_runtime_error(error, werror.WERR_RPC_S_PROCNUM_OUT_OF_RANGE):
1934 raise CommandError("LOCAL_DC[%s]: netr_DsRGetForestTrustInformation() not supported." % (
1935 local_server))
1937 if self.check_runtime_error(error, werror.WERR_INVALID_FUNCTION):
1938 raise CommandError("LOCAL_DC[%s]: netr_DsRGetForestTrustInformation() not supported." % (
1939 local_server))
1941 if self.check_runtime_error(error, werror.WERR_NERR_ACFNOTLOADED):
1942 raise CommandError("LOCAL_DC[%s]: netr_DsRGetForestTrustInformation() not supported." % (
1943 local_server))
1945 raise self.LocalRuntimeError(self, error, "netr_DsRGetForestTrustInformation() failed")
1947 self.outf.write("Own forest trust information...\n")
1948 self.write_forest_trust_info(own_forest_info,
1949 tln=local_lsa_info.dns_domain.string)
1951 try:
1952 local_samdb = self.new_local_ldap_connection()
1953 except RuntimeError as error:
1954 raise self.LocalRuntimeError(self, error, "failed to connect to SamDB")
1956 local_partitions_dn = "CN=Partitions,%s" % str(local_samdb.get_config_basedn())
1957 attrs = ['uPNSuffixes', 'msDS-SPNSuffixes']
1958 try:
1959 msgs = local_samdb.search(base=local_partitions_dn,
1960 scope=ldb.SCOPE_BASE,
1961 expression="(objectClass=crossRefContainer)",
1962 attrs=attrs)
1963 stored_msg = msgs[0]
1964 except ldb.LdbError as error:
1965 raise self.LocalLdbError(self, error, "failed to search partition dn")
1967 stored_upn_vals = []
1968 if 'uPNSuffixes' in stored_msg:
1969 stored_upn_vals.extend(stored_msg['uPNSuffixes'])
1971 stored_spn_vals = []
1972 if 'msDS-SPNSuffixes' in stored_msg:
1973 stored_spn_vals.extend(stored_msg['msDS-SPNSuffixes'])
1975 self.outf.write("Stored uPNSuffixes attributes[%d]:\n" % len(stored_upn_vals))
1976 for v in stored_upn_vals:
1977 self.outf.write("TLN: %-32s DNS[*.%s]\n" % ("", v))
1978 self.outf.write("Stored msDS-SPNSuffixes attributes[%d]:\n" % len(stored_spn_vals))
1979 for v in stored_spn_vals:
1980 self.outf.write("TLN: %-32s DNS[*.%s]\n" % ("", v))
1982 if not require_update:
1983 return
1985 replace_upn = False
1986 update_upn_vals = []
1987 update_upn_vals.extend(stored_upn_vals)
1989 replace_spn = False
1990 update_spn_vals = []
1991 update_spn_vals.extend(stored_spn_vals)
1993 for upn in add_upn:
1994 for v in update_upn_vals:
1995 if str(v).lower() == upn.lower():
1996 raise CommandError("Entry already present for "
1997 "value[%s] specified for "
1998 "--add-upn-suffix" % upn)
1999 update_upn_vals.append(upn)
2000 replace_upn = True
2002 for upn in delete_upn:
2003 idx = None
2004 for i, v in enumerate(update_upn_vals):
2005 if str(v).lower() != upn.lower():
2006 continue
2007 idx = i
2008 break
2009 if idx is None:
2010 raise CommandError("Entry not found for value[%s] specified for --delete-upn-suffix" % upn)
2012 update_upn_vals.pop(idx)
2013 replace_upn = True
2015 for spn in add_spn:
2016 for v in update_spn_vals:
2017 if str(v).lower() == spn.lower():
2018 raise CommandError("Entry already present for "
2019 "value[%s] specified for "
2020 "--add-spn-suffix" % spn)
2021 update_spn_vals.append(spn)
2022 replace_spn = True
2024 for spn in delete_spn:
2025 idx = None
2026 for i, v in enumerate(update_spn_vals):
2027 if str(v).lower() != spn.lower():
2028 continue
2029 idx = i
2030 break
2031 if idx is None:
2032 raise CommandError("Entry not found for value[%s] specified for --delete-spn-suffix" % spn)
2034 update_spn_vals.pop(idx)
2035 replace_spn = True
2037 self.outf.write("Update uPNSuffixes attributes[%d]:\n" % len(update_upn_vals))
2038 for v in update_upn_vals:
2039 self.outf.write("TLN: %-32s DNS[*.%s]\n" % ("", v))
2040 self.outf.write("Update msDS-SPNSuffixes attributes[%d]:\n" % len(update_spn_vals))
2041 for v in update_spn_vals:
2042 self.outf.write("TLN: %-32s DNS[*.%s]\n" % ("", v))
2044 update_msg = ldb.Message()
2045 update_msg.dn = stored_msg.dn
2047 if replace_upn:
2048 update_msg['uPNSuffixes'] = ldb.MessageElement(update_upn_vals,
2049 ldb.FLAG_MOD_REPLACE,
2050 'uPNSuffixes')
2051 if replace_spn:
2052 update_msg['msDS-SPNSuffixes'] = ldb.MessageElement(update_spn_vals,
2053 ldb.FLAG_MOD_REPLACE,
2054 'msDS-SPNSuffixes')
2055 try:
2056 local_samdb.modify(update_msg)
2057 except ldb.LdbError as error:
2058 raise self.LocalLdbError(self, error, "failed to update partition dn")
2060 try:
2061 stored_forest_info = local_netlogon.netr_DsRGetForestTrustInformation(local_netlogon_info.dc_unc,
2062 None, 0)
2063 except RuntimeError as error:
2064 raise self.LocalRuntimeError(self, error, "netr_DsRGetForestTrustInformation() failed")
2066 self.outf.write("Stored forest trust information...\n")
2067 self.write_forest_trust_info(stored_forest_info,
2068 tln=local_lsa_info.dns_domain.string)
2069 return
2071 try:
2072 lsaString = lsa.String()
2073 lsaString.string = domain
2074 local_tdo_info = \
2075 local_lsa.QueryTrustedDomainInfoByName(local_policy,
2076 lsaString,
2077 lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX)
2078 except NTSTATUSError as error:
2079 if self.check_runtime_error(error, ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND):
2080 raise CommandError("trusted domain object does not exist for domain [%s]" % domain)
2082 raise self.LocalRuntimeError(self, error, "QueryTrustedDomainInfoByName(INFO_EX) failed")
2084 self.outf.write("LocalTDO Netbios[%s] DNS[%s] SID[%s]\n" % (
2085 local_tdo_info.netbios_name.string,
2086 local_tdo_info.domain_name.string,
2087 local_tdo_info.sid))
2089 if not local_tdo_info.trust_attributes & lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE:
2090 raise CommandError("trusted domain object for domain [%s] is not marked as FOREST_TRANSITIVE." % domain)
2092 if refresh is not None:
2093 try:
2094 local_netlogon = self.new_local_netlogon_connection()
2095 except RuntimeError as error:
2096 raise self.LocalRuntimeError(self, error, "failed to connect netlogon server")
2098 try:
2099 local_netlogon_info = self.get_netlogon_dc_info(local_netlogon, local_server)
2100 except RuntimeError as error:
2101 raise self.LocalRuntimeError(self, error, "failed to get netlogon dc info")
2103 lsa_update_check = 1
2104 if refresh == "store":
2105 netlogon_update_tdo = netlogon.DS_GFTI_UPDATE_TDO
2106 if enable_all:
2107 lsa_update_check = 0
2108 else:
2109 netlogon_update_tdo = 0
2111 try:
2112 # get all information about the remote trust
2113 # this triggers netr_GetForestTrustInformation to the remote domain
2114 # and lsaRSetForestTrustInformation() locally, but new top level
2115 # names are disabled by default.
2116 fresh_forest_info = \
2117 local_netlogon.netr_DsRGetForestTrustInformation(local_netlogon_info.dc_unc,
2118 local_tdo_info.domain_name.string,
2119 netlogon_update_tdo)
2120 except RuntimeError as error:
2121 raise self.LocalRuntimeError(self, error, "netr_DsRGetForestTrustInformation() failed")
2123 try:
2124 fresh_forest_collision = \
2125 local_lsa.lsaRSetForestTrustInformation(local_policy,
2126 local_tdo_info.domain_name,
2127 lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
2128 fresh_forest_info,
2129 lsa_update_check)
2130 except RuntimeError as error:
2131 raise self.LocalRuntimeError(self, error, "lsaRSetForestTrustInformation() failed")
2133 self.outf.write("Fresh forest trust information...\n")
2134 self.write_forest_trust_info(fresh_forest_info,
2135 tln=local_tdo_info.domain_name.string,
2136 collisions=fresh_forest_collision)
2138 if refresh == "store":
2139 try:
2140 lsaString = lsa.String()
2141 lsaString.string = local_tdo_info.domain_name.string
2142 stored_forest_info = \
2143 local_lsa.lsaRQueryForestTrustInformation(local_policy,
2144 lsaString,
2145 lsa.LSA_FOREST_TRUST_DOMAIN_INFO)
2146 except RuntimeError as error:
2147 raise self.LocalRuntimeError(self, error, "lsaRQueryForestTrustInformation() failed")
2149 self.outf.write("Stored forest trust information...\n")
2150 self.write_forest_trust_info(stored_forest_info,
2151 tln=local_tdo_info.domain_name.string)
2153 return
2156 # The none --refresh path
2159 try:
2160 lsaString = lsa.String()
2161 lsaString.string = local_tdo_info.domain_name.string
2162 local_forest_info = \
2163 local_lsa.lsaRQueryForestTrustInformation(local_policy,
2164 lsaString,
2165 lsa.LSA_FOREST_TRUST_DOMAIN_INFO)
2166 except RuntimeError as error:
2167 raise self.LocalRuntimeError(self, error, "lsaRQueryForestTrustInformation() failed")
2169 self.outf.write("Local forest trust information...\n")
2170 self.write_forest_trust_info(local_forest_info,
2171 tln=local_tdo_info.domain_name.string)
2173 if not require_update:
2174 return
2176 entries = []
2177 entries.extend(local_forest_info.entries)
2178 update_forest_info = lsa.ForestTrustInformation()
2179 update_forest_info.count = len(entries)
2180 update_forest_info.entries = entries
2182 if enable_all:
2183 for r in update_forest_info.entries:
2184 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
2185 continue
2186 if r.flags == 0:
2187 continue
2188 r.time = 0
2189 r.flags &= ~lsa.LSA_TLN_DISABLED_MASK
2190 for r in update_forest_info.entries:
2191 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
2192 continue
2193 if r.flags == 0:
2194 continue
2195 r.time = 0
2196 r.flags &= ~lsa.LSA_NB_DISABLED_MASK
2197 r.flags &= ~lsa.LSA_SID_DISABLED_MASK
2199 for tln in enable_tln:
2200 idx = None
2201 for i, r in enumerate(update_forest_info.entries):
2202 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
2203 continue
2204 if r.forest_trust_data.string.lower() != tln.lower():
2205 continue
2206 idx = i
2207 break
2208 if idx is None:
2209 raise CommandError("Entry not found for value[%s] specified for --enable-tln" % tln)
2210 if not update_forest_info.entries[idx].flags & lsa.LSA_TLN_DISABLED_MASK:
2211 raise CommandError("Entry found for value[%s] specified for --enable-tln is already enabled" % tln)
2212 update_forest_info.entries[idx].time = 0
2213 update_forest_info.entries[idx].flags &= ~lsa.LSA_TLN_DISABLED_MASK
2215 for tln in disable_tln:
2216 idx = None
2217 for i, r in enumerate(update_forest_info.entries):
2218 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
2219 continue
2220 if r.forest_trust_data.string.lower() != tln.lower():
2221 continue
2222 idx = i
2223 break
2224 if idx is None:
2225 raise CommandError("Entry not found for value[%s] specified for --disable-tln" % tln)
2226 if update_forest_info.entries[idx].flags & lsa.LSA_TLN_DISABLED_ADMIN:
2227 raise CommandError("Entry found for value[%s] specified for --disable-tln is already disabled" % tln)
2228 update_forest_info.entries[idx].time = 0
2229 update_forest_info.entries[idx].flags &= ~lsa.LSA_TLN_DISABLED_MASK
2230 update_forest_info.entries[idx].flags |= lsa.LSA_TLN_DISABLED_ADMIN
2232 for tln_ex in add_tln_ex:
2233 idx = None
2234 for i, r in enumerate(update_forest_info.entries):
2235 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
2236 continue
2237 if r.forest_trust_data.string.lower() != tln_ex.lower():
2238 continue
2239 idx = i
2240 break
2241 if idx is not None:
2242 raise CommandError("Entry already present for value[%s] specified for --add-tln-ex" % tln_ex)
2244 tln_dot = ".%s" % tln_ex.lower()
2245 idx = None
2246 for i, r in enumerate(update_forest_info.entries):
2247 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
2248 continue
2249 r_dot = ".%s" % r.forest_trust_data.string.lower()
2250 if tln_dot == r_dot:
2251 raise CommandError("TLN entry present for value[%s] specified for --add-tln-ex" % tln_ex)
2252 if not tln_dot.endswith(r_dot):
2253 continue
2254 idx = i
2255 break
2257 if idx is None:
2258 raise CommandError("No TLN parent present for value[%s] specified for --add-tln-ex" % tln_ex)
2260 r = lsa.ForestTrustRecord()
2261 r.type = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX
2262 r.flags = 0
2263 r.time = 0
2264 r.forest_trust_data.string = tln_ex
2266 entries = []
2267 entries.extend(update_forest_info.entries)
2268 entries.insert(idx + 1, r)
2269 update_forest_info.count = len(entries)
2270 update_forest_info.entries = entries
2272 for tln_ex in delete_tln_ex:
2273 idx = None
2274 for i, r in enumerate(update_forest_info.entries):
2275 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
2276 continue
2277 if r.forest_trust_data.string.lower() != tln_ex.lower():
2278 continue
2279 idx = i
2280 break
2281 if idx is None:
2282 raise CommandError("Entry not found for value[%s] specified for --delete-tln-ex" % tln_ex)
2284 entries = []
2285 entries.extend(update_forest_info.entries)
2286 entries.pop(idx)
2287 update_forest_info.count = len(entries)
2288 update_forest_info.entries = entries
2290 for nb in enable_nb:
2291 idx = None
2292 for i, r in enumerate(update_forest_info.entries):
2293 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
2294 continue
2295 if r.forest_trust_data.netbios_domain_name.string.upper() != nb.upper():
2296 continue
2297 idx = i
2298 break
2299 if idx is None:
2300 raise CommandError("Entry not found for value[%s] specified for --enable-nb" % nb)
2301 if not update_forest_info.entries[idx].flags & lsa.LSA_NB_DISABLED_MASK:
2302 raise CommandError("Entry found for value[%s] specified for --enable-nb is already enabled" % nb)
2303 update_forest_info.entries[idx].time = 0
2304 update_forest_info.entries[idx].flags &= ~lsa.LSA_NB_DISABLED_MASK
2306 for nb in disable_nb:
2307 idx = None
2308 for i, r in enumerate(update_forest_info.entries):
2309 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
2310 continue
2311 if r.forest_trust_data.netbios_domain_name.string.upper() != nb.upper():
2312 continue
2313 idx = i
2314 break
2315 if idx is None:
2316 raise CommandError("Entry not found for value[%s] specified for --delete-nb" % nb)
2317 if update_forest_info.entries[idx].flags & lsa.LSA_NB_DISABLED_ADMIN:
2318 raise CommandError("Entry found for value[%s] specified for --disable-nb is already disabled" % nb)
2319 update_forest_info.entries[idx].time = 0
2320 update_forest_info.entries[idx].flags &= ~lsa.LSA_NB_DISABLED_MASK
2321 update_forest_info.entries[idx].flags |= lsa.LSA_NB_DISABLED_ADMIN
2323 for sid in enable_sid:
2324 idx = None
2325 for i, r in enumerate(update_forest_info.entries):
2326 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
2327 continue
2328 if r.forest_trust_data.domain_sid != sid:
2329 continue
2330 idx = i
2331 break
2332 if idx is None:
2333 raise CommandError("Entry not found for value[%s] specified for --enable-sid" % sid)
2334 if not update_forest_info.entries[idx].flags & lsa.LSA_SID_DISABLED_MASK:
2335 raise CommandError("Entry found for value[%s] specified for --enable-sid is already enabled" % nb)
2336 update_forest_info.entries[idx].time = 0
2337 update_forest_info.entries[idx].flags &= ~lsa.LSA_SID_DISABLED_MASK
2339 for sid in disable_sid:
2340 idx = None
2341 for i, r in enumerate(update_forest_info.entries):
2342 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
2343 continue
2344 if r.forest_trust_data.domain_sid != sid:
2345 continue
2346 idx = i
2347 break
2348 if idx is None:
2349 raise CommandError("Entry not found for value[%s] specified for --delete-sid" % sid)
2350 if update_forest_info.entries[idx].flags & lsa.LSA_SID_DISABLED_ADMIN:
2351 raise CommandError("Entry found for value[%s] specified for --disable-sid is already disabled" % nb)
2352 update_forest_info.entries[idx].time = 0
2353 update_forest_info.entries[idx].flags &= ~lsa.LSA_SID_DISABLED_MASK
2354 update_forest_info.entries[idx].flags |= lsa.LSA_SID_DISABLED_ADMIN
2356 try:
2357 update_forest_collision = local_lsa.lsaRSetForestTrustInformation(local_policy,
2358 local_tdo_info.domain_name,
2359 lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
2360 update_forest_info, 0)
2361 except RuntimeError as error:
2362 raise self.LocalRuntimeError(self, error, "lsaRSetForestTrustInformation() failed")
2364 self.outf.write("Updated forest trust information...\n")
2365 self.write_forest_trust_info(update_forest_info,
2366 tln=local_tdo_info.domain_name.string,
2367 collisions=update_forest_collision)
2369 try:
2370 lsaString = lsa.String()
2371 lsaString.string = local_tdo_info.domain_name.string
2372 stored_forest_info = local_lsa.lsaRQueryForestTrustInformation(local_policy,
2373 lsaString,
2374 lsa.LSA_FOREST_TRUST_DOMAIN_INFO)
2375 except RuntimeError as error:
2376 raise self.LocalRuntimeError(self, error, "lsaRQueryForestTrustInformation() failed")
2378 self.outf.write("Stored forest trust information...\n")
2379 self.write_forest_trust_info(stored_forest_info,
2380 tln=local_tdo_info.domain_name.string)
2381 return
2384 class cmd_domain_trust(SuperCommand):
2385 """Domain and forest trust management."""
2387 subcommands = {}
2388 subcommands["list"] = cmd_domain_trust_list()
2389 subcommands["show"] = cmd_domain_trust_show()
2390 subcommands["create"] = cmd_domain_trust_create()
2391 subcommands["modify"] = cmd_domain_trust_modify()
2392 subcommands["delete"] = cmd_domain_trust_delete()
2393 subcommands["validate"] = cmd_domain_trust_validate()
2394 subcommands["namespaces"] = cmd_domain_trust_namespaces()