libcli/security Provide a common, top level libcli/security/security.h
[sfrench/samba-autobuild/.git] / source3 / libnet / libnet_samsync.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Extract the user/system database from a remote SamSync server
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7    Copyright (C) Guenther Deschner <gd@samba.org> 2008
8
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.
13
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.
18
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/>.
21 */
22
23
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"
31 #include "../libcli/security/security.h"
32
33 /**
34  * Fix up the delta, dealing with encryption issues so that the final
35  * callback need only do the printing or application logic
36  */
37
38 static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
39                                         struct netlogon_creds_CredentialState *creds,
40                                         enum netr_SamDatabaseID database_id,
41                                         struct netr_DELTA_ENUM_ARRAY *r)
42 {
43         NTSTATUS status;
44         int i;
45
46         for (i = 0; i < r->num_deltas; i++) {
47
48                 status = samsync_fix_delta(mem_ctx,
49                                            creds,
50                                            database_id,
51                                            &r->delta_enum[i]);
52                 if (!NT_STATUS_IS_OK(status)) {
53                         return status;
54                 }
55         }
56
57         return NT_STATUS_OK;
58 }
59
60 /**
61  * libnet_samsync_init_context
62  */
63
64 NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
65                                      const struct dom_sid *domain_sid,
66                                      struct samsync_context **ctx_p)
67 {
68         struct samsync_context *ctx;
69
70         *ctx_p = NULL;
71
72         ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
73         NT_STATUS_HAVE_NO_MEMORY(ctx);
74
75         if (domain_sid) {
76                 ctx->domain_sid = dom_sid_dup(mem_ctx, domain_sid);
77                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
78
79                 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
80                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
81         }
82
83         ctx->msg_ctx = messaging_init(ctx, procid_self(),
84                                       event_context_init(ctx));
85         NT_STATUS_HAVE_NO_MEMORY(ctx->msg_ctx);
86
87         *ctx_p = ctx;
88
89         return NT_STATUS_OK;
90 }
91
92 /**
93  * samsync_database_str
94  */
95
96 static const char *samsync_database_str(enum netr_SamDatabaseID database_id)
97 {
98
99         switch (database_id) {
100                 case SAM_DATABASE_DOMAIN:
101                         return "DOMAIN";
102                 case SAM_DATABASE_BUILTIN:
103                         return "BUILTIN";
104                 case SAM_DATABASE_PRIVS:
105                         return "PRIVS";
106                 default:
107                         return "unknown";
108         }
109 }
110
111 /**
112  * samsync_debug_str
113  */
114
115 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
116                                      enum net_samsync_mode mode,
117                                      enum netr_SamDatabaseID database_id)
118 {
119         const char *action = NULL;
120
121         switch (mode) {
122                 case NET_SAMSYNC_MODE_DUMP:
123                         action = "Dumping (to stdout)";
124                         break;
125                 case NET_SAMSYNC_MODE_FETCH_PASSDB:
126                         action = "Fetching (to passdb)";
127                         break;
128                 case NET_SAMSYNC_MODE_FETCH_LDIF:
129                         action = "Fetching (to ldif)";
130                         break;
131                 case NET_SAMSYNC_MODE_FETCH_KEYTAB:
132                         action = "Fetching (to keytab)";
133                         break;
134                 default:
135                         action = "Unknown";
136                         break;
137         }
138
139         return talloc_asprintf(mem_ctx, "%s %s database",
140                                 action, samsync_database_str(database_id));
141 }
142
143 /**
144  * libnet_samsync
145  */
146
147 static void libnet_init_netr_ChangeLogEntry(struct samsync_object *o,
148                                             struct netr_ChangeLogEntry *e)
149 {
150         ZERO_STRUCTP(e);
151
152         e->db_index             = o->database_id;
153         e->delta_type           = o->object_type;
154
155         switch (e->delta_type) {
156                 case NETR_DELTA_DOMAIN:
157                 case NETR_DELTA_DELETE_GROUP:
158                 case NETR_DELTA_RENAME_GROUP:
159                 case NETR_DELTA_DELETE_USER:
160                 case NETR_DELTA_RENAME_USER:
161                 case NETR_DELTA_DELETE_ALIAS:
162                 case NETR_DELTA_RENAME_ALIAS:
163                 case NETR_DELTA_DELETE_TRUST:
164                 case NETR_DELTA_DELETE_ACCOUNT:
165                 case NETR_DELTA_DELETE_SECRET:
166                 case NETR_DELTA_DELETE_GROUP2:
167                 case NETR_DELTA_DELETE_USER2:
168                 case NETR_DELTA_MODIFY_COUNT:
169                         break;
170                 case NETR_DELTA_USER:
171                 case NETR_DELTA_GROUP:
172                 case NETR_DELTA_GROUP_MEMBER:
173                 case NETR_DELTA_ALIAS:
174                 case NETR_DELTA_ALIAS_MEMBER:
175                         e->object_rid = o->object_identifier.rid;
176                         break;
177                 case NETR_DELTA_SECRET:
178                         e->object.object_name = o->object_identifier.name;
179                         e->flags = NETR_CHANGELOG_NAME_INCLUDED;
180                         break;
181                 case NETR_DELTA_TRUSTED_DOMAIN:
182                 case NETR_DELTA_ACCOUNT:
183                 case NETR_DELTA_POLICY:
184                         e->object.object_sid = o->object_identifier.sid;
185                         e->flags = NETR_CHANGELOG_SID_INCLUDED;
186                         break;
187                 default:
188                         break;
189         }
190 }
191
192 /**
193  * libnet_samsync_delta
194  */
195
196 static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
197                                      enum netr_SamDatabaseID database_id,
198                                      uint64_t *sequence_num,
199                                      struct samsync_context *ctx,
200                                      struct netr_ChangeLogEntry *e)
201 {
202         NTSTATUS result;
203         NTSTATUS callback_status;
204         const char *logon_server = ctx->cli->desthost;
205         const char *computername = global_myname();
206         struct netr_Authenticator credential;
207         struct netr_Authenticator return_authenticator;
208         uint16_t restart_state = 0;
209         uint32_t sync_context = 0;
210
211         ZERO_STRUCT(return_authenticator);
212
213         do {
214                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
215
216                 netlogon_creds_client_authenticator(ctx->cli->dc, &credential);
217
218                 if (ctx->single_object_replication &&
219                     !ctx->force_full_replication) {
220                         result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
221                                                           logon_server,
222                                                           computername,
223                                                           &credential,
224                                                           &return_authenticator,
225                                                           *e,
226                                                           0,
227                                                           &delta_enum_array);
228                 } else if (!ctx->force_full_replication &&
229                            sequence_num && (*sequence_num > 0)) {
230                         result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
231                                                             logon_server,
232                                                             computername,
233                                                             &credential,
234                                                             &return_authenticator,
235                                                             database_id,
236                                                             sequence_num,
237                                                             &delta_enum_array,
238                                                             0xffff);
239                 } else {
240                         result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
241                                                            logon_server,
242                                                            computername,
243                                                            &credential,
244                                                            &return_authenticator,
245                                                            database_id,
246                                                            restart_state,
247                                                            &sync_context,
248                                                            &delta_enum_array,
249                                                            0xffff);
250                 }
251
252                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
253                         return result;
254                 }
255
256                 /* Check returned credentials. */
257                 if (!netlogon_creds_client_check(ctx->cli->dc,
258                                                  &return_authenticator.cred)) {
259                         DEBUG(0,("credentials chain check failed\n"));
260                         return NT_STATUS_ACCESS_DENIED;
261                 }
262
263                 if (NT_STATUS_IS_ERR(result)) {
264                         break;
265                 }
266
267                 samsync_fix_delta_array(mem_ctx,
268                                         ctx->cli->dc,
269                                         database_id,
270                                         delta_enum_array);
271
272                 /* Process results */
273                 callback_status = ctx->ops->process_objects(mem_ctx, database_id,
274                                                             delta_enum_array,
275                                                             sequence_num,
276                                                             ctx);
277                 if (!NT_STATUS_IS_OK(callback_status)) {
278                         result = callback_status;
279                         goto out;
280                 }
281
282                 TALLOC_FREE(delta_enum_array);
283
284         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
285
286  out:
287
288         return result;
289 }
290
291 /**
292  * libnet_samsync
293  */
294
295 NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
296                         struct samsync_context *ctx)
297 {
298         NTSTATUS status = NT_STATUS_OK;
299         NTSTATUS callback_status;
300         TALLOC_CTX *mem_ctx;
301         const char *debug_str;
302         uint64_t sequence_num = 0;
303         int i = 0;
304
305         if (!(mem_ctx = talloc_new(ctx))) {
306                 return NT_STATUS_NO_MEMORY;
307         }
308
309         if (!ctx->ops) {
310                 return NT_STATUS_INVALID_PARAMETER;
311         }
312
313         if (ctx->ops->startup) {
314                 status = ctx->ops->startup(mem_ctx, ctx,
315                                            database_id, &sequence_num);
316                 if (!NT_STATUS_IS_OK(status)) {
317                         goto done;
318                 }
319         }
320
321         debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
322         if (debug_str) {
323                 d_fprintf(stderr, "%s\n", debug_str);
324         }
325
326         if (!ctx->single_object_replication) {
327                 status = libnet_samsync_delta(mem_ctx, database_id,
328                                               &sequence_num, ctx, NULL);
329                 goto done;
330         }
331
332         for (i=0; i<ctx->num_objects; i++) {
333
334                 struct netr_ChangeLogEntry e;
335
336                 if (ctx->objects[i].database_id != database_id) {
337                         continue;
338                 }
339
340                 libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
341
342                 status = libnet_samsync_delta(mem_ctx, database_id,
343                                               &sequence_num, ctx, &e);
344                 if (!NT_STATUS_IS_OK(status)) {
345                         goto done;
346                 }
347         }
348
349  done:
350
351         if (NT_STATUS_IS_OK(status) && ctx->ops->finish) {
352                 callback_status = ctx->ops->finish(mem_ctx, ctx,
353                                                    database_id, sequence_num);
354                 if (!NT_STATUS_IS_OK(callback_status)) {
355                         status = callback_status;
356                 }
357         }
358
359         if (NT_STATUS_IS_ERR(status) && !ctx->error_message) {
360
361                 ctx->error_message = talloc_asprintf(ctx,
362                         "Failed to fetch %s database: %s",
363                         samsync_database_str(database_id),
364                         nt_errstr(status));
365
366                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
367
368                         ctx->error_message =
369                                 talloc_asprintf_append(ctx->error_message,
370                                         "\nPerhaps %s is a Windows native mode domain?",
371                                         ctx->domain_name);
372                 }
373         }
374
375         talloc_destroy(mem_ctx);
376
377         return status;
378 }
379
380 /**
381  * pull_netr_AcctLockStr
382  */
383
384 NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
385                                struct lsa_BinaryString *r,
386                                struct netr_AcctLockStr **str_p)
387 {
388         struct netr_AcctLockStr *str;
389         enum ndr_err_code ndr_err;
390         DATA_BLOB blob;
391
392         if (!mem_ctx || !r || !str_p) {
393                 return NT_STATUS_INVALID_PARAMETER;
394         }
395
396         *str_p = NULL;
397
398         str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
399         if (!str) {
400                 return NT_STATUS_NO_MEMORY;
401         }
402
403         blob = data_blob_const(r->array, r->length);
404
405         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, str,
406                        (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
407
408         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
409                 return ndr_map_error2ntstatus(ndr_err);
410         }
411
412         *str_p = str;
413
414         return NT_STATUS_OK;
415 }
416