net_vampire: move some samsync functions to libnet.
[nivanova/samba-autobuild/.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_samsync.h"
26
27 /**
28  * Decrypt and extract the user's passwords.
29  *
30  * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted)
31  * passwords back into the structure
32  */
33
34 static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
35                          DATA_BLOB *session_key,
36                          bool rid_crypt,
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         const char *username = user->account_name.string;
46
47         if (rid_crypt) {
48                 if (user->lm_password_present) {
49                         sam_pwd_hash(rid, user->lmpassword.hash, lm_hash.hash, 0);
50                         user->lmpassword = lm_hash;
51                 }
52
53                 if (user->nt_password_present) {
54                         sam_pwd_hash(rid, user->ntpassword.hash, nt_hash.hash, 0);
55                         user->ntpassword = nt_hash;
56                 }
57         }
58
59         if (user->user_private_info.SensitiveData) {
60                 DATA_BLOB data;
61                 struct netr_USER_KEYS keys;
62                 enum ndr_err_code ndr_err;
63                 data.data = user->user_private_info.SensitiveData;
64                 data.length = user->user_private_info.DataLength;
65                 SamOEMhashBlob(data.data, data.length, session_key);
66                 user->user_private_info.SensitiveData = data.data;
67                 user->user_private_info.DataLength = data.length;
68
69                 ndr_err = ndr_pull_struct_blob(&data, mem_ctx, &keys,
70                         (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
71                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
72                         dump_data(10, data.data, data.length);
73                         return ndr_map_error2ntstatus(ndr_err);
74                 }
75
76                 if (keys.keys.keys2.lmpassword.length == 16) {
77                         if (rid_crypt) {
78                                 sam_pwd_hash(rid,
79                                              keys.keys.keys2.lmpassword.pwd.hash,
80                                              lm_hash.hash, 0);
81                                 user->lmpassword = lm_hash;
82                         } else {
83                                 user->lmpassword = keys.keys.keys2.lmpassword.pwd;
84                         }
85                         user->lm_password_present = true;
86                 }
87                 if (keys.keys.keys2.ntpassword.length == 16) {
88                         if (rid_crypt) {
89                                 sam_pwd_hash(rid,
90                                              keys.keys.keys2.ntpassword.pwd.hash,
91                                              nt_hash.hash, 0);
92                                 user->ntpassword = nt_hash;
93                         } else {
94                                 user->ntpassword = keys.keys.keys2.ntpassword.pwd;
95                         }
96                         user->nt_password_present = true;
97                 }
98                 /* TODO: rid decrypt history fields */
99         }
100         return NT_STATUS_OK;
101 }
102
103 /**
104  * Decrypt and extract the secrets
105  *
106  * The writes decrypted secrets back into the structure
107  */
108 static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
109                            DATA_BLOB *session_key,
110                            enum netr_SamDatabaseID database_id,
111                            struct netr_DELTA_ENUM *delta)
112 {
113         struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
114
115         SamOEMhashBlob(secret->current_cipher.cipher_data,
116                        secret->current_cipher.maxlen,
117                        session_key);
118
119         SamOEMhashBlob(secret->old_cipher.cipher_data,
120                        secret->old_cipher.maxlen,
121                        session_key);
122
123         return NT_STATUS_OK;
124 }
125
126 /**
127  * Fix up the delta, dealing with encryption issues so that the final
128  * callback need only do the printing or application logic
129  */
130
131 static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
132                                   DATA_BLOB *session_key,
133                                   bool rid_crypt,
134                                   enum netr_SamDatabaseID database_id,
135                                   struct netr_DELTA_ENUM *delta)
136 {
137         NTSTATUS status = NT_STATUS_OK;
138
139         switch (delta->delta_type) {
140                 case NETR_DELTA_USER:
141
142                         status = fix_user(mem_ctx,
143                                           session_key,
144                                           rid_crypt,
145                                           database_id,
146                                           delta);
147                         break;
148                 case NETR_DELTA_SECRET:
149
150                         status = fix_secret(mem_ctx,
151                                             session_key,
152                                             database_id,
153                                             delta);
154                         break;
155                 default:
156                         break;
157         }
158
159         return status;
160 }
161
162 /**
163  * Fix up the delta, dealing with encryption issues so that the final
164  * callback need only do the printing or application logic
165  */
166
167 NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
168                                  DATA_BLOB *session_key,
169                                  bool rid_crypt,
170                                  enum netr_SamDatabaseID database_id,
171                                  struct netr_DELTA_ENUM_ARRAY *r)
172 {
173         NTSTATUS status;
174         int i;
175
176         for (i = 0; i < r->num_deltas; i++) {
177
178                 status = samsync_fix_delta(mem_ctx,
179                                            session_key,
180                                            rid_crypt,
181                                            database_id,
182                                            &r->delta_enum[i]);
183                 if (!NT_STATUS_IS_OK(status)) {
184                         return status;
185                 }
186         }
187
188         return NT_STATUS_OK;
189 }
190
191 /**
192  * samsync_init_context
193  */
194
195 NTSTATUS samsync_init_context(TALLOC_CTX *mem_ctx,
196                               const struct dom_sid *domain_sid,
197                               enum net_samsync_mode mode,
198                               struct samsync_context **ctx_p)
199 {
200         struct samsync_context *ctx;
201
202         *ctx_p = NULL;
203
204         ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
205         NT_STATUS_HAVE_NO_MEMORY(ctx);
206
207         ctx->mode = mode;
208
209         if (domain_sid) {
210                 ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
211                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
212
213                 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
214                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
215         }
216
217         *ctx_p = ctx;
218
219         return NT_STATUS_OK;
220 }
221
222 /**
223  * samsync_debug_str
224  */
225
226 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
227                                      enum net_samsync_mode mode,
228                                      enum netr_SamDatabaseID database_id)
229 {
230         const char *action = NULL;
231         const char *str = NULL;
232
233         switch (mode) {
234                 case NET_SAMSYNC_MODE_DUMP:
235                         action = "Dumping (to stdout)";
236                         break;
237                 case NET_SAMSYNC_MODE_FETCH_PASSDB:
238                         action = "Fetching (to passdb)";
239                         break;
240                 case NET_SAMSYNC_MODE_FETCH_LDIF:
241                         action = "Fetching (to ldif)";
242                         break;
243                 default:
244                         action = "Unknown";
245                         break;
246         }
247
248         switch (database_id) {
249                 case SAM_DATABASE_DOMAIN:
250                         str = talloc_asprintf(mem_ctx, "%s DOMAIN database",
251                                 action);
252                         break;
253                 case SAM_DATABASE_BUILTIN:
254                         str = talloc_asprintf(mem_ctx, "%s BUILTIN database",
255                                 action);
256                         break;
257                 case SAM_DATABASE_PRIVS:
258                         str = talloc_asprintf(mem_ctx, "%s PRIVS database",
259                                 action);
260                         break;
261                 default:
262                         str = talloc_asprintf(mem_ctx, "%s unknown database type %u",
263                                 action, database_id);
264                         break;
265         }
266
267         return str;
268 }
269
270 /**
271  * samsync_process_database
272  */
273
274 NTSTATUS samsync_process_database(struct rpc_pipe_client *pipe_hnd,
275                                   enum netr_SamDatabaseID database_id,
276                                   samsync_fn_t callback_fn,
277                                   struct samsync_context *ctx)
278 {
279         NTSTATUS result;
280         TALLOC_CTX *mem_ctx;
281         const char *logon_server = pipe_hnd->desthost;
282         const char *computername = global_myname();
283         struct netr_Authenticator credential;
284         struct netr_Authenticator return_authenticator;
285         uint16_t restart_state = 0;
286         uint32_t sync_context = 0;
287         const char *debug_str;
288         DATA_BLOB session_key;
289
290         ZERO_STRUCT(return_authenticator);
291
292         if (!(mem_ctx = talloc_init("samsync_process_database"))) {
293                 return NT_STATUS_NO_MEMORY;
294         }
295
296         debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
297         if (debug_str) {
298                 d_fprintf(stderr, "%s\n", debug_str);
299         }
300
301         do {
302                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
303
304                 netlogon_creds_client_step(pipe_hnd->dc, &credential);
305
306                 result = rpccli_netr_DatabaseSync2(pipe_hnd, mem_ctx,
307                                                    logon_server,
308                                                    computername,
309                                                    &credential,
310                                                    &return_authenticator,
311                                                    database_id,
312                                                    restart_state,
313                                                    &sync_context,
314                                                    &delta_enum_array,
315                                                    0xffff);
316                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
317                         return result;
318                 }
319
320                 /* Check returned credentials. */
321                 if (!netlogon_creds_client_check(pipe_hnd->dc,
322                                                  &return_authenticator.cred)) {
323                         DEBUG(0,("credentials chain check failed\n"));
324                         return NT_STATUS_ACCESS_DENIED;
325                 }
326
327                 if (NT_STATUS_IS_ERR(result)) {
328                         break;
329                 }
330
331                 session_key = data_blob_const(pipe_hnd->dc->sess_key, 16);
332
333                 samsync_fix_delta_array(mem_ctx,
334                                         &session_key,
335                                         true,
336                                         database_id,
337                                         delta_enum_array);
338
339                 /* Process results */
340                 callback_fn(mem_ctx, database_id, delta_enum_array, result, ctx);
341
342                 TALLOC_FREE(delta_enum_array);
343
344                 /* Increment sync_context */
345                 sync_context += 1;
346
347         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
348
349         talloc_destroy(mem_ctx);
350
351         return result;
352 }