krb5-locator: fix dsgetdcname caller.
[Samba.git] / source / libsmb / trusts_util.c
blob08a49930b4d3e7e834fa13b230096671a61ccbe9
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;
41 result = rpccli_netlogon_setup_creds(cli,
42 cli->desthost, /* server name */
43 lp_workgroup(), /* domain */
44 global_myname(), /* client name */
45 global_myname(), /* machine account name */
46 orig_trust_passwd_hash,
47 sec_channel_type,
48 &neg_flags);
50 if (!NT_STATUS_IS_OK(result)) {
51 DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n",
52 nt_errstr(result)));
53 return result;
56 if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
58 struct netr_Authenticator clnt_creds, srv_cred;
59 struct netr_CryptPassword new_password;
60 struct samr_CryptPassword password_buf;
62 netlogon_creds_client_step(cli->dc, &clnt_creds);
64 encode_pw_buffer(password_buf.data, new_trust_pwd_cleartext, STR_UNICODE);
66 SamOEMhash(password_buf.data, cli->dc->sess_key, 516);
67 memcpy(new_password.data, password_buf.data, 512);
68 new_password.length = IVAL(password_buf.data, 512);
70 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
71 cli->dc->remote_machine,
72 cli->dc->mach_acct,
73 sec_channel_type,
74 global_myname(),
75 &clnt_creds,
76 &srv_cred,
77 &new_password);
79 /* Always check returned credentials. */
80 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
81 DEBUG(0,("rpccli_netr_ServerPasswordSet2: "
82 "credentials chain check failed\n"));
83 return NT_STATUS_ACCESS_DENIED;
86 } else {
88 struct netr_Authenticator clnt_creds, srv_cred;
89 struct samr_Password new_password;
91 netlogon_creds_client_step(cli->dc, &clnt_creds);
93 cred_hash3(new_password.hash,
94 new_trust_passwd_hash,
95 cli->dc->sess_key, 1);
97 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
98 cli->dc->remote_machine,
99 cli->dc->mach_acct,
100 sec_channel_type,
101 global_myname(),
102 &clnt_creds,
103 &srv_cred,
104 &new_password);
106 /* Always check returned credentials. */
107 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
108 DEBUG(0,("rpccli_netr_ServerPasswordSet: "
109 "credentials chain check failed\n"));
110 return NT_STATUS_ACCESS_DENIED;
114 if (!NT_STATUS_IS_OK(result)) {
115 DEBUG(0,("just_change_the_password: unable to change password (%s)!\n",
116 nt_errstr(result)));
118 return result;
121 /*********************************************************
122 Change the domain password on the PDC.
123 Store the password ourselves, but use the supplied password
124 Caller must have already setup the connection to the NETLOGON pipe
125 **********************************************************/
127 NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
128 const char *domain,
129 unsigned char orig_trust_passwd_hash[16],
130 uint32 sec_channel_type)
132 unsigned char new_trust_passwd_hash[16];
133 char *new_trust_passwd;
134 char *str;
135 NTSTATUS nt_status;
137 /* Create a random machine account password */
138 str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
140 if ((new_trust_passwd = talloc_strdup(mem_ctx, str)) == NULL) {
141 DEBUG(0, ("talloc_strdup failed\n"));
142 return NT_STATUS_NO_MEMORY;
145 E_md4hash(new_trust_passwd, new_trust_passwd_hash);
147 nt_status = just_change_the_password(cli, mem_ctx,
148 orig_trust_passwd_hash,
149 new_trust_passwd,
150 new_trust_passwd_hash,
151 sec_channel_type);
153 if (NT_STATUS_IS_OK(nt_status)) {
154 DEBUG(3,("%s : trust_pw_change_and_store_it: Changed password.\n",
155 current_timestring(debug_ctx(), False)));
157 * Return the result of trying to write the new password
158 * back into the trust account file.
160 if (!secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type)) {
161 nt_status = NT_STATUS_UNSUCCESSFUL;
165 return nt_status;
168 /*********************************************************
169 Change the domain password on the PDC.
170 Do most of the legwork ourselfs. Caller must have
171 already setup the connection to the NETLOGON pipe
172 **********************************************************/
174 NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli,
175 TALLOC_CTX *mem_ctx,
176 const char *domain)
178 unsigned char old_trust_passwd_hash[16];
179 uint32 sec_channel_type = 0;
181 if (!secrets_fetch_trust_account_password(domain,
182 old_trust_passwd_hash,
183 NULL, &sec_channel_type)) {
184 DEBUG(0, ("could not fetch domain secrets for domain %s!\n", domain));
185 return NT_STATUS_UNSUCCESSFUL;
188 return trust_pw_change_and_store_it(cli, mem_ctx, domain,
189 old_trust_passwd_hash,
190 sec_channel_type);
193 /*********************************************************************
194 Enumerate the list of trusted domains from a DC
195 *********************************************************************/
197 bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
198 char ***domain_names, uint32 *num_domains,
199 DOM_SID **sids )
201 POLICY_HND pol;
202 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
203 fstring dc_name;
204 struct sockaddr_storage dc_ss;
205 uint32 enum_ctx = 0;
206 struct cli_state *cli = NULL;
207 struct rpc_pipe_client *lsa_pipe;
208 bool retry;
209 struct lsa_DomainList dom_list;
210 int i;
212 *domain_names = NULL;
213 *num_domains = 0;
214 *sids = NULL;
216 /* lookup a DC first */
218 if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) {
219 DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n",
220 domain));
221 return False;
224 /* setup the anonymous connection */
226 result = cli_full_connection( &cli, global_myname(), dc_name, &dc_ss, 0, "IPC$", "IPC",
227 "", "", "", 0, Undefined, &retry);
228 if ( !NT_STATUS_IS_OK(result) )
229 goto done;
231 /* open the LSARPC_PIPE */
233 result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
234 &lsa_pipe);
235 if (!NT_STATUS_IS_OK(result)) {
236 goto done;
239 /* get a handle */
241 result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True,
242 LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol);
243 if ( !NT_STATUS_IS_OK(result) )
244 goto done;
246 /* Lookup list of trusted domains */
248 result = rpccli_lsa_EnumTrustDom(lsa_pipe, mem_ctx,
249 &pol,
250 &enum_ctx,
251 &dom_list,
252 (uint32_t)-1);
253 if ( !NT_STATUS_IS_OK(result) )
254 goto done;
256 *num_domains = dom_list.count;
258 *domain_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_domains);
259 if (!*domain_names) {
260 result = NT_STATUS_NO_MEMORY;
261 goto done;
264 *sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_domains);
265 if (!*sids) {
266 result = NT_STATUS_NO_MEMORY;
267 goto done;
270 for (i=0; i< *num_domains; i++) {
271 (*domain_names)[i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
272 (*sids)[i] = *dom_list.domains[i].sid;
275 done:
276 /* cleanup */
277 if (cli) {
278 DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n"));
279 cli_shutdown( cli );
282 return NT_STATUS_IS_OK(result);