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