2 Unix SMB/CIFS implementation.
4 Extract the user/system database from a remote SamSync server
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7 Copyright (C) Guenther Deschner <gd@samba.org> 2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "libnet/libnet_samsync.h"
26 #include "../libcli/samsync/samsync.h"
27 #include "../libcli/auth/libcli_auth.h"
28 #include "rpc_client/rpc_client.h"
29 #include "../librpc/gen_ndr/ndr_netlogon.h"
30 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
31 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
36 * Fix up the delta, dealing with encryption issues so that the final
37 * callback need only do the printing or application logic
40 static NTSTATUS
samsync_fix_delta_array(TALLOC_CTX
*mem_ctx
,
41 struct netlogon_creds_CredentialState
*creds
,
42 enum netr_SamDatabaseID database_id
,
43 struct netr_DELTA_ENUM_ARRAY
*r
)
48 for (i
= 0; i
< r
->num_deltas
; i
++) {
50 status
= samsync_fix_delta(mem_ctx
,
54 if (!NT_STATUS_IS_OK(status
)) {
63 * libnet_samsync_init_context
66 NTSTATUS
libnet_samsync_init_context(TALLOC_CTX
*mem_ctx
,
67 const struct dom_sid
*domain_sid
,
68 struct samsync_context
**ctx_p
)
70 struct samsync_context
*ctx
;
74 ctx
= talloc_zero(mem_ctx
, struct samsync_context
);
75 NT_STATUS_HAVE_NO_MEMORY(ctx
);
78 ctx
->domain_sid
= dom_sid_dup(mem_ctx
, domain_sid
);
79 NT_STATUS_HAVE_NO_MEMORY(ctx
->domain_sid
);
81 ctx
->domain_sid_str
= sid_string_talloc(mem_ctx
, ctx
->domain_sid
);
82 NT_STATUS_HAVE_NO_MEMORY(ctx
->domain_sid_str
);
85 ctx
->msg_ctx
= messaging_init(ctx
, samba_tevent_context_init(ctx
));
86 NT_STATUS_HAVE_NO_MEMORY(ctx
->msg_ctx
);
94 * samsync_database_str
97 static const char *samsync_database_str(enum netr_SamDatabaseID database_id
)
100 switch (database_id
) {
101 case SAM_DATABASE_DOMAIN
:
103 case SAM_DATABASE_BUILTIN
:
105 case SAM_DATABASE_PRIVS
:
116 static const char *samsync_debug_str(TALLOC_CTX
*mem_ctx
,
117 enum net_samsync_mode mode
,
118 enum netr_SamDatabaseID database_id
)
120 const char *action
= NULL
;
123 case NET_SAMSYNC_MODE_DUMP
:
124 action
= "Dumping (to stdout)";
126 case NET_SAMSYNC_MODE_FETCH_PASSDB
:
127 action
= "Fetching (to passdb)";
129 case NET_SAMSYNC_MODE_FETCH_LDIF
:
130 action
= "Fetching (to ldif)";
132 case NET_SAMSYNC_MODE_FETCH_KEYTAB
:
133 action
= "Fetching (to keytab)";
140 return talloc_asprintf(mem_ctx
, "%s %s database",
141 action
, samsync_database_str(database_id
));
148 static void libnet_init_netr_ChangeLogEntry(struct samsync_object
*o
,
149 struct netr_ChangeLogEntry
*e
)
153 e
->db_index
= o
->database_id
;
154 e
->delta_type
= o
->object_type
;
156 switch (e
->delta_type
) {
157 case NETR_DELTA_DOMAIN
:
158 case NETR_DELTA_DELETE_GROUP
:
159 case NETR_DELTA_RENAME_GROUP
:
160 case NETR_DELTA_DELETE_USER
:
161 case NETR_DELTA_RENAME_USER
:
162 case NETR_DELTA_DELETE_ALIAS
:
163 case NETR_DELTA_RENAME_ALIAS
:
164 case NETR_DELTA_DELETE_TRUST
:
165 case NETR_DELTA_DELETE_ACCOUNT
:
166 case NETR_DELTA_DELETE_SECRET
:
167 case NETR_DELTA_DELETE_GROUP2
:
168 case NETR_DELTA_DELETE_USER2
:
169 case NETR_DELTA_MODIFY_COUNT
:
171 case NETR_DELTA_USER
:
172 case NETR_DELTA_GROUP
:
173 case NETR_DELTA_GROUP_MEMBER
:
174 case NETR_DELTA_ALIAS
:
175 case NETR_DELTA_ALIAS_MEMBER
:
176 e
->object_rid
= o
->object_identifier
.rid
;
178 case NETR_DELTA_SECRET
:
179 e
->object
.object_name
= o
->object_identifier
.name
;
180 e
->flags
= NETR_CHANGELOG_NAME_INCLUDED
;
182 case NETR_DELTA_TRUSTED_DOMAIN
:
183 case NETR_DELTA_ACCOUNT
:
184 case NETR_DELTA_POLICY
:
185 e
->object
.object_sid
= o
->object_identifier
.sid
;
186 e
->flags
= NETR_CHANGELOG_SID_INCLUDED
;
194 * libnet_samsync_delta
197 static NTSTATUS
libnet_samsync_delta(TALLOC_CTX
*mem_ctx
,
198 enum netr_SamDatabaseID database_id
,
199 uint64_t *sequence_num
,
200 struct samsync_context
*ctx
,
201 struct netr_ChangeLogEntry
*e
)
203 NTSTATUS result
, status
;
204 NTSTATUS callback_status
;
205 const char *logon_server
= ctx
->cli
->desthost
;
206 const char *computername
= lp_netbios_name();
207 struct netr_Authenticator credential
;
208 struct netr_Authenticator return_authenticator
;
209 uint16_t restart_state
= 0;
210 uint32_t sync_context
= 0;
211 struct dcerpc_binding_handle
*b
= ctx
->cli
->binding_handle
;
213 ZERO_STRUCT(return_authenticator
);
216 struct netr_DELTA_ENUM_ARRAY
*delta_enum_array
= NULL
;
217 struct netlogon_creds_CredentialState
*creds
= NULL
;
219 status
= netlogon_creds_cli_lock(ctx
->netlogon_creds
,
221 if (!NT_STATUS_IS_OK(status
)) {
225 netlogon_creds_client_authenticator(creds
, &credential
);
227 if (ctx
->single_object_replication
&&
228 !ctx
->force_full_replication
) {
229 status
= dcerpc_netr_DatabaseRedo(b
, mem_ctx
,
233 &return_authenticator
,
238 } else if (!ctx
->force_full_replication
&&
239 sequence_num
&& (*sequence_num
> 0)) {
240 status
= dcerpc_netr_DatabaseDeltas(b
, mem_ctx
,
244 &return_authenticator
,
251 status
= dcerpc_netr_DatabaseSync2(b
, mem_ctx
,
255 &return_authenticator
,
264 if (!NT_STATUS_IS_OK(status
)) {
269 /* Check returned credentials. */
270 if (!netlogon_creds_client_check(creds
,
271 &return_authenticator
.cred
)) {
273 DEBUG(0,("credentials chain check failed\n"));
274 return NT_STATUS_ACCESS_DENIED
;
277 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
)) {
282 if (NT_STATUS_IS_ERR(result
)) {
287 samsync_fix_delta_array(mem_ctx
,
293 /* Process results */
294 callback_status
= ctx
->ops
->process_objects(mem_ctx
, database_id
,
298 if (!NT_STATUS_IS_OK(callback_status
)) {
299 result
= callback_status
;
303 TALLOC_FREE(delta_enum_array
);
305 } while (NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
316 NTSTATUS
libnet_samsync(enum netr_SamDatabaseID database_id
,
317 struct samsync_context
*ctx
)
319 NTSTATUS status
= NT_STATUS_OK
;
320 NTSTATUS callback_status
;
322 const char *debug_str
;
323 uint64_t sequence_num
= 0;
326 if (!(mem_ctx
= talloc_new(ctx
))) {
327 return NT_STATUS_NO_MEMORY
;
331 return NT_STATUS_INVALID_PARAMETER
;
334 if (ctx
->ops
->startup
) {
335 status
= ctx
->ops
->startup(mem_ctx
, ctx
,
336 database_id
, &sequence_num
);
337 if (!NT_STATUS_IS_OK(status
)) {
342 debug_str
= samsync_debug_str(mem_ctx
, ctx
->mode
, database_id
);
344 d_fprintf(stderr
, "%s\n", debug_str
);
347 if (!ctx
->single_object_replication
) {
348 status
= libnet_samsync_delta(mem_ctx
, database_id
,
349 &sequence_num
, ctx
, NULL
);
353 for (i
=0; i
<ctx
->num_objects
; i
++) {
355 struct netr_ChangeLogEntry e
;
357 if (ctx
->objects
[i
].database_id
!= database_id
) {
361 libnet_init_netr_ChangeLogEntry(&ctx
->objects
[i
], &e
);
363 status
= libnet_samsync_delta(mem_ctx
, database_id
,
364 &sequence_num
, ctx
, &e
);
365 if (!NT_STATUS_IS_OK(status
)) {
372 if (NT_STATUS_IS_OK(status
) && ctx
->ops
->finish
) {
373 callback_status
= ctx
->ops
->finish(mem_ctx
, ctx
,
374 database_id
, sequence_num
);
375 if (!NT_STATUS_IS_OK(callback_status
)) {
376 status
= callback_status
;
380 if (NT_STATUS_IS_ERR(status
) && !ctx
->error_message
) {
382 ctx
->error_message
= talloc_asprintf(ctx
,
383 "Failed to fetch %s database: %s",
384 samsync_database_str(database_id
),
387 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
390 talloc_asprintf_append(ctx
->error_message
,
391 "\nPerhaps %s is a Windows native mode domain?",
396 talloc_destroy(mem_ctx
);
402 * pull_netr_AcctLockStr
405 NTSTATUS
pull_netr_AcctLockStr(TALLOC_CTX
*mem_ctx
,
406 struct lsa_BinaryString
*r
,
407 struct netr_AcctLockStr
**str_p
)
409 struct netr_AcctLockStr
*str
;
410 enum ndr_err_code ndr_err
;
413 if (!mem_ctx
|| !r
|| !str_p
) {
414 return NT_STATUS_INVALID_PARAMETER
;
419 str
= talloc_zero(mem_ctx
, struct netr_AcctLockStr
);
421 return NT_STATUS_NO_MEMORY
;
424 blob
= data_blob_const(r
->array
, r
->length
);
426 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, str
,
427 (ndr_pull_flags_fn_t
)ndr_pull_netr_AcctLockStr
);
429 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
430 return ndr_map_error2ntstatus(ndr_err
);