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.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
;
47 if (user
->lm_password_present
) {
48 sam_pwd_hash(rid
, user
->lmpassword
.hash
, lm_hash
.hash
, 0);
49 user
->lmpassword
= lm_hash
;
52 if (user
->nt_password_present
) {
53 sam_pwd_hash(rid
, user
->ntpassword
.hash
, nt_hash
.hash
, 0);
54 user
->ntpassword
= nt_hash
;
58 if (user
->user_private_info
.SensitiveData
) {
60 struct netr_USER_KEYS keys
;
61 enum ndr_err_code ndr_err
;
62 data
.data
= user
->user_private_info
.SensitiveData
;
63 data
.length
= user
->user_private_info
.DataLength
;
64 SamOEMhashBlob(data
.data
, data
.length
, session_key
);
65 user
->user_private_info
.SensitiveData
= data
.data
;
66 user
->user_private_info
.DataLength
= data
.length
;
68 ndr_err
= ndr_pull_struct_blob(&data
, mem_ctx
, &keys
,
69 (ndr_pull_flags_fn_t
)ndr_pull_netr_USER_KEYS
);
70 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
71 dump_data(10, data
.data
, data
.length
);
72 return ndr_map_error2ntstatus(ndr_err
);
75 if (keys
.keys
.keys2
.lmpassword
.length
== 16) {
78 keys
.keys
.keys2
.lmpassword
.pwd
.hash
,
80 user
->lmpassword
= lm_hash
;
82 user
->lmpassword
= keys
.keys
.keys2
.lmpassword
.pwd
;
84 user
->lm_password_present
= true;
86 if (keys
.keys
.keys2
.ntpassword
.length
== 16) {
89 keys
.keys
.keys2
.ntpassword
.pwd
.hash
,
91 user
->ntpassword
= nt_hash
;
93 user
->ntpassword
= keys
.keys
.keys2
.ntpassword
.pwd
;
95 user
->nt_password_present
= true;
97 /* TODO: rid decrypt history fields */
103 * Decrypt and extract the secrets
105 * The writes decrypted secrets back into the structure
107 static NTSTATUS
fix_secret(TALLOC_CTX
*mem_ctx
,
108 DATA_BLOB
*session_key
,
109 enum netr_SamDatabaseID database_id
,
110 struct netr_DELTA_ENUM
*delta
)
112 struct netr_DELTA_SECRET
*secret
= delta
->delta_union
.secret
;
114 SamOEMhashBlob(secret
->current_cipher
.cipher_data
,
115 secret
->current_cipher
.maxlen
,
118 SamOEMhashBlob(secret
->old_cipher
.cipher_data
,
119 secret
->old_cipher
.maxlen
,
126 * Fix up the delta, dealing with encryption issues so that the final
127 * callback need only do the printing or application logic
130 static NTSTATUS
samsync_fix_delta(TALLOC_CTX
*mem_ctx
,
131 DATA_BLOB
*session_key
,
133 enum netr_SamDatabaseID database_id
,
134 struct netr_DELTA_ENUM
*delta
)
136 NTSTATUS status
= NT_STATUS_OK
;
138 switch (delta
->delta_type
) {
139 case NETR_DELTA_USER
:
141 status
= fix_user(mem_ctx
,
147 case NETR_DELTA_SECRET
:
149 status
= fix_secret(mem_ctx
,
162 * Fix up the delta, dealing with encryption issues so that the final
163 * callback need only do the printing or application logic
166 static NTSTATUS
samsync_fix_delta_array(TALLOC_CTX
*mem_ctx
,
167 DATA_BLOB
*session_key
,
169 enum netr_SamDatabaseID database_id
,
170 struct netr_DELTA_ENUM_ARRAY
*r
)
175 for (i
= 0; i
< r
->num_deltas
; i
++) {
177 status
= samsync_fix_delta(mem_ctx
,
182 if (!NT_STATUS_IS_OK(status
)) {
191 * libnet_samsync_init_context
194 NTSTATUS
libnet_samsync_init_context(TALLOC_CTX
*mem_ctx
,
195 const struct dom_sid
*domain_sid
,
196 struct samsync_context
**ctx_p
)
198 struct samsync_context
*ctx
;
202 ctx
= TALLOC_ZERO_P(mem_ctx
, struct samsync_context
);
203 NT_STATUS_HAVE_NO_MEMORY(ctx
);
206 ctx
->domain_sid
= sid_dup_talloc(mem_ctx
, domain_sid
);
207 NT_STATUS_HAVE_NO_MEMORY(ctx
->domain_sid
);
209 ctx
->domain_sid_str
= sid_string_talloc(mem_ctx
, ctx
->domain_sid
);
210 NT_STATUS_HAVE_NO_MEMORY(ctx
->domain_sid_str
);
219 * samsync_database_str
222 static const char *samsync_database_str(enum netr_SamDatabaseID database_id
)
225 switch (database_id
) {
226 case SAM_DATABASE_DOMAIN
:
228 case SAM_DATABASE_BUILTIN
:
230 case SAM_DATABASE_PRIVS
:
241 static const char *samsync_debug_str(TALLOC_CTX
*mem_ctx
,
242 enum net_samsync_mode mode
,
243 enum netr_SamDatabaseID database_id
)
245 const char *action
= NULL
;
248 case NET_SAMSYNC_MODE_DUMP
:
249 action
= "Dumping (to stdout)";
251 case NET_SAMSYNC_MODE_FETCH_PASSDB
:
252 action
= "Fetching (to passdb)";
254 case NET_SAMSYNC_MODE_FETCH_LDIF
:
255 action
= "Fetching (to ldif)";
257 case NET_SAMSYNC_MODE_FETCH_KEYTAB
:
258 action
= "Fetching (to keytab)";
265 return talloc_asprintf(mem_ctx
, "%s %s database",
266 action
, samsync_database_str(database_id
));
273 NTSTATUS
libnet_samsync(enum netr_SamDatabaseID database_id
,
274 struct samsync_context
*ctx
)
278 const char *logon_server
= ctx
->cli
->desthost
;
279 const char *computername
= global_myname();
280 struct netr_Authenticator credential
;
281 struct netr_Authenticator return_authenticator
;
282 uint16_t restart_state
= 0;
283 uint32_t sync_context
= 0;
284 const char *debug_str
;
285 DATA_BLOB session_key
;
287 ZERO_STRUCT(return_authenticator
);
289 if (!(mem_ctx
= talloc_init("libnet_samsync"))) {
290 return NT_STATUS_NO_MEMORY
;
293 debug_str
= samsync_debug_str(mem_ctx
, ctx
->mode
, database_id
);
295 d_fprintf(stderr
, "%s\n", debug_str
);
299 struct netr_DELTA_ENUM_ARRAY
*delta_enum_array
= NULL
;
300 NTSTATUS callback_status
;
302 netlogon_creds_client_step(ctx
->cli
->dc
, &credential
);
304 result
= rpccli_netr_DatabaseSync2(ctx
->cli
, mem_ctx
,
308 &return_authenticator
,
314 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
)) {
318 /* Check returned credentials. */
319 if (!netlogon_creds_client_check(ctx
->cli
->dc
,
320 &return_authenticator
.cred
)) {
321 DEBUG(0,("credentials chain check failed\n"));
322 return NT_STATUS_ACCESS_DENIED
;
325 if (NT_STATUS_IS_ERR(result
)) {
329 session_key
= data_blob_const(ctx
->cli
->dc
->sess_key
, 16);
331 samsync_fix_delta_array(mem_ctx
,
337 /* Process results */
338 callback_status
= ctx
->delta_fn(mem_ctx
, database_id
,
340 NT_STATUS_IS_OK(result
), ctx
);
341 if (!NT_STATUS_IS_OK(callback_status
)) {
342 result
= callback_status
;
346 TALLOC_FREE(delta_enum_array
);
348 /* Increment sync_context */
351 } while (NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
354 if (NT_STATUS_IS_ERR(result
) && !ctx
->error_message
) {
356 ctx
->error_message
= talloc_asprintf(ctx
,
357 "Failed to fetch %s database: %s",
358 samsync_database_str(database_id
),
361 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
)) {
364 talloc_asprintf_append(ctx
->error_message
,
365 "\nPerhaps %s is a Windows native mode domain?",
370 talloc_destroy(mem_ctx
);
376 * pull_netr_AcctLockStr
379 NTSTATUS
pull_netr_AcctLockStr(TALLOC_CTX
*mem_ctx
,
380 struct lsa_BinaryString
*r
,
381 struct netr_AcctLockStr
**str_p
)
383 struct netr_AcctLockStr
*str
;
384 enum ndr_err_code ndr_err
;
387 if (!mem_ctx
|| !r
|| !str_p
) {
388 return NT_STATUS_INVALID_PARAMETER
;
393 str
= TALLOC_ZERO_P(mem_ctx
, struct netr_AcctLockStr
);
395 return NT_STATUS_NO_MEMORY
;
398 blob
= data_blob_const(r
->array
, r
->length
);
400 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, str
,
401 (ndr_pull_flags_fn_t
)ndr_pull_netr_AcctLockStr
);
403 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
404 return ndr_map_error2ntstatus(ndr_err
);