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