43891ce829e6272263baf8151b9d7529c653e311
[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(enum netr_SamDatabaseID database_id,
335                                      struct samsync_context *ctx,
336                                      struct netr_ChangeLogEntry *e)
337 {
338         NTSTATUS result;
339         NTSTATUS callback_status;
340         TALLOC_CTX *mem_ctx;
341         const char *logon_server = ctx->cli->desthost;
342         const char *computername = global_myname();
343         struct netr_Authenticator credential;
344         struct netr_Authenticator return_authenticator;
345         uint16_t restart_state = 0;
346         uint32_t sync_context = 0;
347         const char *debug_str;
348         DATA_BLOB session_key;
349         uint64_t sequence_num = 0;
350
351         ZERO_STRUCT(return_authenticator);
352
353         if (!ctx->ops) {
354                 return NT_STATUS_INVALID_PARAMETER;
355         }
356
357         if (!(mem_ctx = talloc_init("libnet_samsync"))) {
358                 return NT_STATUS_NO_MEMORY;
359         }
360
361         if (ctx->ops->startup) {
362                 result = ctx->ops->startup(mem_ctx, ctx,
363                                            database_id, &sequence_num);
364                 if (!NT_STATUS_IS_OK(result)) {
365                         goto out;
366                 }
367         }
368
369         debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
370         if (debug_str) {
371                 d_fprintf(stderr, "%s\n", debug_str);
372         }
373
374         do {
375                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
376
377                 netlogon_creds_client_step(ctx->cli->dc, &credential);
378
379                 if (ctx->single_object_replication) {
380                         result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
381                                                           logon_server,
382                                                           computername,
383                                                           &credential,
384                                                           &return_authenticator,
385                                                           *e,
386                                                           0,
387                                                           &delta_enum_array);
388                 } else {
389                         result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
390                                                            logon_server,
391                                                            computername,
392                                                            &credential,
393                                                            &return_authenticator,
394                                                            database_id,
395                                                            restart_state,
396                                                            &sync_context,
397                                                            &delta_enum_array,
398                                                            0xffff);
399                 }
400
401                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
402                         return result;
403                 }
404
405                 /* Check returned credentials. */
406                 if (!netlogon_creds_client_check(ctx->cli->dc,
407                                                  &return_authenticator.cred)) {
408                         DEBUG(0,("credentials chain check failed\n"));
409                         return NT_STATUS_ACCESS_DENIED;
410                 }
411
412                 if (NT_STATUS_IS_ERR(result)) {
413                         break;
414                 }
415
416                 session_key = data_blob_const(ctx->cli->dc->sess_key, 16);
417
418                 samsync_fix_delta_array(mem_ctx,
419                                         &session_key,
420                                         database_id,
421                                         delta_enum_array);
422
423                 /* Process results */
424                 callback_status = ctx->ops->process_objects(mem_ctx, database_id,
425                                                             delta_enum_array,
426                                                             &sequence_num,
427                                                             ctx);
428                 if (!NT_STATUS_IS_OK(callback_status)) {
429                         result = callback_status;
430                         goto out;
431                 }
432
433                 TALLOC_FREE(delta_enum_array);
434
435                 /* Increment sync_context */
436                 sync_context += 1;
437
438         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
439
440  out:
441
442         if (NT_STATUS_IS_OK(result) && ctx->ops->finish) {
443                 callback_status = ctx->ops->finish(mem_ctx, ctx,
444                                                    database_id, sequence_num);
445                 if (!NT_STATUS_IS_OK(callback_status)) {
446                         result = callback_status;
447                 }
448         }
449
450         if (NT_STATUS_IS_ERR(result) && !ctx->error_message) {
451
452                 ctx->error_message = talloc_asprintf(ctx,
453                         "Failed to fetch %s database: %s",
454                         samsync_database_str(database_id),
455                         nt_errstr(result));
456
457                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
458
459                         ctx->error_message =
460                                 talloc_asprintf_append(ctx->error_message,
461                                         "\nPerhaps %s is a Windows native mode domain?",
462                                         ctx->domain_name);
463                 }
464         }
465
466         talloc_destroy(mem_ctx);
467
468         return result;
469 }
470
471 /**
472  * libnet_samsync
473  */
474
475 NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
476                         struct samsync_context *ctx)
477 {
478         NTSTATUS status = NT_STATUS_OK;
479         int i = 0;
480
481         if (!ctx->single_object_replication) {
482                 return libnet_samsync_delta(database_id, ctx, NULL);
483         }
484
485         for (i=0; i<ctx->num_objects; i++) {
486
487                 struct netr_ChangeLogEntry e;
488
489                 if (ctx->objects[i].database_id != database_id) {
490                         continue;
491                 }
492
493                 libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
494
495                 status = libnet_samsync_delta(database_id, ctx, &e);
496                 if (!NT_STATUS_IS_OK(status)) {
497                         return status;
498                 }
499         }
500
501         return status;
502 }
503
504 /**
505  * pull_netr_AcctLockStr
506  */
507
508 NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
509                                struct lsa_BinaryString *r,
510                                struct netr_AcctLockStr **str_p)
511 {
512         struct netr_AcctLockStr *str;
513         enum ndr_err_code ndr_err;
514         DATA_BLOB blob;
515
516         if (!mem_ctx || !r || !str_p) {
517                 return NT_STATUS_INVALID_PARAMETER;
518         }
519
520         *str_p = NULL;
521
522         str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
523         if (!str) {
524                 return NT_STATUS_NO_MEMORY;
525         }
526
527         blob = data_blob_const(r->array, r->length);
528
529         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, str,
530                        (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
531
532         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
533                 return ndr_map_error2ntstatus(ndr_err);
534         }
535
536         *str_p = str;
537
538         return NT_STATUS_OK;
539 }
540