1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 | Copyright (C) Andrew Tridgell 1992-2001
|
---|
4 | Copyright (C) Andrew Bartlett 2002
|
---|
5 | Copyright (C) Rafal Szczesniak 2002
|
---|
6 | Copyright (C) Tim Potter 2001
|
---|
7 |
|
---|
8 | This program is free software; you can redistribute it and/or modify
|
---|
9 | it under the terms of the GNU General Public License as published by
|
---|
10 | the Free Software Foundation; either version 3 of the License, or
|
---|
11 | (at your option) any later version.
|
---|
12 |
|
---|
13 | This program is distributed in the hope that it will be useful,
|
---|
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
16 | GNU General Public License for more details.
|
---|
17 |
|
---|
18 | You should have received a copy of the GNU General Public License
|
---|
19 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
20 | */
|
---|
21 |
|
---|
22 | /* the Samba secrets database stores any generated, private information
|
---|
23 | such as the local SID and machine trust password */
|
---|
24 |
|
---|
25 | #include "includes.h"
|
---|
26 | #include "passdb.h"
|
---|
27 | #include "../libcli/auth/libcli_auth.h"
|
---|
28 | #include "secrets.h"
|
---|
29 | #include "dbwrap.h"
|
---|
30 | #include "../librpc/ndr/libndr.h"
|
---|
31 | #include "util_tdb.h"
|
---|
32 |
|
---|
33 | #undef DBGC_CLASS
|
---|
34 | #define DBGC_CLASS DBGC_PASSDB
|
---|
35 |
|
---|
36 | /* Urrrg. global.... */
|
---|
37 | bool global_machine_password_needs_changing;
|
---|
38 |
|
---|
39 | /**
|
---|
40 | * Form a key for fetching the domain sid
|
---|
41 | *
|
---|
42 | * @param domain domain name
|
---|
43 | *
|
---|
44 | * @return keystring
|
---|
45 | **/
|
---|
46 | static const char *domain_sid_keystr(const char *domain)
|
---|
47 | {
|
---|
48 | char *keystr;
|
---|
49 |
|
---|
50 | keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
|
---|
51 | SECRETS_DOMAIN_SID, domain);
|
---|
52 | SMB_ASSERT(keystr != NULL);
|
---|
53 | return keystr;
|
---|
54 | }
|
---|
55 |
|
---|
56 | bool secrets_store_domain_sid(const char *domain, const struct dom_sid *sid)
|
---|
57 | {
|
---|
58 | bool ret;
|
---|
59 |
|
---|
60 | ret = secrets_store(domain_sid_keystr(domain), sid, sizeof(struct dom_sid ));
|
---|
61 |
|
---|
62 | /* Force a re-query, in case we modified our domain */
|
---|
63 | if (ret)
|
---|
64 | reset_global_sam_sid();
|
---|
65 | return ret;
|
---|
66 | }
|
---|
67 |
|
---|
68 | bool secrets_fetch_domain_sid(const char *domain, struct dom_sid *sid)
|
---|
69 | {
|
---|
70 | struct dom_sid *dyn_sid;
|
---|
71 | size_t size = 0;
|
---|
72 |
|
---|
73 | dyn_sid = (struct dom_sid *)secrets_fetch(domain_sid_keystr(domain), &size);
|
---|
74 |
|
---|
75 | if (dyn_sid == NULL)
|
---|
76 | return False;
|
---|
77 |
|
---|
78 | if (size != sizeof(struct dom_sid)) {
|
---|
79 | SAFE_FREE(dyn_sid);
|
---|
80 | return False;
|
---|
81 | }
|
---|
82 |
|
---|
83 | *sid = *dyn_sid;
|
---|
84 | SAFE_FREE(dyn_sid);
|
---|
85 | return True;
|
---|
86 | }
|
---|
87 |
|
---|
88 | bool secrets_store_domain_guid(const char *domain, struct GUID *guid)
|
---|
89 | {
|
---|
90 | fstring key;
|
---|
91 |
|
---|
92 | slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
|
---|
93 | strupper_m(key);
|
---|
94 | return secrets_store(key, guid, sizeof(struct GUID));
|
---|
95 | }
|
---|
96 |
|
---|
97 | bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid)
|
---|
98 | {
|
---|
99 | struct GUID *dyn_guid;
|
---|
100 | fstring key;
|
---|
101 | size_t size = 0;
|
---|
102 | struct GUID new_guid;
|
---|
103 |
|
---|
104 | slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
|
---|
105 | strupper_m(key);
|
---|
106 | dyn_guid = (struct GUID *)secrets_fetch(key, &size);
|
---|
107 |
|
---|
108 | if (!dyn_guid) {
|
---|
109 | if (lp_server_role() == ROLE_DOMAIN_PDC) {
|
---|
110 | new_guid = GUID_random();
|
---|
111 | if (!secrets_store_domain_guid(domain, &new_guid))
|
---|
112 | return False;
|
---|
113 | dyn_guid = (struct GUID *)secrets_fetch(key, &size);
|
---|
114 | }
|
---|
115 | if (dyn_guid == NULL) {
|
---|
116 | return False;
|
---|
117 | }
|
---|
118 | }
|
---|
119 |
|
---|
120 | if (size != sizeof(struct GUID)) {
|
---|
121 | DEBUG(1,("UUID size %d is wrong!\n", (int)size));
|
---|
122 | SAFE_FREE(dyn_guid);
|
---|
123 | return False;
|
---|
124 | }
|
---|
125 |
|
---|
126 | *guid = *dyn_guid;
|
---|
127 | SAFE_FREE(dyn_guid);
|
---|
128 | return True;
|
---|
129 | }
|
---|
130 |
|
---|
131 | /**
|
---|
132 | * Form a key for fetching the machine trust account sec channel type
|
---|
133 | *
|
---|
134 | * @param domain domain name
|
---|
135 | *
|
---|
136 | * @return keystring
|
---|
137 | **/
|
---|
138 | static const char *machine_sec_channel_type_keystr(const char *domain)
|
---|
139 | {
|
---|
140 | char *keystr;
|
---|
141 |
|
---|
142 | keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
|
---|
143 | SECRETS_MACHINE_SEC_CHANNEL_TYPE,
|
---|
144 | domain);
|
---|
145 | SMB_ASSERT(keystr != NULL);
|
---|
146 | return keystr;
|
---|
147 | }
|
---|
148 |
|
---|
149 | /**
|
---|
150 | * Form a key for fetching the machine trust account last change time
|
---|
151 | *
|
---|
152 | * @param domain domain name
|
---|
153 | *
|
---|
154 | * @return keystring
|
---|
155 | **/
|
---|
156 | static const char *machine_last_change_time_keystr(const char *domain)
|
---|
157 | {
|
---|
158 | char *keystr;
|
---|
159 |
|
---|
160 | keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
|
---|
161 | SECRETS_MACHINE_LAST_CHANGE_TIME,
|
---|
162 | domain);
|
---|
163 | SMB_ASSERT(keystr != NULL);
|
---|
164 | return keystr;
|
---|
165 | }
|
---|
166 |
|
---|
167 |
|
---|
168 | /**
|
---|
169 | * Form a key for fetching the machine previous trust account password
|
---|
170 | *
|
---|
171 | * @param domain domain name
|
---|
172 | *
|
---|
173 | * @return keystring
|
---|
174 | **/
|
---|
175 | static const char *machine_prev_password_keystr(const char *domain)
|
---|
176 | {
|
---|
177 | char *keystr;
|
---|
178 |
|
---|
179 | keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
|
---|
180 | SECRETS_MACHINE_PASSWORD_PREV, domain);
|
---|
181 | SMB_ASSERT(keystr != NULL);
|
---|
182 | return keystr;
|
---|
183 | }
|
---|
184 |
|
---|
185 | /**
|
---|
186 | * Form a key for fetching the machine trust account password
|
---|
187 | *
|
---|
188 | * @param domain domain name
|
---|
189 | *
|
---|
190 | * @return keystring
|
---|
191 | **/
|
---|
192 | static const char *machine_password_keystr(const char *domain)
|
---|
193 | {
|
---|
194 | char *keystr;
|
---|
195 |
|
---|
196 | keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
|
---|
197 | SECRETS_MACHINE_PASSWORD, domain);
|
---|
198 | SMB_ASSERT(keystr != NULL);
|
---|
199 | return keystr;
|
---|
200 | }
|
---|
201 |
|
---|
202 | /**
|
---|
203 | * Form a key for fetching the machine trust account password
|
---|
204 | *
|
---|
205 | * @param domain domain name
|
---|
206 | *
|
---|
207 | * @return stored password's key
|
---|
208 | **/
|
---|
209 | static const char *trust_keystr(const char *domain)
|
---|
210 | {
|
---|
211 | char *keystr;
|
---|
212 |
|
---|
213 | keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
|
---|
214 | SECRETS_MACHINE_ACCT_PASS, domain);
|
---|
215 | SMB_ASSERT(keystr != NULL);
|
---|
216 | return keystr;
|
---|
217 | }
|
---|
218 |
|
---|
219 | /************************************************************************
|
---|
220 | Lock the trust password entry.
|
---|
221 | ************************************************************************/
|
---|
222 |
|
---|
223 | void *secrets_get_trust_account_lock(TALLOC_CTX *mem_ctx, const char *domain)
|
---|
224 | {
|
---|
225 | struct db_context *db_ctx;
|
---|
226 | if (!secrets_init()) {
|
---|
227 | return NULL;
|
---|
228 | }
|
---|
229 |
|
---|
230 | db_ctx = secrets_db_ctx();
|
---|
231 |
|
---|
232 | return db_ctx->fetch_locked(
|
---|
233 | db_ctx, mem_ctx, string_term_tdb_data(trust_keystr(domain)));
|
---|
234 | }
|
---|
235 |
|
---|
236 | /************************************************************************
|
---|
237 | Routine to get the default secure channel type for trust accounts
|
---|
238 | ************************************************************************/
|
---|
239 |
|
---|
240 | enum netr_SchannelType get_default_sec_channel(void)
|
---|
241 | {
|
---|
242 | if (lp_server_role() == ROLE_DOMAIN_BDC ||
|
---|
243 | lp_server_role() == ROLE_DOMAIN_PDC) {
|
---|
244 | return SEC_CHAN_BDC;
|
---|
245 | } else {
|
---|
246 | return SEC_CHAN_WKSTA;
|
---|
247 | }
|
---|
248 | }
|
---|
249 |
|
---|
250 | /************************************************************************
|
---|
251 | Routine to get the trust account password for a domain.
|
---|
252 | This only tries to get the legacy hashed version of the password.
|
---|
253 | The user of this function must have locked the trust password file using
|
---|
254 | the above secrets_lock_trust_account_password().
|
---|
255 | ************************************************************************/
|
---|
256 |
|
---|
257 | bool secrets_fetch_trust_account_password_legacy(const char *domain,
|
---|
258 | uint8 ret_pwd[16],
|
---|
259 | time_t *pass_last_set_time,
|
---|
260 | enum netr_SchannelType *channel)
|
---|
261 | {
|
---|
262 | struct machine_acct_pass *pass;
|
---|
263 | size_t size = 0;
|
---|
264 |
|
---|
265 | if (!(pass = (struct machine_acct_pass *)secrets_fetch(
|
---|
266 | trust_keystr(domain), &size))) {
|
---|
267 | DEBUG(5, ("secrets_fetch failed!\n"));
|
---|
268 | return False;
|
---|
269 | }
|
---|
270 |
|
---|
271 | if (size != sizeof(*pass)) {
|
---|
272 | DEBUG(0, ("secrets were of incorrect size!\n"));
|
---|
273 | SAFE_FREE(pass);
|
---|
274 | return False;
|
---|
275 | }
|
---|
276 |
|
---|
277 | if (pass_last_set_time) {
|
---|
278 | *pass_last_set_time = pass->mod_time;
|
---|
279 | }
|
---|
280 | memcpy(ret_pwd, pass->hash, 16);
|
---|
281 |
|
---|
282 | if (channel) {
|
---|
283 | *channel = get_default_sec_channel();
|
---|
284 | }
|
---|
285 |
|
---|
286 | /* Test if machine password has expired and needs to be changed */
|
---|
287 | if (lp_machine_password_timeout()) {
|
---|
288 | if (pass->mod_time > 0 && time(NULL) > (pass->mod_time +
|
---|
289 | (time_t)lp_machine_password_timeout())) {
|
---|
290 | global_machine_password_needs_changing = True;
|
---|
291 | }
|
---|
292 | }
|
---|
293 |
|
---|
294 | SAFE_FREE(pass);
|
---|
295 | return True;
|
---|
296 | }
|
---|
297 |
|
---|
298 | /************************************************************************
|
---|
299 | Routine to get the trust account password for a domain.
|
---|
300 | The user of this function must have locked the trust password file using
|
---|
301 | the above secrets_lock_trust_account_password().
|
---|
302 | ************************************************************************/
|
---|
303 |
|
---|
304 | bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16],
|
---|
305 | time_t *pass_last_set_time,
|
---|
306 | enum netr_SchannelType *channel)
|
---|
307 | {
|
---|
308 | char *plaintext;
|
---|
309 |
|
---|
310 | plaintext = secrets_fetch_machine_password(domain, pass_last_set_time,
|
---|
311 | channel);
|
---|
312 | if (plaintext) {
|
---|
313 | DEBUG(4,("Using cleartext machine password\n"));
|
---|
314 | E_md4hash(plaintext, ret_pwd);
|
---|
315 | SAFE_FREE(plaintext);
|
---|
316 | return True;
|
---|
317 | }
|
---|
318 |
|
---|
319 | return secrets_fetch_trust_account_password_legacy(domain, ret_pwd,
|
---|
320 | pass_last_set_time,
|
---|
321 | channel);
|
---|
322 | }
|
---|
323 |
|
---|
324 | /************************************************************************
|
---|
325 | Routine to delete the old plaintext machine account password if any
|
---|
326 | ************************************************************************/
|
---|
327 |
|
---|
328 | static bool secrets_delete_prev_machine_password(const char *domain)
|
---|
329 | {
|
---|
330 | char *oldpass = (char *)secrets_fetch(machine_prev_password_keystr(domain), NULL);
|
---|
331 | if (oldpass == NULL) {
|
---|
332 | return true;
|
---|
333 | }
|
---|
334 | SAFE_FREE(oldpass);
|
---|
335 | return secrets_delete(machine_prev_password_keystr(domain));
|
---|
336 | }
|
---|
337 |
|
---|
338 | /************************************************************************
|
---|
339 | Routine to delete the plaintext machine account password and old
|
---|
340 | password if any
|
---|
341 | ************************************************************************/
|
---|
342 |
|
---|
343 | bool secrets_delete_machine_password(const char *domain)
|
---|
344 | {
|
---|
345 | if (!secrets_delete_prev_machine_password(domain)) {
|
---|
346 | return false;
|
---|
347 | }
|
---|
348 | return secrets_delete(machine_password_keystr(domain));
|
---|
349 | }
|
---|
350 |
|
---|
351 | /************************************************************************
|
---|
352 | Routine to delete the plaintext machine account password, old password,
|
---|
353 | sec channel type and last change time from secrets database
|
---|
354 | ************************************************************************/
|
---|
355 |
|
---|
356 | bool secrets_delete_machine_password_ex(const char *domain)
|
---|
357 | {
|
---|
358 | if (!secrets_delete_prev_machine_password(domain)) {
|
---|
359 | return false;
|
---|
360 | }
|
---|
361 | if (!secrets_delete(machine_password_keystr(domain))) {
|
---|
362 | return false;
|
---|
363 | }
|
---|
364 | if (!secrets_delete(machine_sec_channel_type_keystr(domain))) {
|
---|
365 | return false;
|
---|
366 | }
|
---|
367 | return secrets_delete(machine_last_change_time_keystr(domain));
|
---|
368 | }
|
---|
369 |
|
---|
370 | /************************************************************************
|
---|
371 | Routine to delete the domain sid
|
---|
372 | ************************************************************************/
|
---|
373 |
|
---|
374 | bool secrets_delete_domain_sid(const char *domain)
|
---|
375 | {
|
---|
376 | return secrets_delete(domain_sid_keystr(domain));
|
---|
377 | }
|
---|
378 |
|
---|
379 | /************************************************************************
|
---|
380 | Routine to store the previous machine password (by storing the current password
|
---|
381 | as the old)
|
---|
382 | ************************************************************************/
|
---|
383 |
|
---|
384 | static bool secrets_store_prev_machine_password(const char *domain)
|
---|
385 | {
|
---|
386 | char *oldpass;
|
---|
387 | bool ret;
|
---|
388 |
|
---|
389 | oldpass = (char *)secrets_fetch(machine_password_keystr(domain), NULL);
|
---|
390 | if (oldpass == NULL) {
|
---|
391 | return true;
|
---|
392 | }
|
---|
393 | ret = secrets_store(machine_prev_password_keystr(domain), oldpass, strlen(oldpass)+1);
|
---|
394 | SAFE_FREE(oldpass);
|
---|
395 | return ret;
|
---|
396 | }
|
---|
397 |
|
---|
398 | /************************************************************************
|
---|
399 | Routine to set the plaintext machine account password for a realm
|
---|
400 | the password is assumed to be a null terminated ascii string.
|
---|
401 | Before storing
|
---|
402 | ************************************************************************/
|
---|
403 |
|
---|
404 | bool secrets_store_machine_password(const char *pass, const char *domain,
|
---|
405 | enum netr_SchannelType sec_channel)
|
---|
406 | {
|
---|
407 | bool ret;
|
---|
408 | uint32 last_change_time;
|
---|
409 | uint32 sec_channel_type;
|
---|
410 |
|
---|
411 | if (!secrets_store_prev_machine_password(domain)) {
|
---|
412 | return false;
|
---|
413 | }
|
---|
414 |
|
---|
415 | ret = secrets_store(machine_password_keystr(domain), pass, strlen(pass)+1);
|
---|
416 | if (!ret)
|
---|
417 | return ret;
|
---|
418 |
|
---|
419 | SIVAL(&last_change_time, 0, time(NULL));
|
---|
420 | ret = secrets_store(machine_last_change_time_keystr(domain), &last_change_time, sizeof(last_change_time));
|
---|
421 |
|
---|
422 | SIVAL(&sec_channel_type, 0, sec_channel);
|
---|
423 | ret = secrets_store(machine_sec_channel_type_keystr(domain), &sec_channel_type, sizeof(sec_channel_type));
|
---|
424 |
|
---|
425 | return ret;
|
---|
426 | }
|
---|
427 |
|
---|
428 |
|
---|
429 | /************************************************************************
|
---|
430 | Routine to fetch the previous plaintext machine account password for a realm
|
---|
431 | the password is assumed to be a null terminated ascii string.
|
---|
432 | ************************************************************************/
|
---|
433 |
|
---|
434 | char *secrets_fetch_prev_machine_password(const char *domain)
|
---|
435 | {
|
---|
436 | return (char *)secrets_fetch(machine_prev_password_keystr(domain), NULL);
|
---|
437 | }
|
---|
438 |
|
---|
439 | /************************************************************************
|
---|
440 | Routine to fetch the plaintext machine account password for a realm
|
---|
441 | the password is assumed to be a null terminated ascii string.
|
---|
442 | ************************************************************************/
|
---|
443 |
|
---|
444 | char *secrets_fetch_machine_password(const char *domain,
|
---|
445 | time_t *pass_last_set_time,
|
---|
446 | enum netr_SchannelType *channel)
|
---|
447 | {
|
---|
448 | char *ret;
|
---|
449 | ret = (char *)secrets_fetch(machine_password_keystr(domain), NULL);
|
---|
450 |
|
---|
451 | if (pass_last_set_time) {
|
---|
452 | size_t size;
|
---|
453 | uint32 *last_set_time;
|
---|
454 | last_set_time = (unsigned int *)secrets_fetch(machine_last_change_time_keystr(domain), &size);
|
---|
455 | if (last_set_time) {
|
---|
456 | *pass_last_set_time = IVAL(last_set_time,0);
|
---|
457 | SAFE_FREE(last_set_time);
|
---|
458 | } else {
|
---|
459 | *pass_last_set_time = 0;
|
---|
460 | }
|
---|
461 | }
|
---|
462 |
|
---|
463 | if (channel) {
|
---|
464 | size_t size;
|
---|
465 | uint32 *channel_type;
|
---|
466 | channel_type = (unsigned int *)secrets_fetch(machine_sec_channel_type_keystr(domain), &size);
|
---|
467 | if (channel_type) {
|
---|
468 | *channel = IVAL(channel_type,0);
|
---|
469 | SAFE_FREE(channel_type);
|
---|
470 | } else {
|
---|
471 | *channel = get_default_sec_channel();
|
---|
472 | }
|
---|
473 | }
|
---|
474 |
|
---|
475 | return ret;
|
---|
476 | }
|
---|