2 Unix SMB/CIFS implementation.
4 Extract the user/system database from a remote SamSync server
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7 Copyright (C) Guenther Deschner <gd@samba.org> 2008
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.
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.
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/>.
25 #include "libnet/libnet_samsync.h"
28 * Decrypt and extract the user's passwords.
30 * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted)
31 * passwords back into the structure
34 static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
35 DATA_BLOB *session_key,
37 enum netr_SamDatabaseID database_id,
38 struct netr_DELTA_ENUM *delta)
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;
48 if (user->lm_password_present) {
49 sam_pwd_hash(rid, user->lmpassword.hash, lm_hash.hash, 0);
50 user->lmpassword = lm_hash;
53 if (user->nt_password_present) {
54 sam_pwd_hash(rid, user->ntpassword.hash, nt_hash.hash, 0);
55 user->ntpassword = nt_hash;
59 if (user->user_private_info.SensitiveData) {
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;
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);
76 if (keys.keys.keys2.lmpassword.length == 16) {
79 keys.keys.keys2.lmpassword.pwd.hash,
81 user->lmpassword = lm_hash;
83 user->lmpassword = keys.keys.keys2.lmpassword.pwd;
85 user->lm_password_present = true;
87 if (keys.keys.keys2.ntpassword.length == 16) {
90 keys.keys.keys2.ntpassword.pwd.hash,
92 user->ntpassword = nt_hash;
94 user->ntpassword = keys.keys.keys2.ntpassword.pwd;
96 user->nt_password_present = true;
98 /* TODO: rid decrypt history fields */
104 * Decrypt and extract the secrets
106 * The writes decrypted secrets back into the structure
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)
113 struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
115 SamOEMhashBlob(secret->current_cipher.cipher_data,
116 secret->current_cipher.maxlen,
119 SamOEMhashBlob(secret->old_cipher.cipher_data,
120 secret->old_cipher.maxlen,
127 * Fix up the delta, dealing with encryption issues so that the final
128 * callback need only do the printing or application logic
131 static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
132 DATA_BLOB *session_key,
134 enum netr_SamDatabaseID database_id,
135 struct netr_DELTA_ENUM *delta)
137 NTSTATUS status = NT_STATUS_OK;
139 switch (delta->delta_type) {
140 case NETR_DELTA_USER:
142 status = fix_user(mem_ctx,
148 case NETR_DELTA_SECRET:
150 status = fix_secret(mem_ctx,
163 * Fix up the delta, dealing with encryption issues so that the final
164 * callback need only do the printing or application logic
167 NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
168 DATA_BLOB *session_key,
170 enum netr_SamDatabaseID database_id,
171 struct netr_DELTA_ENUM_ARRAY *r)
176 for (i = 0; i < r->num_deltas; i++) {
178 status = samsync_fix_delta(mem_ctx,
183 if (!NT_STATUS_IS_OK(status)) {
192 * samsync_init_context
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)
200 struct samsync_context *ctx;
204 ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
205 NT_STATUS_HAVE_NO_MEMORY(ctx);
210 ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
211 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
213 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
214 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
226 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
227 enum net_samsync_mode mode,
228 enum netr_SamDatabaseID database_id)
230 const char *action = NULL;
231 const char *str = NULL;
234 case NET_SAMSYNC_MODE_DUMP:
235 action = "Dumping (to stdout)";
237 case NET_SAMSYNC_MODE_FETCH_PASSDB:
238 action = "Fetching (to passdb)";
240 case NET_SAMSYNC_MODE_FETCH_LDIF:
241 action = "Fetching (to ldif)";
248 switch (database_id) {
249 case SAM_DATABASE_DOMAIN:
250 str = talloc_asprintf(mem_ctx, "%s DOMAIN database",
253 case SAM_DATABASE_BUILTIN:
254 str = talloc_asprintf(mem_ctx, "%s BUILTIN database",
257 case SAM_DATABASE_PRIVS:
258 str = talloc_asprintf(mem_ctx, "%s PRIVS database",
262 str = talloc_asprintf(mem_ctx, "%s unknown database type %u",
263 action, database_id);
271 * samsync_process_database
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)
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;
290 ZERO_STRUCT(return_authenticator);
292 if (!(mem_ctx = talloc_init("samsync_process_database"))) {
293 return NT_STATUS_NO_MEMORY;
296 debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
298 d_fprintf(stderr, "%s\n", debug_str);
302 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
304 netlogon_creds_client_step(pipe_hnd->dc, &credential);
306 result = rpccli_netr_DatabaseSync2(pipe_hnd, mem_ctx,
310 &return_authenticator,
316 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
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;
327 if (NT_STATUS_IS_ERR(result)) {
331 session_key = data_blob_const(pipe_hnd->dc->sess_key, 16);
333 samsync_fix_delta_array(mem_ctx,
339 /* Process results */
340 callback_fn(mem_ctx, database_id, delta_enum_array, result, ctx);
342 TALLOC_FREE(delta_enum_array);
344 /* Increment sync_context */
347 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
349 talloc_destroy(mem_ctx);