b89f4efaf571f2e7c0fcee5c5c8d0a7f7e1a504b
[ira/wip.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.h"
26 #include "../lib/crypto/crypto.h"
27 #include "../libcli/auth/libcli_auth.h"
28
29 /**
30  * Decrypt and extract the user's passwords.
31  *
32  * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted)
33  * passwords back into the structure
34  */
35
36 static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
37                          DATA_BLOB *session_key,
38                          enum netr_SamDatabaseID database_id,
39                          struct netr_DELTA_ENUM *delta)
40 {
41
42         uint32_t rid = delta->delta_id_union.rid;
43         struct netr_DELTA_USER *user = delta->delta_union.user;
44         struct samr_Password lm_hash;
45         struct samr_Password nt_hash;
46         unsigned char zero_buf[16];
47
48         memset(zero_buf, '\0', sizeof(zero_buf));
49
50         /* Note that win2000 may send us all zeros
51          * for the hashes if it doesn't
52          * think this channel is secure enough. */
53         if (user->lm_password_present) {
54                 if (memcmp(user->lmpassword.hash, zero_buf, 16) != 0) {
55                         sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
56                 } else {
57                         memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
58                 }
59                 user->lmpassword = lm_hash;
60         }
61
62         if (user->nt_password_present) {
63                 if (memcmp(user->ntpassword.hash, zero_buf, 16) != 0) {
64                         sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
65                 } else {
66                         memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
67                 }
68                 user->ntpassword = nt_hash;
69         }
70
71         if (user->user_private_info.SensitiveData) {
72                 DATA_BLOB data;
73                 struct netr_USER_KEYS keys;
74                 enum ndr_err_code ndr_err;
75                 data.data = user->user_private_info.SensitiveData;
76                 data.length = user->user_private_info.DataLength;
77                 arcfour_crypt_blob(data.data, data.length, session_key);
78                 user->user_private_info.SensitiveData = data.data;
79                 user->user_private_info.DataLength = data.length;
80
81                 ndr_err = ndr_pull_struct_blob(&data, mem_ctx, NULL, &keys,
82                         (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
83                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84                         dump_data(10, data.data, data.length);
85                         return ndr_map_error2ntstatus(ndr_err);
86                 }
87
88                 /* Note that win2000 may send us all zeros
89                  * for the hashes if it doesn't
90                  * think this channel is secure enough. */
91                 if (keys.keys.keys2.lmpassword.length == 16) {
92                         if (memcmp(keys.keys.keys2.lmpassword.pwd.hash,
93                                         zero_buf, 16) != 0) {
94                                 sam_rid_crypt(rid,
95                                               keys.keys.keys2.lmpassword.pwd.hash,
96                                               lm_hash.hash, 0);
97                         } else {
98                                 memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
99                         }
100                         user->lmpassword = lm_hash;
101                         user->lm_password_present = true;
102                 }
103                 if (keys.keys.keys2.ntpassword.length == 16) {
104                         if (memcmp(keys.keys.keys2.ntpassword.pwd.hash,
105                                                 zero_buf, 16) != 0) {
106                                 sam_rid_crypt(rid,
107                                               keys.keys.keys2.ntpassword.pwd.hash,
108                                               nt_hash.hash, 0);
109                         } else {
110                                 memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
111                         }
112                         user->ntpassword = nt_hash;
113                         user->nt_password_present = true;
114                 }
115                 /* TODO: rid decrypt history fields */
116         }
117         return NT_STATUS_OK;
118 }
119
120 /**
121  * Decrypt and extract the secrets
122  *
123  * The writes decrypted secrets back into the structure
124  */
125 static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
126                            DATA_BLOB *session_key,
127                            enum netr_SamDatabaseID database_id,
128                            struct netr_DELTA_ENUM *delta)
129 {
130         struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
131
132         arcfour_crypt_blob(secret->current_cipher.cipher_data,
133                            secret->current_cipher.maxlen,
134                            session_key);
135         
136         arcfour_crypt_blob(secret->old_cipher.cipher_data,
137                            secret->old_cipher.maxlen,
138                            session_key);
139
140         return NT_STATUS_OK;
141 }
142
143 /**
144  * Fix up the delta, dealing with encryption issues so that the final
145  * callback need only do the printing or application logic
146  */
147
148 static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
149                                   DATA_BLOB *session_key,
150                                   enum netr_SamDatabaseID database_id,
151                                   struct netr_DELTA_ENUM *delta)
152 {
153         NTSTATUS status = NT_STATUS_OK;
154
155         switch (delta->delta_type) {
156                 case NETR_DELTA_USER:
157
158                         status = fix_user(mem_ctx,
159                                           session_key,
160                                           database_id,
161                                           delta);
162                         break;
163                 case NETR_DELTA_SECRET:
164
165                         status = fix_secret(mem_ctx,
166                                             session_key,
167                                             database_id,
168                                             delta);
169                         break;
170                 default:
171                         break;
172         }
173
174         return status;
175 }
176
177 /**
178  * Fix up the delta, dealing with encryption issues so that the final
179  * callback need only do the printing or application logic
180  */
181
182 static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
183                                         DATA_BLOB *session_key,
184                                         enum netr_SamDatabaseID database_id,
185                                         struct netr_DELTA_ENUM_ARRAY *r)
186 {
187         NTSTATUS status;
188         int i;
189
190         for (i = 0; i < r->num_deltas; i++) {
191
192                 status = samsync_fix_delta(mem_ctx,
193                                            session_key,
194                                            database_id,
195                                            &r->delta_enum[i]);
196                 if (!NT_STATUS_IS_OK(status)) {
197                         return status;
198                 }
199         }
200
201         return NT_STATUS_OK;
202 }
203
204 /**
205  * libnet_samsync_init_context
206  */
207
208 NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
209                                      const struct dom_sid *domain_sid,
210                                      struct samsync_context **ctx_p)
211 {
212         struct samsync_context *ctx;
213
214         *ctx_p = NULL;
215
216         ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
217         NT_STATUS_HAVE_NO_MEMORY(ctx);
218
219         if (domain_sid) {
220                 ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
221                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
222
223                 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
224                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
225         }
226
227         *ctx_p = ctx;
228
229         return NT_STATUS_OK;
230 }
231
232 /**
233  * samsync_database_str
234  */
235
236 static const char *samsync_database_str(enum netr_SamDatabaseID database_id)
237 {
238
239         switch (database_id) {
240                 case SAM_DATABASE_DOMAIN:
241                         return "DOMAIN";
242                 case SAM_DATABASE_BUILTIN:
243                         return "BUILTIN";
244                 case SAM_DATABASE_PRIVS:
245                         return "PRIVS";
246                 default:
247                         return "unknown";
248         }
249 }
250
251 /**
252  * samsync_debug_str
253  */
254
255 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
256                                      enum net_samsync_mode mode,
257                                      enum netr_SamDatabaseID database_id)
258 {
259         const char *action = NULL;
260
261         switch (mode) {
262                 case NET_SAMSYNC_MODE_DUMP:
263                         action = "Dumping (to stdout)";
264                         break;
265                 case NET_SAMSYNC_MODE_FETCH_PASSDB:
266                         action = "Fetching (to passdb)";
267                         break;
268                 case NET_SAMSYNC_MODE_FETCH_LDIF:
269                         action = "Fetching (to ldif)";
270                         break;
271                 case NET_SAMSYNC_MODE_FETCH_KEYTAB:
272                         action = "Fetching (to keytab)";
273                         break;
274                 default:
275                         action = "Unknown";
276                         break;
277         }
278
279         return talloc_asprintf(mem_ctx, "%s %s database",
280                                 action, samsync_database_str(database_id));
281 }
282
283 /**
284  * libnet_samsync
285  */
286
287 static void libnet_init_netr_ChangeLogEntry(struct samsync_object *o,
288                                             struct netr_ChangeLogEntry *e)
289 {
290         ZERO_STRUCTP(e);
291
292         e->db_index             = o->database_id;
293         e->delta_type           = o->object_type;
294
295         switch (e->delta_type) {
296                 case NETR_DELTA_DOMAIN:
297                 case NETR_DELTA_DELETE_GROUP:
298                 case NETR_DELTA_RENAME_GROUP:
299                 case NETR_DELTA_DELETE_USER:
300                 case NETR_DELTA_RENAME_USER:
301                 case NETR_DELTA_DELETE_ALIAS:
302                 case NETR_DELTA_RENAME_ALIAS:
303                 case NETR_DELTA_DELETE_TRUST:
304                 case NETR_DELTA_DELETE_ACCOUNT:
305                 case NETR_DELTA_DELETE_SECRET:
306                 case NETR_DELTA_DELETE_GROUP2:
307                 case NETR_DELTA_DELETE_USER2:
308                 case NETR_DELTA_MODIFY_COUNT:
309                         break;
310                 case NETR_DELTA_USER:
311                 case NETR_DELTA_GROUP:
312                 case NETR_DELTA_GROUP_MEMBER:
313                 case NETR_DELTA_ALIAS:
314                 case NETR_DELTA_ALIAS_MEMBER:
315                         e->object_rid = o->object_identifier.rid;
316                         break;
317                 case NETR_DELTA_SECRET:
318                         e->object.object_name = o->object_identifier.name;
319                         e->flags = NETR_CHANGELOG_NAME_INCLUDED;
320                         break;
321                 case NETR_DELTA_TRUSTED_DOMAIN:
322                 case NETR_DELTA_ACCOUNT:
323                 case NETR_DELTA_POLICY:
324                         e->object.object_sid = o->object_identifier.sid;
325                         e->flags = NETR_CHANGELOG_SID_INCLUDED;
326                         break;
327                 default:
328                         break;
329         }
330 }
331
332 /**
333  * libnet_samsync_delta
334  */
335
336 static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
337                                      enum netr_SamDatabaseID database_id,
338                                      uint64_t *sequence_num,
339                                      struct samsync_context *ctx,
340                                      struct netr_ChangeLogEntry *e)
341 {
342         NTSTATUS result;
343         NTSTATUS callback_status;
344         const char *logon_server = ctx->cli->desthost;
345         const char *computername = global_myname();
346         struct netr_Authenticator credential;
347         struct netr_Authenticator return_authenticator;
348         uint16_t restart_state = 0;
349         uint32_t sync_context = 0;
350         DATA_BLOB session_key;
351
352         ZERO_STRUCT(return_authenticator);
353
354         do {
355                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
356
357                 netlogon_creds_client_step(ctx->cli->dc, &credential);
358
359                 if (ctx->single_object_replication &&
360                     !ctx->force_full_replication) {
361                         result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
362                                                           logon_server,
363                                                           computername,
364                                                           &credential,
365                                                           &return_authenticator,
366                                                           *e,
367                                                           0,
368                                                           &delta_enum_array);
369                 } else if (!ctx->force_full_replication &&
370                            sequence_num && (*sequence_num > 0)) {
371                         result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
372                                                             logon_server,
373                                                             computername,
374                                                             &credential,
375                                                             &return_authenticator,
376                                                             database_id,
377                                                             sequence_num,
378                                                             &delta_enum_array,
379                                                             0xffff);
380                 } else {
381                         result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
382                                                            logon_server,
383                                                            computername,
384                                                            &credential,
385                                                            &return_authenticator,
386                                                            database_id,
387                                                            restart_state,
388                                                            &sync_context,
389                                                            &delta_enum_array,
390                                                            0xffff);
391                 }
392
393                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
394                         return result;
395                 }
396
397                 /* Check returned credentials. */
398                 if (!netlogon_creds_client_check(ctx->cli->dc,
399                                                  &return_authenticator.cred)) {
400                         DEBUG(0,("credentials chain check failed\n"));
401                         return NT_STATUS_ACCESS_DENIED;
402                 }
403
404                 if (NT_STATUS_IS_ERR(result)) {
405                         break;
406                 }
407
408                 session_key = data_blob_const(ctx->cli->dc->sess_key, 16);
409
410                 samsync_fix_delta_array(mem_ctx,
411                                         &session_key,
412                                         database_id,
413                                         delta_enum_array);
414
415                 /* Process results */
416                 callback_status = ctx->ops->process_objects(mem_ctx, database_id,
417                                                             delta_enum_array,
418                                                             sequence_num,
419                                                             ctx);
420                 if (!NT_STATUS_IS_OK(callback_status)) {
421                         result = callback_status;
422                         goto out;
423                 }
424
425                 TALLOC_FREE(delta_enum_array);
426
427         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
428
429  out:
430
431         return result;
432 }
433
434 /**
435  * libnet_samsync
436  */
437
438 NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
439                         struct samsync_context *ctx)
440 {
441         NTSTATUS status = NT_STATUS_OK;
442         NTSTATUS callback_status;
443         TALLOC_CTX *mem_ctx;
444         const char *debug_str;
445         uint64_t sequence_num = 0;
446         int i = 0;
447
448         if (!(mem_ctx = talloc_new(ctx))) {
449                 return NT_STATUS_NO_MEMORY;
450         }
451
452         if (!ctx->ops) {
453                 return NT_STATUS_INVALID_PARAMETER;
454         }
455
456         if (ctx->ops->startup) {
457                 status = ctx->ops->startup(mem_ctx, ctx,
458                                            database_id, &sequence_num);
459                 if (!NT_STATUS_IS_OK(status)) {
460                         goto done;
461                 }
462         }
463
464         debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
465         if (debug_str) {
466                 d_fprintf(stderr, "%s\n", debug_str);
467         }
468
469         if (!ctx->single_object_replication) {
470                 status = libnet_samsync_delta(mem_ctx, database_id,
471                                               &sequence_num, ctx, NULL);
472                 goto done;
473         }
474
475         for (i=0; i<ctx->num_objects; i++) {
476
477                 struct netr_ChangeLogEntry e;
478
479                 if (ctx->objects[i].database_id != database_id) {
480                         continue;
481                 }
482
483                 libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
484
485                 status = libnet_samsync_delta(mem_ctx, database_id,
486                                               &sequence_num, ctx, &e);
487                 if (!NT_STATUS_IS_OK(status)) {
488                         goto done;
489                 }
490         }
491
492  done:
493
494         if (NT_STATUS_IS_OK(status) && ctx->ops->finish) {
495                 callback_status = ctx->ops->finish(mem_ctx, ctx,
496                                                    database_id, sequence_num);
497                 if (!NT_STATUS_IS_OK(callback_status)) {
498                         status = callback_status;
499                 }
500         }
501
502         if (NT_STATUS_IS_ERR(status) && !ctx->error_message) {
503
504                 ctx->error_message = talloc_asprintf(ctx,
505                         "Failed to fetch %s database: %s",
506                         samsync_database_str(database_id),
507                         nt_errstr(status));
508
509                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
510
511                         ctx->error_message =
512                                 talloc_asprintf_append(ctx->error_message,
513                                         "\nPerhaps %s is a Windows native mode domain?",
514                                         ctx->domain_name);
515                 }
516         }
517
518         talloc_destroy(mem_ctx);
519
520         return status;
521 }
522
523 /**
524  * pull_netr_AcctLockStr
525  */
526
527 NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
528                                struct lsa_BinaryString *r,
529                                struct netr_AcctLockStr **str_p)
530 {
531         struct netr_AcctLockStr *str;
532         enum ndr_err_code ndr_err;
533         DATA_BLOB blob;
534
535         if (!mem_ctx || !r || !str_p) {
536                 return NT_STATUS_INVALID_PARAMETER;
537         }
538
539         *str_p = NULL;
540
541         str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
542         if (!str) {
543                 return NT_STATUS_NO_MEMORY;
544         }
545
546         blob = data_blob_const(r->array, r->length);
547
548         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, str,
549                        (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
550
551         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
552                 return ndr_map_error2ntstatus(ndr_err);
553         }
554
555         *str_p = str;
556
557         return NT_STATUS_OK;
558 }
559