r6603: More work on the samdump puzzle. This implements a function pointer
[kamenim/samba.git] / source4 / libnet / libnet_vampire.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include "includes.h"
23 #include "libnet/libnet.h"
24 #include "librpc/gen_ndr/ndr_netlogon.h"
25 #include "librpc/gen_ndr/ndr_samr.h"
26
27 static NTSTATUS vampire_samdump_handle_user(TALLOC_CTX *mem_ctx,
28                                             struct creds_CredentialState *creds,
29                                             struct netr_DELTA_ENUM *delta) 
30 {
31         uint32_t rid = delta->delta_id_union.rid;
32         struct netr_DELTA_USER *user = delta->delta_union.user;
33         struct samr_Password lm_hash;
34         struct samr_Password nt_hash;
35         struct samr_Password *lm_hash_p = NULL;
36         struct samr_Password *nt_hash_p = NULL;
37         const char *username = user->account_name.string;
38         char *hex_lm_password;
39         char *hex_nt_password;
40
41         NTSTATUS nt_status;
42
43         if (user->lm_password_present) {
44                 sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
45                 lm_hash_p = &lm_hash;
46         }
47
48         if (user->nt_password_present) {
49                 sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
50                 nt_hash_p = &nt_hash;
51         }
52
53         if (user->user_private_info.SensitiveData) {
54                 DATA_BLOB data;
55                 struct netr_USER_KEYS keys;
56                 data.data = user->user_private_info.SensitiveData;
57                 data.length = user->user_private_info.DataLength;
58                 creds_arcfour_crypt(creds, data.data, data.length);
59                 nt_status = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
60                 if (NT_STATUS_IS_OK(nt_status)) {
61                         if (keys.keys.keys2.lmpassword.length == 16) {
62                                 sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0);
63                                 lm_hash_p = &lm_hash;
64                         }
65                         if (keys.keys.keys2.ntpassword.length == 16) {
66                                 sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
67                                 nt_hash_p = &nt_hash;
68                         }
69                 } else {
70                         DEBUG(1, ("Failed to parse Sensitive Data for %s:\n", username));
71                         dump_data(10, data.data, data.length);
72                         return nt_status;
73                 }
74         }
75
76         hex_lm_password = smbpasswd_sethexpwd(mem_ctx, lm_hash_p, user->acct_flags);
77         hex_nt_password = smbpasswd_sethexpwd(mem_ctx, nt_hash_p, user->acct_flags);
78
79         printf("%s:%d:%s:%s:%s:LCT-%08X\n", username,
80                rid, hex_lm_password, hex_nt_password,
81                smbpasswd_encode_acb_info(mem_ctx, user->acct_flags),
82                (unsigned int)nt_time_to_unix(user->last_password_change));
83
84         return NT_STATUS_OK;
85 }
86
87 static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx,          
88                                   void *private,                        
89                                   struct creds_CredentialState *creds,
90                                   enum netr_SamDatabaseID database,
91                                   struct netr_DELTA_ENUM *delta,
92                                   char **error_string)
93 {
94         NTSTATUS nt_status = NT_STATUS_OK;
95         *error_string = NULL;
96         switch (database) {
97         case SAM_DATABASE_DOMAIN: 
98         {
99                 switch (delta->delta_type) {
100                 case NETR_DELTA_USER:
101                 {
102                         nt_status = vampire_samdump_handle_user(mem_ctx, 
103                                                                 creds,
104                                                                 delta);
105                         break;
106                 }
107                 }
108                 break;
109         }
110         }
111         return nt_status;
112 }
113
114 static NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamSync *r)
115 {
116         NTSTATUS nt_status, dbsync_nt_status;
117         TALLOC_CTX *loop_ctx, *delta_ctx;
118         struct creds_CredentialState *creds;
119         struct netr_DatabaseSync dbsync;
120         struct cli_credentials *machine_account;
121         struct dcerpc_binding *b;
122         struct dcerpc_pipe *p;
123         const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; 
124         int i;
125
126         /* TODO: This is bogus */
127         const char **bindings = lp_passwordserver();
128         const char *binding;
129
130         if (bindings && bindings[0]) {
131                 binding = bindings[0];
132         }
133
134         machine_account = cli_credentials_init(mem_ctx);
135         if (!machine_account) {
136                 return NT_STATUS_NO_MEMORY;
137         }
138
139         cli_credentials_set_conf(machine_account);
140         nt_status = cli_credentials_set_machine_account(machine_account);
141         
142         if (!NT_STATUS_IS_OK(nt_status)) {
143                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
144                 return nt_status;
145         }
146         
147         if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
148                 r->netlogon.error_string
149                         = talloc_asprintf(mem_ctx, 
150                                           "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
151                                           
152                                           cli_credentials_get_domain(machine_account),
153                                           cli_credentials_get_secure_channel_type(machine_account));
154                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
155         }
156
157         /* Connect to DC (take a binding string for now) */
158
159         nt_status = dcerpc_parse_binding(mem_ctx, binding, &b);
160         if (!NT_STATUS_IS_OK(nt_status)) {
161                 r->netlogon.error_string = talloc_asprintf(mem_ctx, "Bad binding string %s\n", binding);
162                 return NT_STATUS_INVALID_PARAMETER;
163         }
164
165         /* We like schannel */
166         b->flags &= ~DCERPC_AUTH_OPTIONS;
167         b->flags |= DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128;
168
169         /* Setup schannel */
170         nt_status = dcerpc_pipe_connect_b(mem_ctx, &p, b, 
171                                           DCERPC_NETLOGON_UUID,
172                                           DCERPC_NETLOGON_VERSION,
173                                           machine_account);
174
175         if (!NT_STATUS_IS_OK(nt_status)) {
176                 return nt_status;
177         }
178
179         /* get NETLOGON credentails */
180
181         nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
182         if (!NT_STATUS_IS_OK(nt_status)) {
183                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
184                 return nt_status;
185         }
186
187         dbsync.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
188         dbsync.in.computername = cli_credentials_get_workstation(machine_account);
189         dbsync.in.preferredmaximumlength = (uint32_t)-1;
190         ZERO_STRUCT(dbsync.in.return_authenticator);
191
192         for (i=0;i< ARRAY_SIZE(database_ids); i++) { 
193                 dbsync.in.sync_context = 0;
194                 dbsync.in.database_id = database_ids[i]; 
195                 
196                 do {
197                         int d;
198                         loop_ctx = talloc_named(mem_ctx, 0, "DatabaseSync loop context");
199                         creds_client_authenticator(creds, &dbsync.in.credential);
200                         
201                         dbsync_nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync);
202                         if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
203                             !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
204                                 r->netlogon.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
205                                 return nt_status;
206                         }
207                         
208                         if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
209                                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Credential chaining failed");
210                                 return NT_STATUS_ACCESS_DENIED;
211                         }
212                         
213                         dbsync.in.sync_context = dbsync.out.sync_context;
214                         
215                         for (d=0; d < dbsync.out.delta_enum_array->num_deltas; d++) {
216                                 char *error_string = NULL;
217                                 delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
218                                 nt_status = r->netlogon.delta_fn(delta_ctx, 
219                                                                  r->netlogon.fn_ctx,
220                                                                  creds,
221                                                                  dbsync.in.database_id,
222                                                                  &dbsync.out.delta_enum_array->delta_enum[d], 
223                                                                  &error_string);
224                                 if (!NT_STATUS_IS_OK(nt_status)) {
225                                         r->netlogon.error_string = talloc_steal(mem_ctx, error_string);
226                                         talloc_free(delta_ctx);
227                                         return nt_status;
228                                 }
229                                 talloc_free(delta_ctx);
230                         }
231                         talloc_free(loop_ctx);
232                 } while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
233                 nt_status = dbsync_nt_status;
234         }
235         return nt_status;
236 }
237
238 NTSTATUS libnet_SamDump_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
239 {
240         NTSTATUS nt_status;
241         union libnet_SamSync r2;
242
243         r2.netlogon.level = LIBNET_SAMDUMP_NETLOGON;
244         r2.netlogon.error_string = NULL;
245         r2.netlogon.delta_fn = libnet_samdump_fn;
246         r2.netlogon.fn_ctx = NULL;
247         nt_status = libnet_SamSync_netlogon(ctx, mem_ctx, &r2);
248         r->generic.error_string = r2.netlogon.error_string;
249
250         
251         return nt_status;
252 }
253
254
255
256 NTSTATUS libnet_SamDump_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
257 {
258         NTSTATUS nt_status;
259         union libnet_SamDump r2;
260
261         r2.generic.level = LIBNET_SAMDUMP_NETLOGON;
262         r2.generic.error_string = NULL;
263         nt_status = libnet_SamDump(ctx, mem_ctx, &r2);
264         r->generic.error_string = r2.netlogon.error_string;
265
266         
267         return nt_status;
268 }
269
270 NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
271 {
272         switch (r->generic.level) {
273         case LIBNET_SAMDUMP_GENERIC:
274                 return libnet_SamDump_generic(ctx, mem_ctx, r);
275         case LIBNET_SAMDUMP_NETLOGON:
276                 return libnet_SamDump_netlogon(ctx, mem_ctx, r);
277         }
278
279         return NT_STATUS_INVALID_LEVEL;
280 }