source: vendor/current/source3/libsmb/trusts_util.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 8.1 KB
Line 
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#include "../libcli/auth/libcli_auth.h"
23#include "../libcli/auth/netlogon_creds_cli.h"
24#include "rpc_client/cli_netlogon.h"
25#include "rpc_client/cli_pipe.h"
26#include "../librpc/gen_ndr/ndr_netlogon.h"
27#include "secrets.h"
28#include "passdb.h"
29#include "libsmb/libsmb.h"
30#include "source3/include/messages.h"
31#include "source3/include/g_lock.h"
32
33/*********************************************************
34 Change the domain password on the PDC.
35 Do most of the legwork ourselfs. Caller must have
36 already setup the connection to the NETLOGON pipe
37**********************************************************/
38
39struct trust_pw_change_state {
40 struct g_lock_ctx *g_ctx;
41 char *g_lock_key;
42};
43
44static int trust_pw_change_state_destructor(struct trust_pw_change_state *state)
45{
46 g_lock_unlock(state->g_ctx, state->g_lock_key);
47 return 0;
48}
49
50NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
51 struct messaging_context *msg_ctx,
52 struct dcerpc_binding_handle *b,
53 const char *domain,
54 bool force)
55{
56 TALLOC_CTX *frame = talloc_stackframe();
57 struct trust_pw_change_state *state;
58 struct cli_credentials *creds = NULL;
59 const struct samr_Password *current_nt_hash = NULL;
60 const struct samr_Password *previous_nt_hash = NULL;
61 enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
62 time_t pass_last_set_time;
63 uint32_t old_version = 0;
64 struct pdb_trusted_domain *td = NULL;
65 struct timeval g_timeout = { 0, };
66 int timeout = 0;
67 struct timeval tv = { 0, };
68 size_t new_len = DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH;
69 uint8_t new_password_buffer[256 * 2] = { 0, };
70 char *new_trust_passwd = NULL;
71 size_t len = 0;
72 uint32_t new_version = 0;
73 uint32_t *new_trust_version = NULL;
74 NTSTATUS status;
75 bool ok;
76
77 state = talloc_zero(frame, struct trust_pw_change_state);
78 if (state == NULL) {
79 TALLOC_FREE(frame);
80 return NT_STATUS_NO_MEMORY;
81 }
82
83 state->g_ctx = g_lock_ctx_init(state, msg_ctx);
84 if (state->g_ctx == NULL) {
85 TALLOC_FREE(frame);
86 return NT_STATUS_NO_MEMORY;
87 }
88
89 state->g_lock_key = talloc_asprintf(state,
90 "trust_password_change_%s",
91 domain);
92 if (state->g_lock_key == NULL) {
93 TALLOC_FREE(frame);
94 return NT_STATUS_NO_MEMORY;
95 }
96
97 g_timeout = timeval_current_ofs(10, 0);
98 status = g_lock_lock(state->g_ctx,
99 state->g_lock_key,
100 G_LOCK_WRITE, g_timeout);
101 if (!NT_STATUS_IS_OK(status)) {
102 DEBUG(1, ("could not get g_lock on [%s]!\n",
103 state->g_lock_key));
104 TALLOC_FREE(frame);
105 return status;
106 }
107
108 talloc_set_destructor(state, trust_pw_change_state_destructor);
109
110 status = pdb_get_trust_credentials(domain, NULL, frame, &creds);
111 if (!NT_STATUS_IS_OK(status)) {
112 DEBUG(0, ("could not fetch domain creds for domain %s - %s!\n",
113 domain, nt_errstr(status)));
114 TALLOC_FREE(frame);
115 return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
116 }
117
118 current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
119 if (current_nt_hash == NULL) {
120 DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
121 domain));
122 TALLOC_FREE(frame);
123 return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
124 }
125
126 old_version = cli_credentials_get_kvno(creds);
127 pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
128 sec_channel_type = cli_credentials_get_secure_channel_type(creds);
129
130 new_version = old_version + 1;
131
132 switch (sec_channel_type) {
133 case SEC_CHAN_WKSTA:
134 case SEC_CHAN_BDC:
135 break;
136 case SEC_CHAN_DNS_DOMAIN:
137 /*
138 * new_len * 2 = 498 bytes is the largest possible length
139 * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes
140 * and a confounder with at least 2 bytes is required.
141 *
142 * Windows uses new_len = 120 => 240 bytes.
143 */
144 new_len = 120;
145
146 /* fall through */
147 case SEC_CHAN_DOMAIN:
148 status = pdb_get_trusted_domain(frame, domain, &td);
149 if (!NT_STATUS_IS_OK(status)) {
150 DEBUG(0, ("pdb_get_trusted_domain() failed for domain %s - %s!\n",
151 domain, nt_errstr(status)));
152 TALLOC_FREE(frame);
153 return status;
154 }
155
156 new_trust_version = &new_version;
157 break;
158 default:
159 TALLOC_FREE(frame);
160 return NT_STATUS_NOT_SUPPORTED;
161 }
162
163 timeout = lp_machine_password_timeout();
164 if (timeout == 0) {
165 if (!force) {
166 DEBUG(10,("machine password never expires\n"));
167 TALLOC_FREE(frame);
168 return NT_STATUS_OK;
169 }
170 }
171
172 tv.tv_sec = pass_last_set_time;
173 DEBUG(10, ("password last changed %s\n",
174 timeval_string(talloc_tos(), &tv, false)));
175 tv.tv_sec += timeout;
176 DEBUGADD(10, ("password valid until %s\n",
177 timeval_string(talloc_tos(), &tv, false)));
178
179 if (!force && !timeval_expired(&tv)) {
180 TALLOC_FREE(frame);
181 return NT_STATUS_OK;
182 }
183
184 /*
185 * Create a random machine account password
186 * We create a random buffer and convert that to utf8.
187 * This is similar to what windows is doing.
188 */
189 generate_secret_buffer(new_password_buffer, new_len * 2);
190 ok = convert_string_talloc(frame,
191 CH_UTF16MUNGED, CH_UTF8,
192 new_password_buffer, new_len * 2,
193 (void *)&new_trust_passwd, &len);
194 ZERO_STRUCT(new_password_buffer);
195 if (!ok) {
196 DEBUG(0, ("convert_string_talloc failed\n"));
197 TALLOC_FREE(frame);
198 return NT_STATUS_NO_MEMORY;
199 }
200
201 /*
202 * We could use cli_credentials_get_old_nt_hash(creds, frame) to
203 * set previous_nt_hash.
204 *
205 * But we want to check if the dc has our current password and only do
206 * a change if that's the case. So we keep previous_nt_hash = NULL.
207 *
208 * TODO:
209 * If the previous password is the only password in common with the dc,
210 * we better skip the password change, or use something like
211 * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our
212 * local secrets before doing the change.
213 */
214 status = netlogon_creds_cli_auth(context, b,
215 *current_nt_hash,
216 previous_nt_hash);
217 if (!NT_STATUS_IS_OK(status)) {
218 DEBUG(0, ("netlogon_creds_cli_auth for domain %s - %s!\n",
219 domain, nt_errstr(status)));
220 TALLOC_FREE(frame);
221 return status;
222 }
223
224 /*
225 * Return the result of trying to write the new password
226 * back into the trust account file.
227 */
228
229 switch (sec_channel_type) {
230
231 case SEC_CHAN_WKSTA:
232 case SEC_CHAN_BDC:
233 ok = secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type);
234 if (!ok) {
235 DEBUG(0, ("secrets_store_machine_password failed for domain %s!\n",
236 domain));
237 TALLOC_FREE(frame);
238 return NT_STATUS_INTERNAL_DB_CORRUPTION;
239 }
240 break;
241
242 case SEC_CHAN_DNS_DOMAIN:
243 case SEC_CHAN_DOMAIN:
244 /*
245 * we need to get the sid first for the
246 * pdb_set_trusteddom_pw call
247 */
248 ok = pdb_set_trusteddom_pw(domain, new_trust_passwd,
249 &td->security_identifier);
250 if (!ok) {
251 DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n",
252 domain));
253 TALLOC_FREE(frame);
254 return NT_STATUS_INTERNAL_DB_CORRUPTION;
255 }
256 break;
257
258 default:
259 smb_panic("Unsupported secure channel type");
260 break;
261 }
262
263 DEBUG(1,("%s : %s(%s): Changed password locally\n",
264 current_timestring(talloc_tos(), false), __func__, domain));
265
266 status = netlogon_creds_cli_ServerPasswordSet(context, b,
267 new_trust_passwd,
268 new_trust_version);
269 if (!NT_STATUS_IS_OK(status)) {
270 DEBUG(0,("%s : %s(%s) remote password change set failed - %s\n",
271 current_timestring(talloc_tos(), false), __func__,
272 domain, nt_errstr(status)));
273 TALLOC_FREE(frame);
274 return status;
275 }
276
277 DEBUG(1,("%s : %s(%s): Changed password remotely.\n",
278 current_timestring(talloc_tos(), false), __func__, domain));
279
280 TALLOC_FREE(frame);
281 return NT_STATUS_OK;
282}
Note: See TracBrowser for help on using the repository browser.