r6928: Add support for printing trusted domain names, sids and passwords in
[kai/samba.git] / source4 / libnet / libnet_vampire.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    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 #include "includes.h"
25 #include "libnet/libnet.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "librpc/gen_ndr/ndr_samr.h"
28 #include "dlinklist.h"
29
30 struct samsync_secret {
31         struct samsync_secret *prev, *next;
32         DATA_BLOB secret;
33         char *name;
34         NTTIME mtime;
35 };
36
37 struct samsync_trusted_domain {
38         struct samsync_trusted_domain *prev, *next;
39         struct dom_sid *sid;
40         char *name;
41 };
42
43 struct samdump_state {
44         struct samsync_secret *secrets;
45         struct samsync_trusted_domain *trusted_domains;
46 };
47
48
49 /**
50  * Decrypt and extract the user's passwords.  
51  * 
52  * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted) passwords back into the structure
53  */
54 static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
55                          struct creds_CredentialState *creds,
56                          enum netr_SamDatabaseID database,
57                          struct netr_DELTA_ENUM *delta,
58                          char **error_string) 
59 {
60
61         uint32_t rid = delta->delta_id_union.rid;
62         struct netr_DELTA_USER *user = delta->delta_union.user;
63         struct samr_Password lm_hash;
64         struct samr_Password nt_hash;
65         const char *username = user->account_name.string;
66         NTSTATUS nt_status;
67
68         if (user->lm_password_present) {
69                 sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
70                 user->lmpassword = lm_hash;
71         }
72
73         if (user->nt_password_present) {
74                 sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
75                 user->ntpassword = nt_hash;
76         }
77
78         if (user->user_private_info.SensitiveData) {
79                 DATA_BLOB data;
80                 struct netr_USER_KEYS keys;
81                 data.data = user->user_private_info.SensitiveData;
82                 data.length = user->user_private_info.DataLength;
83                 creds_arcfour_crypt(creds, data.data, data.length);
84                 user->user_private_info.SensitiveData = data.data;
85                 user->user_private_info.DataLength = data.length;
86
87                 nt_status = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
88                 if (NT_STATUS_IS_OK(nt_status)) {
89                         if (keys.keys.keys2.lmpassword.length == 16) {
90                                 sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0);
91                                 user->lmpassword = lm_hash;
92                                 user->lm_password_present = True;
93                         }
94                         if (keys.keys.keys2.ntpassword.length == 16) {
95                                 sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
96                                 user->ntpassword = nt_hash;
97                                 user->nt_password_present = True;
98                         }
99                 } else {
100                         *error_string = talloc_asprintf(mem_ctx, "Failed to parse Sensitive Data for %s:\n", username);
101                         dump_data(10, data.data, data.length);
102                         return nt_status;
103                 }
104         }
105         return NT_STATUS_OK;
106 }
107
108 /**
109  * Decrypt and extract the secrets
110  * 
111  * The writes decrypted secrets back into the structure
112  */
113 static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
114                            struct creds_CredentialState *creds,
115                            enum netr_SamDatabaseID database,
116                            struct netr_DELTA_ENUM *delta,
117                            char **error_string) 
118 {
119         struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
120         creds_arcfour_crypt(creds, secret->current_cipher.cipher_data, 
121                             secret->current_cipher.maxlen); 
122
123         creds_arcfour_crypt(creds, secret->old_cipher.cipher_data, 
124                             secret->old_cipher.maxlen); 
125
126         return NT_STATUS_OK;
127 }
128
129 /**
130  * Fix up the delta, dealing with encryption issues so that the final
131  * callback need only do the printing or application logic
132  */
133
134 static NTSTATUS fix_delta(TALLOC_CTX *mem_ctx,          
135                           struct creds_CredentialState *creds,
136                           enum netr_SamDatabaseID database,
137                           struct netr_DELTA_ENUM *delta,
138                           char **error_string)
139 {
140         NTSTATUS nt_status = NT_STATUS_OK;
141         *error_string = NULL;
142         switch (delta->delta_type) {
143         case NETR_DELTA_USER:
144         {
145                 nt_status = fix_user(mem_ctx, 
146                                      creds,
147                                      database,
148                                      delta,
149                                      error_string);
150                 break;
151         }
152         case NETR_DELTA_SECRET:
153         {
154                 nt_status = fix_secret(mem_ctx, 
155                                        creds,
156                                        database,
157                                        delta,
158                                        error_string);
159                 break;
160         }
161         }
162         return nt_status;
163 }
164
165 static NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamSync *r)
166 {
167         NTSTATUS nt_status, dbsync_nt_status;
168         TALLOC_CTX *loop_ctx, *delta_ctx;
169         struct creds_CredentialState *creds;
170         struct netr_DatabaseSync dbsync;
171         struct cli_credentials *machine_account;
172         struct dcerpc_binding *b;
173         struct dcerpc_pipe *p;
174         const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; 
175         int i;
176
177         /* TODO: This is bogus */
178         const char **bindings = lp_passwordserver();
179         const char *binding;
180
181         if (bindings && bindings[0]) {
182                 binding = bindings[0];
183         }
184
185         machine_account = cli_credentials_init(mem_ctx);
186         if (!machine_account) {
187                 return NT_STATUS_NO_MEMORY;
188         }
189
190         cli_credentials_set_conf(machine_account);
191         nt_status = cli_credentials_set_machine_account(machine_account);
192         
193         if (!NT_STATUS_IS_OK(nt_status)) {
194                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
195                 return nt_status;
196         }
197         
198         if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
199                 r->netlogon.error_string
200                         = talloc_asprintf(mem_ctx, 
201                                           "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
202                                           
203                                           cli_credentials_get_domain(machine_account),
204                                           cli_credentials_get_secure_channel_type(machine_account));
205                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
206         }
207
208         /* Connect to DC (take a binding string for now) */
209
210         nt_status = dcerpc_parse_binding(mem_ctx, binding, &b);
211         if (!NT_STATUS_IS_OK(nt_status)) {
212                 r->netlogon.error_string = talloc_asprintf(mem_ctx, "Bad binding string %s\n", binding);
213                 return NT_STATUS_INVALID_PARAMETER;
214         }
215
216         /* We like schannel */
217         b->flags &= ~DCERPC_AUTH_OPTIONS;
218         b->flags |= DCERPC_SCHANNEL | DCERPC_SEAL /* | DCERPC_SCHANNEL_128 */;
219
220         /* Setup schannel */
221         nt_status = dcerpc_pipe_connect_b(mem_ctx, &p, b, 
222                                           DCERPC_NETLOGON_UUID,
223                                           DCERPC_NETLOGON_VERSION,
224                                           machine_account);
225
226         if (!NT_STATUS_IS_OK(nt_status)) {
227                 return nt_status;
228         }
229
230         /* get NETLOGON credentails */
231
232         nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
233         if (!NT_STATUS_IS_OK(nt_status)) {
234                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
235                 return nt_status;
236         }
237
238         dbsync.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
239         dbsync.in.computername = cli_credentials_get_workstation(machine_account);
240         dbsync.in.preferredmaximumlength = (uint32_t)-1;
241         ZERO_STRUCT(dbsync.in.return_authenticator);
242
243         for (i=0;i< ARRAY_SIZE(database_ids); i++) { 
244                 dbsync.in.sync_context = 0;
245                 dbsync.in.database_id = database_ids[i]; 
246                 
247                 do {
248                         int d;
249                         loop_ctx = talloc_named(mem_ctx, 0, "DatabaseSync loop context");
250                         creds_client_authenticator(creds, &dbsync.in.credential);
251                         
252                         dbsync_nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync);
253                         if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
254                             !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
255                                 r->netlogon.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
256                                 return nt_status;
257                         }
258                         
259                         if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
260                                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Credential chaining failed");
261                                 return NT_STATUS_ACCESS_DENIED;
262                         }
263                         
264                         dbsync.in.sync_context = dbsync.out.sync_context;
265                         
266                         for (d=0; d < dbsync.out.delta_enum_array->num_deltas; d++) {
267                                 char *error_string = NULL;
268                                 delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
269                                 nt_status = fix_delta(delta_ctx, 
270                                                       creds, 
271                                                       dbsync.in.database_id,
272                                                       &dbsync.out.delta_enum_array->delta_enum[d], 
273                                                       &error_string);
274                                 if (!NT_STATUS_IS_OK(nt_status)) {
275                                         r->netlogon.error_string = talloc_steal(mem_ctx, error_string);
276                                         talloc_free(delta_ctx);
277                                         return nt_status;
278                                 }
279                                 nt_status = r->netlogon.delta_fn(delta_ctx, 
280                                                                  r->netlogon.fn_ctx,
281                                                                  creds,
282                                                                  dbsync.in.database_id,
283                                                                  &dbsync.out.delta_enum_array->delta_enum[d], 
284                                                                  &error_string);
285                                 if (!NT_STATUS_IS_OK(nt_status)) {
286                                         r->netlogon.error_string = talloc_steal(mem_ctx, error_string);
287                                         talloc_free(delta_ctx);
288                                         return nt_status;
289                                 }
290                                 talloc_free(delta_ctx);
291                         }
292                         talloc_free(loop_ctx);
293                 } while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
294                 nt_status = dbsync_nt_status;
295         }
296         return nt_status;
297 }
298
299 static NTSTATUS vampire_samdump_handle_user(TALLOC_CTX *mem_ctx,
300                                             struct creds_CredentialState *creds,
301                                             struct netr_DELTA_ENUM *delta) 
302 {
303         uint32_t rid = delta->delta_id_union.rid;
304         struct netr_DELTA_USER *user = delta->delta_union.user;
305         const char *username = user->account_name.string;
306         char *hex_lm_password;
307         char *hex_nt_password;
308
309         hex_lm_password = smbpasswd_sethexpwd(mem_ctx, 
310                                               user->lm_password_present ? &user->lmpassword : NULL, 
311                                               user->acct_flags);
312         hex_nt_password = smbpasswd_sethexpwd(mem_ctx, 
313                                               user->nt_password_present ? &user->ntpassword : NULL, 
314                                               user->acct_flags);
315
316         printf("%s:%d:%s:%s:%s:LCT-%08X\n", username,
317                rid, hex_lm_password, hex_nt_password,
318                smbpasswd_encode_acb_info(mem_ctx, user->acct_flags),
319                (unsigned int)nt_time_to_unix(user->last_password_change));
320
321         return NT_STATUS_OK;
322 }
323
324 static NTSTATUS vampire_samdump_handle_secret(TALLOC_CTX *mem_ctx,
325                                               struct samdump_state *samdump_state,
326                                               struct creds_CredentialState *creds,
327                                               struct netr_DELTA_ENUM *delta) 
328 {
329         struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
330         const char *name = delta->delta_id_union.name;
331         struct samsync_secret *new = talloc(samdump_state, struct samsync_secret);
332
333         new->name = talloc_reference(new, name);
334         new->secret = data_blob_talloc(new, secret->current_cipher.cipher_data, secret->current_cipher.maxlen);
335         new->mtime = secret->current_cipher_set_time;
336
337         DLIST_ADD(samdump_state->secrets, new);
338
339         return NT_STATUS_OK;
340 }
341
342 static NTSTATUS vampire_samdump_handle_trusted_domain(TALLOC_CTX *mem_ctx,
343                                               struct samdump_state *samdump_state,
344                                               struct creds_CredentialState *creds,
345                                               struct netr_DELTA_ENUM *delta) 
346 {
347         struct netr_DELTA_TRUSTED_DOMAIN *trusted_domain = delta->delta_union.trusted_domain;
348         struct dom_sid *dom_sid = delta->delta_id_union.sid;
349
350         struct samsync_trusted_domain *new = talloc(samdump_state, struct samsync_trusted_domain);
351
352         new->name = talloc_reference(new, trusted_domain->domain_name.string);
353         new->sid = talloc_reference(new, dom_sid);
354
355         DLIST_ADD(samdump_state->trusted_domains, new);
356
357         return NT_STATUS_OK;
358 }
359
360 static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx,          
361                                   void *private,                        
362                                   struct creds_CredentialState *creds,
363                                   enum netr_SamDatabaseID database,
364                                   struct netr_DELTA_ENUM *delta,
365                                   char **error_string)
366 {
367         NTSTATUS nt_status = NT_STATUS_OK;
368         struct samdump_state *samdump_state = private;
369
370         *error_string = NULL;
371         switch (delta->delta_type) {
372         case NETR_DELTA_USER:
373         {
374                 /* not interested in builtin users */
375                 if (database == SAM_DATABASE_DOMAIN) {
376                         nt_status = vampire_samdump_handle_user(mem_ctx, 
377                                                                 creds,
378                                                                 delta);
379                         break;
380                 }
381         }
382         case NETR_DELTA_SECRET:
383         {
384                 nt_status = vampire_samdump_handle_secret(mem_ctx,
385                                                           samdump_state,
386                                                           creds,
387                                                           delta);
388                 break;
389         }
390         case NETR_DELTA_TRUSTED_DOMAIN:
391         {
392                 nt_status = vampire_samdump_handle_trusted_domain(mem_ctx,
393                                                                   samdump_state,
394                                                                   creds,
395                                                                   delta);
396                 break;
397         }
398         }
399         return nt_status;
400 }
401
402 NTSTATUS libnet_SamDump_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
403 {
404         NTSTATUS nt_status;
405         union libnet_SamSync r2;
406         struct samdump_state *samdump_state = talloc(mem_ctx, struct samdump_state);
407
408         struct samsync_trusted_domain *t;
409         struct samsync_secret *s;
410
411         if (!samdump_state) {
412                 return NT_STATUS_NO_MEMORY;
413         }
414
415         samdump_state->secrets = NULL;
416         samdump_state->trusted_domains = NULL;
417
418         r2.netlogon.level = LIBNET_SAMDUMP_NETLOGON;
419         r2.netlogon.error_string = NULL;
420         r2.netlogon.delta_fn = libnet_samdump_fn;
421         r2.netlogon.fn_ctx = samdump_state;
422         nt_status = libnet_SamSync_netlogon(ctx, mem_ctx, &r2);
423         r->generic.error_string = r2.netlogon.error_string;
424
425         if (!NT_STATUS_IS_OK(nt_status)) {
426                 return nt_status;
427         }
428
429         printf("Trusted domains, sids and secrets:\n");
430         for (t=samdump_state->trusted_domains; t; t=t->next) {
431                 char *secret_name = talloc_asprintf(mem_ctx, "G$$%s", t->name);
432                 for (s=samdump_state->secrets; s; s=s->next) {
433                         if (StrCaseCmp(s->name, secret_name) == 0) {
434                                 char *secret_string;
435                                 if (convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
436                                                           s->secret.data, s->secret.length, 
437                                                           (void **)&secret_string) == -1) {
438                                         r->generic.error_string = talloc_asprintf(mem_ctx, 
439                                                                                   "Could not convert secret for domain %s to a string\n",
440                                                                                   t->name);
441                                         return NT_STATUS_INVALID_PARAMETER;
442                                 }
443                                 printf("%s\t%s\t%s\n", 
444                                        t->name, dom_sid_string(mem_ctx, t->sid), 
445                                        secret_string);
446                         }
447                 }
448         }
449         return nt_status;
450 }
451
452
453
454 NTSTATUS libnet_SamDump_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
455 {
456         NTSTATUS nt_status;
457         union libnet_SamDump r2;
458         r2.generic.level = LIBNET_SAMDUMP_NETLOGON;
459         r2.generic.error_string = NULL;
460         nt_status = libnet_SamDump(ctx, mem_ctx, &r2);
461         r->generic.error_string = r2.netlogon.error_string;
462
463         
464         return nt_status;
465 }
466
467 NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
468 {
469         switch (r->generic.level) {
470         case LIBNET_SAMDUMP_GENERIC:
471                 return libnet_SamDump_generic(ctx, mem_ctx, r);
472         case LIBNET_SAMDUMP_NETLOGON:
473                 return libnet_SamDump_netlogon(ctx, mem_ctx, r);
474         }
475
476         return NT_STATUS_INVALID_LEVEL;
477 }