5 # Copyright Andrew Tridgell 2010
6 # Copyright Andrew Bartlett 2010
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 from samba
.dcerpc
import drsuapi
, misc
23 from samba
.net
import Net
28 '''make a DsBind call, returning the binding handle'''
29 bind_info
= drsuapi
.DsBindInfoCtr()
31 bind_info
.info
= drsuapi
.DsBindInfo28()
32 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_BASE
33 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION
34 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI
35 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2
36 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS
37 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1
38 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
39 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE
40 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2
41 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION
42 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2
43 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
44 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND
45 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO
46 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION
47 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01
48 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP
49 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY
50 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
51 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2
52 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6
53 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS
54 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
55 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5
56 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6
57 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
58 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7
59 bind_info
.info
.supported_extensions |
= drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT
60 (info
, handle
) = drs
.DsBind(misc
.GUID(drsuapi
.DRSUAPI_DS_BIND_GUID
), bind_info
)
62 return (handle
, info
.info
.supported_extensions
)
66 '''DRS replication calls'''
68 def __init__(self
, binding_string
, lp
, creds
, samdb
):
69 self
.drs
= drsuapi
.drsuapi(binding_string
, lp
, creds
)
70 (self
.drs_handle
, self
.supported_extensions
) = drs_DsBind(self
.drs
)
71 self
.net
= Net(creds
=creds
, lp
=lp
)
73 self
.replication_state
= self
.net
.replicate_init(self
.samdb
, lp
, self
.drs
)
75 def drs_get_rodc_partial_attribute_set(self
):
76 '''get a list of attributes for RODC replication'''
77 partial_attribute_set
= drsuapi
.DsPartialAttributeSet()
78 partial_attribute_set
.version
= 1
82 # the exact list of attids we send is quite critical. Note that
83 # we do ask for the secret attributes, but set SPECIAL_SECRET_PROCESSING
85 schema_dn
= self
.samdb
.get_schema_basedn()
86 res
= self
.samdb
.search(base
=schema_dn
, scope
=ldb
.SCOPE_SUBTREE
,
87 expression
="objectClass=attributeSchema",
88 attrs
=["lDAPDisplayName", "systemFlags",
92 ldap_display_name
= r
["lDAPDisplayName"][0]
93 if "systemFlags" in r
:
94 system_flags
= r
["systemFlags"][0]
95 if (int(system_flags
) & (samba
.dsdb
.DS_FLAG_ATTR_NOT_REPLICATED |
96 samba
.dsdb
.DS_FLAG_ATTR_IS_CONSTRUCTED
)):
98 if "searchFlags" in r
:
99 search_flags
= r
["searchFlags"][0]
100 if (int(search_flags
) & samba
.dsdb
.SEARCH_FLAG_RODC_ATTRIBUTE
):
102 attid
= self
.samdb
.get_attid_from_lDAPDisplayName(ldap_display_name
)
103 attids
.append(int(attid
))
105 # the attids do need to be sorted, or windows doesn't return
106 # all the attributes we need
108 partial_attribute_set
.attids
= attids
109 partial_attribute_set
.num_attids
= len(attids
)
110 return partial_attribute_set
112 def replicate(self
, dn
, source_dsa_invocation_id
, destination_dsa_guid
,
113 schema
=False, exop
=drsuapi
.DRSUAPI_EXOP_NONE
, rodc
=False,
115 '''replicate a single DN'''
117 # setup for a GetNCChanges call
118 req8
= drsuapi
.DsGetNCChangesRequest8()
120 req8
.destination_dsa_guid
= destination_dsa_guid
121 req8
.source_dsa_invocation_id
= source_dsa_invocation_id
122 req8
.naming_context
= drsuapi
.DsReplicaObjectIdentifier()
123 req8
.naming_context
.dn
= dn
124 req8
.highwatermark
= drsuapi
.DsReplicaHighWaterMark()
125 req8
.highwatermark
.tmp_highest_usn
= 0
126 req8
.highwatermark
.reserved_usn
= 0
127 req8
.highwatermark
.highest_usn
= 0
128 req8
.uptodateness_vector
= None
129 if replica_flags
is not None:
130 req8
.replica_flags
= replica_flags
131 elif exop
== drsuapi
.DRSUAPI_EXOP_REPL_SECRET
:
132 req8
.replica_flags
= 0
134 req8
.replica_flags
= (drsuapi
.DRSUAPI_DRS_INIT_SYNC |
135 drsuapi
.DRSUAPI_DRS_PER_SYNC |
136 drsuapi
.DRSUAPI_DRS_GET_ANC |
137 drsuapi
.DRSUAPI_DRS_NEVER_SYNCED
)
139 req8
.replica_flags |
= drsuapi
.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
141 req8
.replica_flags |
= drsuapi
.DRSUAPI_DRS_WRIT_REP
142 req8
.max_object_count
= 402
143 req8
.max_ndr_size
= 402116
144 req8
.extended_op
= exop
146 req8
.partial_attribute_set
= None
147 req8
.partial_attribute_set_ex
= None
148 req8
.mapping_ctr
.num_mappings
= 0
149 req8
.mapping_ctr
.mappings
= None
151 if not schema
and rodc
:
152 req8
.partial_attribute_set
= self
.drs_get_rodc_partial_attribute_set()
154 if self
.supported_extensions
& drsuapi
.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
:
159 req5
= drsuapi
.DsGetNCChangesRequest5()
162 setattr(req5
, a
, getattr(req8
, a
))
167 (level
, ctr
) = self
.drs
.DsGetNCChanges(self
.drs_handle
, req_level
, req
)
168 if ctr
.first_object
== None and ctr
.object_count
!= 0:
169 raise RuntimeError("DsGetNCChanges: NULL first_object with object_count=%u" % (ctr
.object_count
))
170 self
.net
.replicate_chunk(self
.replication_state
, level
, ctr
,
171 schema
=schema
, req_level
=req_level
, req
=req
)
172 if ctr
.more_data
== 0:
174 req
.highwatermark
.tmp_highest_usn
= ctr
.new_highwatermark
.tmp_highest_usn