s3: async cli_list
[Samba/gbeck.git] / source3 / libnet / libnet_samsync.c
blob6668be28b5bd62551ca2a0fd9305d8ea6cc2c0e1
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_samsync.h"
26 #include "../lib/crypto/crypto.h"
27 #include "../libcli/samsync/samsync.h"
28 #include "../libcli/auth/libcli_auth.h"
29 #include "../librpc/gen_ndr/ndr_netlogon.h"
30 #include "../librpc/gen_ndr/cli_netlogon.h"
32 /**
33 * Fix up the delta, dealing with encryption issues so that the final
34 * callback need only do the printing or application logic
37 static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
38 struct netlogon_creds_CredentialState *creds,
39 enum netr_SamDatabaseID database_id,
40 struct netr_DELTA_ENUM_ARRAY *r)
42 NTSTATUS status;
43 int i;
45 for (i = 0; i < r->num_deltas; i++) {
47 status = samsync_fix_delta(mem_ctx,
48 creds,
49 database_id,
50 &r->delta_enum[i]);
51 if (!NT_STATUS_IS_OK(status)) {
52 return status;
56 return NT_STATUS_OK;
59 /**
60 * libnet_samsync_init_context
63 NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
64 const struct dom_sid *domain_sid,
65 struct samsync_context **ctx_p)
67 struct samsync_context *ctx;
69 *ctx_p = NULL;
71 ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
72 NT_STATUS_HAVE_NO_MEMORY(ctx);
74 if (domain_sid) {
75 ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
76 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
78 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
79 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
82 *ctx_p = ctx;
84 return NT_STATUS_OK;
87 /**
88 * samsync_database_str
91 static const char *samsync_database_str(enum netr_SamDatabaseID database_id)
94 switch (database_id) {
95 case SAM_DATABASE_DOMAIN:
96 return "DOMAIN";
97 case SAM_DATABASE_BUILTIN:
98 return "BUILTIN";
99 case SAM_DATABASE_PRIVS:
100 return "PRIVS";
101 default:
102 return "unknown";
107 * samsync_debug_str
110 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
111 enum net_samsync_mode mode,
112 enum netr_SamDatabaseID database_id)
114 const char *action = NULL;
116 switch (mode) {
117 case NET_SAMSYNC_MODE_DUMP:
118 action = "Dumping (to stdout)";
119 break;
120 case NET_SAMSYNC_MODE_FETCH_PASSDB:
121 action = "Fetching (to passdb)";
122 break;
123 case NET_SAMSYNC_MODE_FETCH_LDIF:
124 action = "Fetching (to ldif)";
125 break;
126 case NET_SAMSYNC_MODE_FETCH_KEYTAB:
127 action = "Fetching (to keytab)";
128 break;
129 default:
130 action = "Unknown";
131 break;
134 return talloc_asprintf(mem_ctx, "%s %s database",
135 action, samsync_database_str(database_id));
139 * libnet_samsync
142 static void libnet_init_netr_ChangeLogEntry(struct samsync_object *o,
143 struct netr_ChangeLogEntry *e)
145 ZERO_STRUCTP(e);
147 e->db_index = o->database_id;
148 e->delta_type = o->object_type;
150 switch (e->delta_type) {
151 case NETR_DELTA_DOMAIN:
152 case NETR_DELTA_DELETE_GROUP:
153 case NETR_DELTA_RENAME_GROUP:
154 case NETR_DELTA_DELETE_USER:
155 case NETR_DELTA_RENAME_USER:
156 case NETR_DELTA_DELETE_ALIAS:
157 case NETR_DELTA_RENAME_ALIAS:
158 case NETR_DELTA_DELETE_TRUST:
159 case NETR_DELTA_DELETE_ACCOUNT:
160 case NETR_DELTA_DELETE_SECRET:
161 case NETR_DELTA_DELETE_GROUP2:
162 case NETR_DELTA_DELETE_USER2:
163 case NETR_DELTA_MODIFY_COUNT:
164 break;
165 case NETR_DELTA_USER:
166 case NETR_DELTA_GROUP:
167 case NETR_DELTA_GROUP_MEMBER:
168 case NETR_DELTA_ALIAS:
169 case NETR_DELTA_ALIAS_MEMBER:
170 e->object_rid = o->object_identifier.rid;
171 break;
172 case NETR_DELTA_SECRET:
173 e->object.object_name = o->object_identifier.name;
174 e->flags = NETR_CHANGELOG_NAME_INCLUDED;
175 break;
176 case NETR_DELTA_TRUSTED_DOMAIN:
177 case NETR_DELTA_ACCOUNT:
178 case NETR_DELTA_POLICY:
179 e->object.object_sid = o->object_identifier.sid;
180 e->flags = NETR_CHANGELOG_SID_INCLUDED;
181 break;
182 default:
183 break;
188 * libnet_samsync_delta
191 static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
192 enum netr_SamDatabaseID database_id,
193 uint64_t *sequence_num,
194 struct samsync_context *ctx,
195 struct netr_ChangeLogEntry *e)
197 NTSTATUS result;
198 NTSTATUS callback_status;
199 const char *logon_server = ctx->cli->desthost;
200 const char *computername = global_myname();
201 struct netr_Authenticator credential;
202 struct netr_Authenticator return_authenticator;
203 uint16_t restart_state = 0;
204 uint32_t sync_context = 0;
206 ZERO_STRUCT(return_authenticator);
208 do {
209 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
211 netlogon_creds_client_authenticator(ctx->cli->dc, &credential);
213 if (ctx->single_object_replication &&
214 !ctx->force_full_replication) {
215 result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
216 logon_server,
217 computername,
218 &credential,
219 &return_authenticator,
222 &delta_enum_array);
223 } else if (!ctx->force_full_replication &&
224 sequence_num && (*sequence_num > 0)) {
225 result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
226 logon_server,
227 computername,
228 &credential,
229 &return_authenticator,
230 database_id,
231 sequence_num,
232 &delta_enum_array,
233 0xffff);
234 } else {
235 result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
236 logon_server,
237 computername,
238 &credential,
239 &return_authenticator,
240 database_id,
241 restart_state,
242 &sync_context,
243 &delta_enum_array,
244 0xffff);
247 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
248 return result;
251 /* Check returned credentials. */
252 if (!netlogon_creds_client_check(ctx->cli->dc,
253 &return_authenticator.cred)) {
254 DEBUG(0,("credentials chain check failed\n"));
255 return NT_STATUS_ACCESS_DENIED;
258 if (NT_STATUS_IS_ERR(result)) {
259 break;
262 samsync_fix_delta_array(mem_ctx,
263 ctx->cli->dc,
264 database_id,
265 delta_enum_array);
267 /* Process results */
268 callback_status = ctx->ops->process_objects(mem_ctx, database_id,
269 delta_enum_array,
270 sequence_num,
271 ctx);
272 if (!NT_STATUS_IS_OK(callback_status)) {
273 result = callback_status;
274 goto out;
277 TALLOC_FREE(delta_enum_array);
279 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
281 out:
283 return result;
287 * libnet_samsync
290 NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
291 struct samsync_context *ctx)
293 NTSTATUS status = NT_STATUS_OK;
294 NTSTATUS callback_status;
295 TALLOC_CTX *mem_ctx;
296 const char *debug_str;
297 uint64_t sequence_num = 0;
298 int i = 0;
300 if (!(mem_ctx = talloc_new(ctx))) {
301 return NT_STATUS_NO_MEMORY;
304 if (!ctx->ops) {
305 return NT_STATUS_INVALID_PARAMETER;
308 if (ctx->ops->startup) {
309 status = ctx->ops->startup(mem_ctx, ctx,
310 database_id, &sequence_num);
311 if (!NT_STATUS_IS_OK(status)) {
312 goto done;
316 debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
317 if (debug_str) {
318 d_fprintf(stderr, "%s\n", debug_str);
321 if (!ctx->single_object_replication) {
322 status = libnet_samsync_delta(mem_ctx, database_id,
323 &sequence_num, ctx, NULL);
324 goto done;
327 for (i=0; i<ctx->num_objects; i++) {
329 struct netr_ChangeLogEntry e;
331 if (ctx->objects[i].database_id != database_id) {
332 continue;
335 libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
337 status = libnet_samsync_delta(mem_ctx, database_id,
338 &sequence_num, ctx, &e);
339 if (!NT_STATUS_IS_OK(status)) {
340 goto done;
344 done:
346 if (NT_STATUS_IS_OK(status) && ctx->ops->finish) {
347 callback_status = ctx->ops->finish(mem_ctx, ctx,
348 database_id, sequence_num);
349 if (!NT_STATUS_IS_OK(callback_status)) {
350 status = callback_status;
354 if (NT_STATUS_IS_ERR(status) && !ctx->error_message) {
356 ctx->error_message = talloc_asprintf(ctx,
357 "Failed to fetch %s database: %s",
358 samsync_database_str(database_id),
359 nt_errstr(status));
361 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
363 ctx->error_message =
364 talloc_asprintf_append(ctx->error_message,
365 "\nPerhaps %s is a Windows native mode domain?",
366 ctx->domain_name);
370 talloc_destroy(mem_ctx);
372 return status;
376 * pull_netr_AcctLockStr
379 NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
380 struct lsa_BinaryString *r,
381 struct netr_AcctLockStr **str_p)
383 struct netr_AcctLockStr *str;
384 enum ndr_err_code ndr_err;
385 DATA_BLOB blob;
387 if (!mem_ctx || !r || !str_p) {
388 return NT_STATUS_INVALID_PARAMETER;
391 *str_p = NULL;
393 str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
394 if (!str) {
395 return NT_STATUS_NO_MEMORY;
398 blob = data_blob_const(r->array, r->length);
400 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, str,
401 (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
403 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
404 return ndr_map_error2ntstatus(ndr_err);
407 *str_p = str;
409 return NT_STATUS_OK;