2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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.
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.
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.
23 #include "libnet/libnet.h"
24 #include "librpc/gen_ndr/ndr_netlogon.h"
25 #include "librpc/gen_ndr/ndr_samr.h"
27 static BOOL vampire_samdump_handle_user(TALLOC_CTX *mem_ctx,
28 struct creds_CredentialState *creds,
29 struct netr_DELTA_ENUM *delta)
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;
43 if (user->lm_password_present) {
44 sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
47 if (user->nt_password_present) {
48 sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
52 if (user->user_private_info.SensitiveData) {
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);
64 if (keys.keys.keys2.ntpassword.length == 16) {
65 sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
69 printf("Failed to parse Sensitive Data for %s:\n", username);
70 dump_data(10, data.data, data.length);
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);
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));
88 static NTSTATUS libnet_SamDump_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
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;
98 /* TODO: This is bogus */
99 const char **bindings = lp_passwordserver();
102 if (bindings && bindings[0]) {
103 binding = bindings[0];
106 machine_account = cli_credentials_init(mem_ctx);
107 if (!machine_account) {
108 return NT_STATUS_NO_MEMORY;
111 cli_credentials_set_conf(machine_account);
112 nt_status = cli_credentials_set_machine_account(machine_account);
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?");
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;
128 /* Connect to DC (take a binding string for now) */
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;
136 /* We like schannel */
137 b->flags &= ~DCERPC_AUTH_OPTIONS;
138 b->flags |= DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128;
141 nt_status = dcerpc_pipe_connect_b(mem_ctx, &p, b,
142 DCERPC_NETLOGON_UUID,
143 DCERPC_NETLOGON_VERSION,
146 if (!NT_STATUS_IS_OK(nt_status)) {
150 /* call domain logon */
152 nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
153 if (!NT_STATUS_IS_OK(nt_status)) {
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);
162 dbsync.in.sync_context = 0;
163 dbsync.in.database_id = SAM_DATABASE_DOMAIN;
167 loop_ctx = talloc_named(mem_ctx, 0, "DatabaseSync loop context");
168 creds_client_authenticator(creds, &dbsync.in.credential);
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));
177 if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
178 printf("Credential chaining failed\n");
181 dbsync.in.sync_context = dbsync.out.sync_context;
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,
189 &dbsync.out.delta_enum_array->delta_enum[d])) {
190 return NT_STATUS_INVALID_PARAMETER;
194 talloc_free(delta_ctx);
196 talloc_free(loop_ctx);
197 } while (NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES));
201 NTSTATUS libnet_SamDump_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
204 union libnet_SamDump r2;
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;
215 NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SamDump *r)
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);
224 return NT_STATUS_INVALID_LEVEL;