r8741: Kill warnings about enums not fully enumerated, as we will never use
[kamenim/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         default:
162                 break;
163         }
164         return nt_status;
165 }
166
167 static NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamSync *r)
168 {
169         NTSTATUS nt_status, dbsync_nt_status;
170         TALLOC_CTX *loop_ctx, *delta_ctx;
171         struct creds_CredentialState *creds;
172         struct netr_DatabaseSync dbsync;
173         struct cli_credentials *machine_account;
174         struct dcerpc_binding *b;
175         struct dcerpc_pipe *p;
176         const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; 
177         int i;
178
179         /* TODO: This is bogus */
180         const char **bindings = lp_passwordserver();
181         const char *binding;
182
183         if (bindings && bindings[0]) {
184                 binding = bindings[0];
185         }
186
187         machine_account = cli_credentials_init(mem_ctx);
188         if (!machine_account) {
189                 return NT_STATUS_NO_MEMORY;
190         }
191
192         cli_credentials_set_conf(machine_account);
193         nt_status = cli_credentials_set_machine_account(machine_account);
194         
195         if (!NT_STATUS_IS_OK(nt_status)) {
196                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
197                 return nt_status;
198         }
199         
200         if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
201                 r->netlogon.error_string
202                         = talloc_asprintf(mem_ctx, 
203                                           "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
204                                           
205                                           cli_credentials_get_domain(machine_account),
206                                           cli_credentials_get_secure_channel_type(machine_account));
207                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
208         }
209
210         /* Connect to DC (take a binding string for now) */
211
212         nt_status = dcerpc_parse_binding(mem_ctx, binding, &b);
213         if (!NT_STATUS_IS_OK(nt_status)) {
214                 r->netlogon.error_string = talloc_asprintf(mem_ctx, "Bad binding string %s\n", binding);
215                 return NT_STATUS_INVALID_PARAMETER;
216         }
217
218         /* We like schannel */
219         b->flags &= ~DCERPC_AUTH_OPTIONS;
220         b->flags |= DCERPC_SCHANNEL | DCERPC_SEAL /* | DCERPC_SCHANNEL_128 */;
221
222         /* Setup schannel */
223         nt_status = dcerpc_pipe_connect_b(mem_ctx, &p, b, 
224                                           DCERPC_NETLOGON_UUID,
225                                           DCERPC_NETLOGON_VERSION,
226                                           machine_account, ctx->event_ctx);
227
228         if (!NT_STATUS_IS_OK(nt_status)) {
229                 return nt_status;
230         }
231
232         /* get NETLOGON credentails */
233
234         nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
235         if (!NT_STATUS_IS_OK(nt_status)) {
236                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
237                 return nt_status;
238         }
239
240         dbsync.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
241         dbsync.in.computername = cli_credentials_get_workstation(machine_account);
242         dbsync.in.preferredmaximumlength = (uint32_t)-1;
243         ZERO_STRUCT(dbsync.in.return_authenticator);
244
245         for (i=0;i< ARRAY_SIZE(database_ids); i++) { 
246                 dbsync.in.sync_context = 0;
247                 dbsync.in.database_id = database_ids[i]; 
248                 
249                 do {
250                         int d;
251                         loop_ctx = talloc_named(mem_ctx, 0, "DatabaseSync loop context");
252                         creds_client_authenticator(creds, &dbsync.in.credential);
253                         
254                         dbsync_nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync);
255                         if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
256                             !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
257                                 r->netlogon.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
258                                 return nt_status;
259                         }
260                         
261                         if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
262                                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Credential chaining failed");
263                                 return NT_STATUS_ACCESS_DENIED;
264                         }
265                         
266                         dbsync.in.sync_context = dbsync.out.sync_context;
267                         
268                         for (d=0; d < dbsync.out.delta_enum_array->num_deltas; d++) {
269                                 char *error_string = NULL;
270                                 delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
271                                 nt_status = fix_delta(delta_ctx, 
272                                                       creds, 
273                                                       dbsync.in.database_id,
274                                                       &dbsync.out.delta_enum_array->delta_enum[d], 
275                                                       &error_string);
276                                 if (!NT_STATUS_IS_OK(nt_status)) {
277                                         r->netlogon.error_string = talloc_steal(mem_ctx, error_string);
278                                         talloc_free(delta_ctx);
279                                         return nt_status;
280                                 }
281                                 nt_status = r->netlogon.delta_fn(delta_ctx, 
282                                                                  r->netlogon.fn_ctx,
283                                                                  creds,
284                                                                  dbsync.in.database_id,
285                                                                  &dbsync.out.delta_enum_array->delta_enum[d], 
286                                                                  &error_string);
287                                 if (!NT_STATUS_IS_OK(nt_status)) {
288                                         r->netlogon.error_string = talloc_steal(mem_ctx, error_string);
289                                         talloc_free(delta_ctx);
290                                         return nt_status;
291                                 }
292                                 talloc_free(delta_ctx);
293                         }
294                         talloc_free(loop_ctx);
295                 } while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
296                 nt_status = dbsync_nt_status;
297         }
298         return nt_status;
299 }
300
301 static NTSTATUS vampire_samdump_handle_user(TALLOC_CTX *mem_ctx,
302                                             struct creds_CredentialState *creds,
303                                             struct netr_DELTA_ENUM *delta) 
304 {
305         uint32_t rid = delta->delta_id_union.rid;
306         struct netr_DELTA_USER *user = delta->delta_union.user;
307         const char *username = user->account_name.string;
308         char *hex_lm_password;
309         char *hex_nt_password;
310
311         hex_lm_password = smbpasswd_sethexpwd(mem_ctx, 
312                                               user->lm_password_present ? &user->lmpassword : NULL, 
313                                               user->acct_flags);
314         hex_nt_password = smbpasswd_sethexpwd(mem_ctx, 
315                                               user->nt_password_present ? &user->ntpassword : NULL, 
316                                               user->acct_flags);
317
318         printf("%s:%d:%s:%s:%s:LCT-%08X\n", username,
319                rid, hex_lm_password, hex_nt_password,
320                smbpasswd_encode_acb_info(mem_ctx, user->acct_flags),
321                (unsigned int)nt_time_to_unix(user->last_password_change));
322
323         return NT_STATUS_OK;
324 }
325
326 static NTSTATUS vampire_samdump_handle_secret(TALLOC_CTX *mem_ctx,
327                                               struct samdump_state *samdump_state,
328                                               struct creds_CredentialState *creds,
329                                               struct netr_DELTA_ENUM *delta) 
330 {
331         struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
332         const char *name = delta->delta_id_union.name;
333         struct samsync_secret *new = talloc(samdump_state, struct samsync_secret);
334
335         new->name = talloc_reference(new, name);
336         new->secret = data_blob_talloc(new, secret->current_cipher.cipher_data, secret->current_cipher.maxlen);
337         new->mtime = secret->current_cipher_set_time;
338
339         DLIST_ADD(samdump_state->secrets, new);
340
341         return NT_STATUS_OK;
342 }
343
344 static NTSTATUS vampire_samdump_handle_trusted_domain(TALLOC_CTX *mem_ctx,
345                                               struct samdump_state *samdump_state,
346                                               struct creds_CredentialState *creds,
347                                               struct netr_DELTA_ENUM *delta) 
348 {
349         struct netr_DELTA_TRUSTED_DOMAIN *trusted_domain = delta->delta_union.trusted_domain;
350         struct dom_sid *dom_sid = delta->delta_id_union.sid;
351
352         struct samsync_trusted_domain *new = talloc(samdump_state, struct samsync_trusted_domain);
353
354         new->name = talloc_reference(new, trusted_domain->domain_name.string);
355         new->sid = talloc_reference(new, dom_sid);
356
357         DLIST_ADD(samdump_state->trusted_domains, new);
358
359         return NT_STATUS_OK;
360 }
361
362 static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx,          
363                                   void *private,                        
364                                   struct creds_CredentialState *creds,
365                                   enum netr_SamDatabaseID database,
366                                   struct netr_DELTA_ENUM *delta,
367                                   char **error_string)
368 {
369         NTSTATUS nt_status = NT_STATUS_OK;
370         struct samdump_state *samdump_state = private;
371
372         *error_string = NULL;
373         switch (delta->delta_type) {
374         case NETR_DELTA_USER:
375         {
376                 /* not interested in builtin users */
377                 if (database == SAM_DATABASE_DOMAIN) {
378                         nt_status = vampire_samdump_handle_user(mem_ctx, 
379                                                                 creds,
380                                                                 delta);
381                         break;
382                 }
383         }
384         case NETR_DELTA_SECRET:
385         {
386                 nt_status = vampire_samdump_handle_secret(mem_ctx,
387                                                           samdump_state,
388                                                           creds,
389                                                           delta);
390                 break;
391         }
392         case NETR_DELTA_TRUSTED_DOMAIN:
393         {
394                 nt_status = vampire_samdump_handle_trusted_domain(mem_ctx,
395                                                                   samdump_state,
396                                                                   creds,
397                                                                   delta);
398                 break;
399         }
400         default:
401                 /* Can't dump them all right now */
402                 break;
403         }
404         return nt_status;
405 }
406
407 NTSTATUS libnet_SamDump_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
408 {
409         NTSTATUS nt_status;
410         union libnet_SamSync r2;
411         struct samdump_state *samdump_state = talloc(mem_ctx, struct samdump_state);
412
413         struct samsync_trusted_domain *t;
414         struct samsync_secret *s;
415
416         if (!samdump_state) {
417                 return NT_STATUS_NO_MEMORY;
418         }
419
420         samdump_state->secrets = NULL;
421         samdump_state->trusted_domains = NULL;
422
423         r2.netlogon.level = LIBNET_SAMDUMP_NETLOGON;
424         r2.netlogon.error_string = NULL;
425         r2.netlogon.delta_fn = libnet_samdump_fn;
426         r2.netlogon.fn_ctx = samdump_state;
427         nt_status = libnet_SamSync_netlogon(ctx, mem_ctx, &r2);
428         r->generic.error_string = r2.netlogon.error_string;
429
430         if (!NT_STATUS_IS_OK(nt_status)) {
431                 return nt_status;
432         }
433
434         printf("Trusted domains, sids and secrets:\n");
435         for (t=samdump_state->trusted_domains; t; t=t->next) {
436                 char *secret_name = talloc_asprintf(mem_ctx, "G$$%s", t->name);
437                 for (s=samdump_state->secrets; s; s=s->next) {
438                         if (StrCaseCmp(s->name, secret_name) == 0) {
439                                 char *secret_string;
440                                 if (convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
441                                                           s->secret.data, s->secret.length, 
442                                                           (void **)&secret_string) == -1) {
443                                         r->generic.error_string = talloc_asprintf(mem_ctx, 
444                                                                                   "Could not convert secret for domain %s to a string\n",
445                                                                                   t->name);
446                                         return NT_STATUS_INVALID_PARAMETER;
447                                 }
448                                 printf("%s\t%s\t%s\n", 
449                                        t->name, dom_sid_string(mem_ctx, t->sid), 
450                                        secret_string);
451                         }
452                 }
453         }
454         return nt_status;
455 }
456
457
458
459 NTSTATUS libnet_SamDump_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
460 {
461         NTSTATUS nt_status;
462         union libnet_SamDump r2;
463         r2.generic.level = LIBNET_SAMDUMP_NETLOGON;
464         r2.generic.error_string = NULL;
465         nt_status = libnet_SamDump(ctx, mem_ctx, &r2);
466         r->generic.error_string = r2.netlogon.error_string;
467
468         
469         return nt_status;
470 }
471
472 NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
473 {
474         switch (r->generic.level) {
475         case LIBNET_SAMDUMP_GENERIC:
476                 return libnet_SamDump_generic(ctx, mem_ctx, r);
477         case LIBNET_SAMDUMP_NETLOGON:
478                 return libnet_SamDump_netlogon(ctx, mem_ctx, r);
479         }
480
481         return NT_STATUS_INVALID_LEVEL;
482 }