s3:netlogon: replace cred_hash3 by des_crypt112_16
[obnox/samba-ctdb.git] / source / libsmb / trusts_util.c
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
6  *
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.
11  *  
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.
16  *  
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/>.
19  */
20
21 #include "includes.h"
22
23 /*********************************************************
24  Change the domain password on the PDC.
25
26  Just changes the password betwen the two values specified.
27
28  Caller must have the cli connected to the netlogon pipe
29  already.
30 **********************************************************/
31
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)
37 {
38         NTSTATUS result;
39         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
40
41         result = rpccli_netlogon_setup_creds(cli,
42                                              cli->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);
49
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;
54         }
55
56         if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
57
58                 struct netr_Authenticator clnt_creds, srv_cred;
59                 struct netr_CryptPassword new_password;
60                 struct samr_CryptPassword password_buf;
61
62                 netlogon_creds_client_step(cli->dc, &clnt_creds);
63
64                 encode_pw_buffer(password_buf.data, new_trust_pwd_cleartext, STR_UNICODE);
65
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);
69
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);
78
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;
84                 }
85
86         } else {
87
88                 struct netr_Authenticator clnt_creds, srv_cred;
89                 struct samr_Password new_password;
90
91                 netlogon_creds_client_step(cli->dc, &clnt_creds);
92
93                 des_crypt112_16(new_password.hash,
94                                 new_trust_passwd_hash,
95                                 cli->dc->sess_key, 1);
96
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);
105
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;
111                 }
112         }
113
114         if (!NT_STATUS_IS_OK(result)) {
115                 DEBUG(0,("just_change_the_password: unable to change password (%s)!\n",
116                          nt_errstr(result)));
117         }
118         return result;
119 }
120
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 **********************************************************/
126
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)
131 {
132         unsigned char new_trust_passwd_hash[16];
133         char *new_trust_passwd;
134         char *str;
135         NTSTATUS nt_status;
136                 
137         /* Create a random machine account password */
138         str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
139
140         if ((new_trust_passwd = talloc_strdup(mem_ctx, str)) == NULL) {
141                 DEBUG(0, ("talloc_strdup failed\n"));
142                 return NT_STATUS_NO_MEMORY;
143         }
144         
145         E_md4hash(new_trust_passwd, new_trust_passwd_hash);
146
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);
152         
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)));
156                 /*
157                  * Return the result of trying to write the new password
158                  * back into the trust account file.
159                  */
160                 if (!secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type)) {
161                         nt_status = NT_STATUS_UNSUCCESSFUL;
162                 }
163         }
164
165         return nt_status;
166 }
167
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 **********************************************************/
173
174 NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli, 
175                                            TALLOC_CTX *mem_ctx, 
176                                            const char *domain) 
177 {
178         unsigned char old_trust_passwd_hash[16];
179         uint32 sec_channel_type = 0;
180
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;
186         }
187         
188         return trust_pw_change_and_store_it(cli, mem_ctx, domain,
189                                             old_trust_passwd_hash,
190                                             sec_channel_type);
191 }
192
193 /*********************************************************************
194  Enumerate the list of trusted domains from a DC
195 *********************************************************************/
196
197 bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
198                                      char ***domain_names, uint32 *num_domains,
199                                      DOM_SID **sids )
200 {
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;
211
212         *domain_names = NULL;
213         *num_domains = 0;
214         *sids = NULL;
215
216         /* lookup a DC first */
217
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;
222         }
223
224         /* setup the anonymous connection */
225
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;
230
231         /* open the LSARPC_PIPE */
232
233         lsa_pipe = cli_rpc_pipe_open_noauth( cli, PI_LSARPC, &result );
234         if ( !lsa_pipe) {
235                 goto done;
236         }
237
238         /* get a handle */
239
240         result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True,
241                 LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol);
242         if ( !NT_STATUS_IS_OK(result) )
243                 goto done;
244
245         /* Lookup list of trusted domains */
246
247         result = rpccli_lsa_EnumTrustDom(lsa_pipe, mem_ctx,
248                                          &pol,
249                                          &enum_ctx,
250                                          &dom_list,
251                                          (uint32_t)-1);
252         if ( !NT_STATUS_IS_OK(result) )
253                 goto done;
254
255         *num_domains = dom_list.count;
256
257         *domain_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_domains);
258         if (!*domain_names) {
259                 result = NT_STATUS_NO_MEMORY;
260                 goto done;
261         }
262
263         *sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_domains);
264         if (!*sids) {
265                 result = NT_STATUS_NO_MEMORY;
266                 goto done;
267         }
268
269         for (i=0; i< *num_domains; i++) {
270                 (*domain_names)[i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
271                 (*sids)[i] = *dom_list.domains[i].sid;
272         }
273
274 done:
275         /* cleanup */
276         if (cli) {
277                 DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n"));
278                 cli_shutdown( cli );
279         }
280
281         return NT_STATUS_IS_OK(result);
282 }