s4-ldb: allow for unescaped '=' in a index DN
[Samba/cd1.git] / source3 / libnet / libnet_samsync.c
blobdf7e875ab64d6161609fc244cde6679fb5d8fee0
1 /*
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/>.
24 #include "includes.h"
25 #include "libnet/libnet.h"
26 #include "../lib/crypto/crypto.h"
27 #include "../libcli/samsync/samsync.h"
28 #include "../libcli/auth/libcli_auth.h"
30 /**
31 * Fix up the delta, dealing with encryption issues so that the final
32 * callback need only do the printing or application logic
35 static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
36 struct netlogon_creds_CredentialState *creds,
37 enum netr_SamDatabaseID database_id,
38 struct netr_DELTA_ENUM_ARRAY *r)
40 NTSTATUS status;
41 int i;
43 for (i = 0; i < r->num_deltas; i++) {
45 status = samsync_fix_delta(mem_ctx,
46 creds,
47 database_id,
48 &r->delta_enum[i]);
49 if (!NT_STATUS_IS_OK(status)) {
50 return status;
54 return NT_STATUS_OK;
57 /**
58 * libnet_samsync_init_context
61 NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
62 const struct dom_sid *domain_sid,
63 struct samsync_context **ctx_p)
65 struct samsync_context *ctx;
67 *ctx_p = NULL;
69 ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
70 NT_STATUS_HAVE_NO_MEMORY(ctx);
72 if (domain_sid) {
73 ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
74 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
76 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
77 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
80 *ctx_p = ctx;
82 return NT_STATUS_OK;
85 /**
86 * samsync_database_str
89 static const char *samsync_database_str(enum netr_SamDatabaseID database_id)
92 switch (database_id) {
93 case SAM_DATABASE_DOMAIN:
94 return "DOMAIN";
95 case SAM_DATABASE_BUILTIN:
96 return "BUILTIN";
97 case SAM_DATABASE_PRIVS:
98 return "PRIVS";
99 default:
100 return "unknown";
105 * samsync_debug_str
108 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
109 enum net_samsync_mode mode,
110 enum netr_SamDatabaseID database_id)
112 const char *action = NULL;
114 switch (mode) {
115 case NET_SAMSYNC_MODE_DUMP:
116 action = "Dumping (to stdout)";
117 break;
118 case NET_SAMSYNC_MODE_FETCH_PASSDB:
119 action = "Fetching (to passdb)";
120 break;
121 case NET_SAMSYNC_MODE_FETCH_LDIF:
122 action = "Fetching (to ldif)";
123 break;
124 case NET_SAMSYNC_MODE_FETCH_KEYTAB:
125 action = "Fetching (to keytab)";
126 break;
127 default:
128 action = "Unknown";
129 break;
132 return talloc_asprintf(mem_ctx, "%s %s database",
133 action, samsync_database_str(database_id));
137 * libnet_samsync
140 static void libnet_init_netr_ChangeLogEntry(struct samsync_object *o,
141 struct netr_ChangeLogEntry *e)
143 ZERO_STRUCTP(e);
145 e->db_index = o->database_id;
146 e->delta_type = o->object_type;
148 switch (e->delta_type) {
149 case NETR_DELTA_DOMAIN:
150 case NETR_DELTA_DELETE_GROUP:
151 case NETR_DELTA_RENAME_GROUP:
152 case NETR_DELTA_DELETE_USER:
153 case NETR_DELTA_RENAME_USER:
154 case NETR_DELTA_DELETE_ALIAS:
155 case NETR_DELTA_RENAME_ALIAS:
156 case NETR_DELTA_DELETE_TRUST:
157 case NETR_DELTA_DELETE_ACCOUNT:
158 case NETR_DELTA_DELETE_SECRET:
159 case NETR_DELTA_DELETE_GROUP2:
160 case NETR_DELTA_DELETE_USER2:
161 case NETR_DELTA_MODIFY_COUNT:
162 break;
163 case NETR_DELTA_USER:
164 case NETR_DELTA_GROUP:
165 case NETR_DELTA_GROUP_MEMBER:
166 case NETR_DELTA_ALIAS:
167 case NETR_DELTA_ALIAS_MEMBER:
168 e->object_rid = o->object_identifier.rid;
169 break;
170 case NETR_DELTA_SECRET:
171 e->object.object_name = o->object_identifier.name;
172 e->flags = NETR_CHANGELOG_NAME_INCLUDED;
173 break;
174 case NETR_DELTA_TRUSTED_DOMAIN:
175 case NETR_DELTA_ACCOUNT:
176 case NETR_DELTA_POLICY:
177 e->object.object_sid = o->object_identifier.sid;
178 e->flags = NETR_CHANGELOG_SID_INCLUDED;
179 break;
180 default:
181 break;
186 * libnet_samsync_delta
189 static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
190 enum netr_SamDatabaseID database_id,
191 uint64_t *sequence_num,
192 struct samsync_context *ctx,
193 struct netr_ChangeLogEntry *e)
195 NTSTATUS result;
196 NTSTATUS callback_status;
197 const char *logon_server = ctx->cli->desthost;
198 const char *computername = global_myname();
199 struct netr_Authenticator credential;
200 struct netr_Authenticator return_authenticator;
201 uint16_t restart_state = 0;
202 uint32_t sync_context = 0;
204 ZERO_STRUCT(return_authenticator);
206 do {
207 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
209 netlogon_creds_client_authenticator(ctx->cli->dc, &credential);
211 if (ctx->single_object_replication &&
212 !ctx->force_full_replication) {
213 result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
214 logon_server,
215 computername,
216 &credential,
217 &return_authenticator,
220 &delta_enum_array);
221 } else if (!ctx->force_full_replication &&
222 sequence_num && (*sequence_num > 0)) {
223 result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
224 logon_server,
225 computername,
226 &credential,
227 &return_authenticator,
228 database_id,
229 sequence_num,
230 &delta_enum_array,
231 0xffff);
232 } else {
233 result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
234 logon_server,
235 computername,
236 &credential,
237 &return_authenticator,
238 database_id,
239 restart_state,
240 &sync_context,
241 &delta_enum_array,
242 0xffff);
245 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
246 return result;
249 /* Check returned credentials. */
250 if (!netlogon_creds_client_check(ctx->cli->dc,
251 &return_authenticator.cred)) {
252 DEBUG(0,("credentials chain check failed\n"));
253 return NT_STATUS_ACCESS_DENIED;
256 if (NT_STATUS_IS_ERR(result)) {
257 break;
260 samsync_fix_delta_array(mem_ctx,
261 ctx->cli->dc,
262 database_id,
263 delta_enum_array);
265 /* Process results */
266 callback_status = ctx->ops->process_objects(mem_ctx, database_id,
267 delta_enum_array,
268 sequence_num,
269 ctx);
270 if (!NT_STATUS_IS_OK(callback_status)) {
271 result = callback_status;
272 goto out;
275 TALLOC_FREE(delta_enum_array);
277 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
279 out:
281 return result;
285 * libnet_samsync
288 NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
289 struct samsync_context *ctx)
291 NTSTATUS status = NT_STATUS_OK;
292 NTSTATUS callback_status;
293 TALLOC_CTX *mem_ctx;
294 const char *debug_str;
295 uint64_t sequence_num = 0;
296 int i = 0;
298 if (!(mem_ctx = talloc_new(ctx))) {
299 return NT_STATUS_NO_MEMORY;
302 if (!ctx->ops) {
303 return NT_STATUS_INVALID_PARAMETER;
306 if (ctx->ops->startup) {
307 status = ctx->ops->startup(mem_ctx, ctx,
308 database_id, &sequence_num);
309 if (!NT_STATUS_IS_OK(status)) {
310 goto done;
314 debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
315 if (debug_str) {
316 d_fprintf(stderr, "%s\n", debug_str);
319 if (!ctx->single_object_replication) {
320 status = libnet_samsync_delta(mem_ctx, database_id,
321 &sequence_num, ctx, NULL);
322 goto done;
325 for (i=0; i<ctx->num_objects; i++) {
327 struct netr_ChangeLogEntry e;
329 if (ctx->objects[i].database_id != database_id) {
330 continue;
333 libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
335 status = libnet_samsync_delta(mem_ctx, database_id,
336 &sequence_num, ctx, &e);
337 if (!NT_STATUS_IS_OK(status)) {
338 goto done;
342 done:
344 if (NT_STATUS_IS_OK(status) && ctx->ops->finish) {
345 callback_status = ctx->ops->finish(mem_ctx, ctx,
346 database_id, sequence_num);
347 if (!NT_STATUS_IS_OK(callback_status)) {
348 status = callback_status;
352 if (NT_STATUS_IS_ERR(status) && !ctx->error_message) {
354 ctx->error_message = talloc_asprintf(ctx,
355 "Failed to fetch %s database: %s",
356 samsync_database_str(database_id),
357 nt_errstr(status));
359 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
361 ctx->error_message =
362 talloc_asprintf_append(ctx->error_message,
363 "\nPerhaps %s is a Windows native mode domain?",
364 ctx->domain_name);
368 talloc_destroy(mem_ctx);
370 return status;
374 * pull_netr_AcctLockStr
377 NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
378 struct lsa_BinaryString *r,
379 struct netr_AcctLockStr **str_p)
381 struct netr_AcctLockStr *str;
382 enum ndr_err_code ndr_err;
383 DATA_BLOB blob;
385 if (!mem_ctx || !r || !str_p) {
386 return NT_STATUS_INVALID_PARAMETER;
389 *str_p = NULL;
391 str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
392 if (!str) {
393 return NT_STATUS_NO_MEMORY;
396 blob = data_blob_const(r->array, r->length);
398 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, str,
399 (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
401 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
402 return ndr_map_error2ntstatus(ndr_err);
405 *str_p = str;
407 return NT_STATUS_OK;