netlogon: refactor just_change_the_password a bit.
[Samba.git] / source / libsmb / trusts_util.c
blob7897d5171784c8ce7e671b1f413f5a4a79af87c6
1 /*
2 * Unix SMB/CIFS implementation.
3 * Routines to operate on various trust relationships
4 * Copyright (C) Andrew Bartlett 2001
5 * Copyright (C) Rafal Szczesniak 2003
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
23 /*********************************************************
24 Change the domain password on the PDC.
26 Just changes the password betwen the two values specified.
28 Caller must have the cli connected to the netlogon pipe
29 already.
30 **********************************************************/
32 static NTSTATUS just_change_the_password(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
33 const unsigned char orig_trust_passwd_hash[16],
34 const char *new_trust_pwd_cleartext,
35 const unsigned char new_trust_passwd_hash[16],
36 uint32 sec_channel_type)
38 NTSTATUS result;
39 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
40 struct netr_Authenticator clnt_creds, srv_cred;
42 result = rpccli_netlogon_setup_creds(cli,
43 cli->desthost, /* server name */
44 lp_workgroup(), /* domain */
45 global_myname(), /* client name */
46 global_myname(), /* machine account name */
47 orig_trust_passwd_hash,
48 sec_channel_type,
49 &neg_flags);
51 if (!NT_STATUS_IS_OK(result)) {
52 DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n",
53 nt_errstr(result)));
54 return result;
57 netlogon_creds_client_step(cli->dc, &clnt_creds);
59 if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
61 struct netr_CryptPassword new_password;
63 init_netr_CryptPassword(new_trust_pwd_cleartext,
64 cli->dc->sess_key,
65 &new_password);
67 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
68 cli->dc->remote_machine,
69 cli->dc->mach_acct,
70 sec_channel_type,
71 global_myname(),
72 &clnt_creds,
73 &srv_cred,
74 &new_password);
75 if (!NT_STATUS_IS_OK(result)) {
76 DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
77 nt_errstr(result)));
78 return result;
80 } else {
82 struct samr_Password new_password;
84 cred_hash3(new_password.hash,
85 new_trust_passwd_hash,
86 cli->dc->sess_key, 1);
88 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
89 cli->dc->remote_machine,
90 cli->dc->mach_acct,
91 sec_channel_type,
92 global_myname(),
93 &clnt_creds,
94 &srv_cred,
95 &new_password);
96 if (!NT_STATUS_IS_OK(result)) {
97 DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
98 nt_errstr(result)));
99 return result;
103 /* Always check returned credentials. */
104 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
105 DEBUG(0,("credentials chain check failed\n"));
106 return NT_STATUS_ACCESS_DENIED;
109 return result;
112 /*********************************************************
113 Change the domain password on the PDC.
114 Store the password ourselves, but use the supplied password
115 Caller must have already setup the connection to the NETLOGON pipe
116 **********************************************************/
118 NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
119 const char *domain,
120 unsigned char orig_trust_passwd_hash[16],
121 uint32 sec_channel_type)
123 unsigned char new_trust_passwd_hash[16];
124 char *new_trust_passwd;
125 char *str;
126 NTSTATUS nt_status;
128 /* Create a random machine account password */
129 str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
131 if ((new_trust_passwd = talloc_strdup(mem_ctx, str)) == NULL) {
132 DEBUG(0, ("talloc_strdup failed\n"));
133 return NT_STATUS_NO_MEMORY;
136 E_md4hash(new_trust_passwd, new_trust_passwd_hash);
138 nt_status = just_change_the_password(cli, mem_ctx,
139 orig_trust_passwd_hash,
140 new_trust_passwd,
141 new_trust_passwd_hash,
142 sec_channel_type);
144 if (NT_STATUS_IS_OK(nt_status)) {
145 DEBUG(3,("%s : trust_pw_change_and_store_it: Changed password.\n",
146 current_timestring(debug_ctx(), False)));
148 * Return the result of trying to write the new password
149 * back into the trust account file.
151 if (!secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type)) {
152 nt_status = NT_STATUS_UNSUCCESSFUL;
156 return nt_status;
159 /*********************************************************
160 Change the domain password on the PDC.
161 Do most of the legwork ourselfs. Caller must have
162 already setup the connection to the NETLOGON pipe
163 **********************************************************/
165 NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli,
166 TALLOC_CTX *mem_ctx,
167 const char *domain)
169 unsigned char old_trust_passwd_hash[16];
170 uint32 sec_channel_type = 0;
172 if (!secrets_fetch_trust_account_password(domain,
173 old_trust_passwd_hash,
174 NULL, &sec_channel_type)) {
175 DEBUG(0, ("could not fetch domain secrets for domain %s!\n", domain));
176 return NT_STATUS_UNSUCCESSFUL;
179 return trust_pw_change_and_store_it(cli, mem_ctx, domain,
180 old_trust_passwd_hash,
181 sec_channel_type);
184 /*********************************************************************
185 Enumerate the list of trusted domains from a DC
186 *********************************************************************/
188 bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
189 char ***domain_names, uint32 *num_domains,
190 DOM_SID **sids )
192 POLICY_HND pol;
193 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
194 fstring dc_name;
195 struct sockaddr_storage dc_ss;
196 uint32 enum_ctx = 0;
197 struct cli_state *cli = NULL;
198 struct rpc_pipe_client *lsa_pipe;
199 bool retry;
200 struct lsa_DomainList dom_list;
201 int i;
203 *domain_names = NULL;
204 *num_domains = 0;
205 *sids = NULL;
207 /* lookup a DC first */
209 if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) {
210 DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n",
211 domain));
212 return False;
215 /* setup the anonymous connection */
217 result = cli_full_connection( &cli, global_myname(), dc_name, &dc_ss, 0, "IPC$", "IPC",
218 "", "", "", 0, Undefined, &retry);
219 if ( !NT_STATUS_IS_OK(result) )
220 goto done;
222 /* open the LSARPC_PIPE */
224 result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
225 &lsa_pipe);
226 if (!NT_STATUS_IS_OK(result)) {
227 goto done;
230 /* get a handle */
232 result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True,
233 LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol);
234 if ( !NT_STATUS_IS_OK(result) )
235 goto done;
237 /* Lookup list of trusted domains */
239 result = rpccli_lsa_EnumTrustDom(lsa_pipe, mem_ctx,
240 &pol,
241 &enum_ctx,
242 &dom_list,
243 (uint32_t)-1);
244 if ( !NT_STATUS_IS_OK(result) )
245 goto done;
247 *num_domains = dom_list.count;
249 *domain_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_domains);
250 if (!*domain_names) {
251 result = NT_STATUS_NO_MEMORY;
252 goto done;
255 *sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_domains);
256 if (!*sids) {
257 result = NT_STATUS_NO_MEMORY;
258 goto done;
261 for (i=0; i< *num_domains; i++) {
262 (*domain_names)[i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
263 (*sids)[i] = *dom_list.domains[i].sid;
266 done:
267 /* cleanup */
268 if (cli) {
269 DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n"));
270 cli_shutdown( cli );
273 return NT_STATUS_IS_OK(result);