r6573: Start on my project to implement an NT4 compatible BDC in Samba4.
[samba.git] / source / 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 BOOL 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         if (user->nt_password_present) {
48                 sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
49                 nt_hash_p = &nt_hash;
50         }
51
52         if (user->user_private_info.SensitiveData) {
53                 DATA_BLOB data;
54                 struct netr_USER_KEYS keys;
55                 data.data = user->user_private_info.SensitiveData;
56                 data.length = user->user_private_info.DataLength;
57                 creds_arcfour_crypt(creds, data.data, data.length);
58                 nt_status = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
59                 if (NT_STATUS_IS_OK(nt_status)) {
60                         if (keys.keys.keys2.lmpassword.length == 16) {
61                                 sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0);
62                                 lm_hash_p = &lm_hash;
63                         }
64                         if (keys.keys.keys2.ntpassword.length == 16) {
65                                 sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
66                                 nt_hash_p = &nt_hash;
67                         }
68                 } else {
69                         printf("Failed to parse Sensitive Data for %s:\n", username);
70                         dump_data(10, data.data, data.length);
71                         return False;
72                 }
73         }
74
75         hex_lm_password = smbpasswd_sethexpwd(mem_ctx, lm_hash_p, user->acct_flags);
76         hex_nt_password = smbpasswd_sethexpwd(mem_ctx, nt_hash_p, user->acct_flags);
77
78         printf("%s:%d:%s:%s:%s:LCT-%08X\n", username,
79                rid, hex_lm_password, hex_nt_password,
80                smbpasswd_encode_acb_info(mem_ctx, user->acct_flags),
81                (unsigned int)nt_time_to_unix(user->last_password_change));
82
83         return True;
84 }
85
86
87
88 static NTSTATUS libnet_SamDump_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
89 {
90         NTSTATUS nt_status;
91         TALLOC_CTX *loop_ctx, *delta_ctx;
92         struct creds_CredentialState *creds;
93         struct netr_DatabaseSync dbsync;
94         struct cli_credentials *machine_account;
95         struct dcerpc_binding *b;
96         struct dcerpc_pipe *p;
97
98         /* TODO: This is bogus */
99         const char **bindings = lp_passwordserver();
100         const char *binding;
101
102         if (bindings && bindings[0]) {
103                 binding = bindings[0];
104         }
105
106         machine_account = cli_credentials_init(mem_ctx);
107         if (!machine_account) {
108                 return NT_STATUS_NO_MEMORY;
109         }
110
111         cli_credentials_set_conf(machine_account);
112         nt_status = cli_credentials_set_machine_account(machine_account);
113         
114         if (!NT_STATUS_IS_OK(nt_status)) {
115                 r->netlogon.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
116                 return nt_status;
117         }
118         
119         if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
120                 r->netlogon.error_string
121                         = talloc_asprintf(mem_ctx, 
122                                           "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
123                                           cli_credentials_get_secure_channel_type(machine_account),
124                                           cli_credentials_get_domain(machine_account));
125                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
126         }
127
128         /* Connect to DC (take a binding string for now) */
129
130         nt_status = dcerpc_parse_binding(mem_ctx, binding, &b);
131         if (!NT_STATUS_IS_OK(nt_status)) {
132                 r->netlogon.error_string = talloc_asprintf(mem_ctx, "Bad binding string %s\n", binding);
133                 return NT_STATUS_INVALID_PARAMETER;
134         }
135
136         /* We like schannel */
137         b->flags &= ~DCERPC_AUTH_OPTIONS;
138         b->flags |= DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128;
139
140         /* Setup schannel */
141         nt_status = dcerpc_pipe_connect_b(mem_ctx, &p, b, 
142                                           DCERPC_NETLOGON_UUID,
143                                           DCERPC_NETLOGON_VERSION,
144                                           machine_account);
145
146         if (!NT_STATUS_IS_OK(nt_status)) {
147                 return nt_status;
148         }
149
150         /* call domain logon */
151
152         nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
153         if (!NT_STATUS_IS_OK(nt_status)) {
154                 return nt_status;
155         }
156
157         dbsync.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
158         dbsync.in.computername = cli_credentials_get_workstation(machine_account);
159         dbsync.in.preferredmaximumlength = (uint32_t)-1;
160         ZERO_STRUCT(dbsync.in.return_authenticator);
161
162         dbsync.in.sync_context = 0;
163         dbsync.in.database_id = SAM_DATABASE_DOMAIN;
164
165         do {
166                 int d;
167                 loop_ctx = talloc_named(mem_ctx, 0, "DatabaseSync loop context");
168                 creds_client_authenticator(creds, &dbsync.in.credential);
169                 
170                 nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync);
171                 if (!NT_STATUS_IS_OK(nt_status) &&
172                     !NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES)) {
173                         printf("DatabaseSync - %s\n", nt_errstr(nt_status));
174                         return nt_status;
175                 }
176                 
177                 if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
178                         printf("Credential chaining failed\n");
179                 }
180                 
181                 dbsync.in.sync_context = dbsync.out.sync_context;
182                 
183                 for (d=0; d < dbsync.out.delta_enum_array->num_deltas; d++) {
184                         delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
185                         switch (dbsync.out.delta_enum_array->delta_enum[d].delta_type) {
186                         case NETR_DELTA_USER:
187                                 if (!vampire_samdump_handle_user(delta_ctx, 
188                                                                  creds,
189                                                                  &dbsync.out.delta_enum_array->delta_enum[d])) {
190                                         return NT_STATUS_INVALID_PARAMETER;
191                                 }
192                                 break;
193                         }
194                         talloc_free(delta_ctx);
195                 }
196                 talloc_free(loop_ctx);
197         } while (NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES));
198         return NT_STATUS_OK;
199 }
200
201 NTSTATUS libnet_SamDump_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
202 {
203         NTSTATUS nt_status;
204         union libnet_SamDump r2;
205
206         r2.generic.level = LIBNET_SAMDUMP_NETLOGON;
207         r2.generic.error_string = NULL;
208         nt_status = libnet_SamDump(ctx, mem_ctx, &r2);
209         r->generic.error_string = r2.netlogon.error_string;
210
211         
212         return nt_status;
213 }
214
215 NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
216 {
217         switch (r->generic.level) {
218         case LIBNET_SAMDUMP_GENERIC:
219                 return libnet_SamDump_generic(ctx, mem_ctx, r);
220         case LIBNET_SAMDUMP_NETLOGON:
221                 return libnet_SamDump_netlogon(ctx, mem_ctx, r);
222         }
223
224         return NT_STATUS_INVALID_LEVEL;
225 }