c3f5f2538aaa106aa52f442f6811573354b29cbc
[tprouty/samba.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 unsigned char new_trust_passwd_hash[16],
35                                          uint32 sec_channel_type)
36 {
37         NTSTATUS result;
38
39         /* Check if the netlogon pipe is open using schannel. If so we
40            already have valid creds. If not we must set them up. */
41
42         if (cli->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
43                 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
44
45                 result = rpccli_netlogon_setup_creds(cli, 
46                                         cli->cli->desthost, /* server name */
47                                         lp_workgroup(), /* domain */
48                                         global_myname(), /* client name */
49                                         global_myname(), /* machine account name */
50                                         orig_trust_passwd_hash,
51                                         sec_channel_type,
52                                         &neg_flags);
53
54                 if (!NT_STATUS_IS_OK(result)) {
55                         DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n",
56                                  nt_errstr(result)));
57                         return result;
58                 }
59         }
60
61         {
62                 struct netr_Authenticator clnt_creds, srv_cred;
63                 struct samr_Password new_password;
64
65                 netlogon_creds_client_step(cli->dc, &clnt_creds);
66
67                 cred_hash3(new_password.hash,
68                            new_trust_passwd_hash,
69                            cli->dc->sess_key, 1);
70
71                 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
72                                                        cli->dc->remote_machine,
73                                                        cli->dc->mach_acct,
74                                                        sec_channel_type,
75                                                        global_myname(),
76                                                        &clnt_creds,
77                                                        &srv_cred,
78                                                        &new_password);
79
80                 /* Always check returned credentials. */
81                 if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
82                         DEBUG(0,("rpccli_netr_ServerPasswordSet: "
83                                 "credentials chain check failed\n"));
84                         return NT_STATUS_ACCESS_DENIED;
85                 }
86         }
87
88         if (!NT_STATUS_IS_OK(result)) {
89                 DEBUG(0,("just_change_the_password: unable to change password (%s)!\n",
90                          nt_errstr(result)));
91         }
92         return result;
93 }
94
95 /*********************************************************
96  Change the domain password on the PDC.
97  Store the password ourselves, but use the supplied password
98  Caller must have already setup the connection to the NETLOGON pipe
99 **********************************************************/
100
101 NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, 
102                                       const char *domain,
103                                       unsigned char orig_trust_passwd_hash[16],
104                                       uint32 sec_channel_type)
105 {
106         unsigned char new_trust_passwd_hash[16];
107         char *new_trust_passwd;
108         char *str;
109         NTSTATUS nt_status;
110                 
111         /* Create a random machine account password */
112         str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
113
114         if ((new_trust_passwd = talloc_strdup(mem_ctx, str)) == NULL) {
115                 DEBUG(0, ("talloc_strdup failed\n"));
116                 return NT_STATUS_NO_MEMORY;
117         }
118         
119         E_md4hash(new_trust_passwd, new_trust_passwd_hash);
120
121         nt_status = just_change_the_password(cli, mem_ctx, orig_trust_passwd_hash,
122                                              new_trust_passwd_hash, sec_channel_type);
123         
124         if (NT_STATUS_IS_OK(nt_status)) {
125                 DEBUG(3,("%s : trust_pw_change_and_store_it: Changed password.\n", 
126                          current_timestring(debug_ctx(), False)));
127                 /*
128                  * Return the result of trying to write the new password
129                  * back into the trust account file.
130                  */
131                 if (!secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type)) {
132                         nt_status = NT_STATUS_UNSUCCESSFUL;
133                 }
134         }
135
136         return nt_status;
137 }
138
139 /*********************************************************
140  Change the domain password on the PDC.
141  Do most of the legwork ourselfs.  Caller must have
142  already setup the connection to the NETLOGON pipe
143 **********************************************************/
144
145 NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli, 
146                                            TALLOC_CTX *mem_ctx, 
147                                            const char *domain) 
148 {
149         unsigned char old_trust_passwd_hash[16];
150         uint32 sec_channel_type = 0;
151
152         if (!secrets_fetch_trust_account_password(domain,
153                                                   old_trust_passwd_hash, 
154                                                   NULL, &sec_channel_type)) {
155                 DEBUG(0, ("could not fetch domain secrets for domain %s!\n", domain));
156                 return NT_STATUS_UNSUCCESSFUL;
157         }
158         
159         return trust_pw_change_and_store_it(cli, mem_ctx, domain,
160                                             old_trust_passwd_hash,
161                                             sec_channel_type);
162 }
163
164 /*********************************************************************
165  Enumerate the list of trusted domains from a DC
166 *********************************************************************/
167
168 bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
169                                      char ***domain_names, uint32 *num_domains,
170                                      DOM_SID **sids )
171 {
172         POLICY_HND      pol;
173         NTSTATUS        result = NT_STATUS_UNSUCCESSFUL;
174         fstring         dc_name;
175         struct sockaddr_storage dc_ss;
176         uint32          enum_ctx = 0;
177         struct cli_state *cli = NULL;
178         struct rpc_pipe_client *lsa_pipe;
179         bool            retry;
180         struct lsa_DomainList dom_list;
181         int i;
182
183         *domain_names = NULL;
184         *num_domains = 0;
185         *sids = NULL;
186
187         /* lookup a DC first */
188
189         if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) {
190                 DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n",
191                         domain));
192                 return False;
193         }
194
195         /* setup the anonymous connection */
196
197         result = cli_full_connection( &cli, global_myname(), dc_name, &dc_ss, 0, "IPC$", "IPC",
198                 "", "", "", 0, Undefined, &retry);
199         if ( !NT_STATUS_IS_OK(result) )
200                 goto done;
201
202         /* open the LSARPC_PIPE */
203
204         lsa_pipe = cli_rpc_pipe_open_noauth( cli, PI_LSARPC, &result );
205         if ( !lsa_pipe) {
206                 goto done;
207         }
208
209         /* get a handle */
210
211         result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True,
212                 LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol);
213         if ( !NT_STATUS_IS_OK(result) )
214                 goto done;
215
216         /* Lookup list of trusted domains */
217
218         result = rpccli_lsa_EnumTrustDom(lsa_pipe, mem_ctx,
219                                          &pol,
220                                          &enum_ctx,
221                                          &dom_list,
222                                          (uint32_t)-1);
223         if ( !NT_STATUS_IS_OK(result) )
224                 goto done;
225
226         *num_domains = dom_list.count;
227
228         *domain_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_domains);
229         if (!*domain_names) {
230                 result = NT_STATUS_NO_MEMORY;
231                 goto done;
232         }
233
234         *sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_domains);
235         if (!*sids) {
236                 result = NT_STATUS_NO_MEMORY;
237                 goto done;
238         }
239
240         for (i=0; i< *num_domains; i++) {
241                 (*domain_names)[i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
242                 (*sids)[i] = *dom_list.domains[i].sid;
243         }
244
245 done:
246         /* cleanup */
247         if (cli) {
248                 DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n"));
249                 cli_shutdown( cli );
250         }
251
252         return NT_STATUS_IS_OK(result);
253 }