source: trunk/server/source3/passdb/secrets.c@ 902

Last change on this file since 902 was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 14.9 KB
Line 
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 "system/filesys.h"
27#include "passdb.h"
28#include "../libcli/auth/libcli_auth.h"
29#include "librpc/gen_ndr/ndr_secrets.h"
30#include "secrets.h"
31#include "dbwrap.h"
32#include "../libcli/security/security.h"
33#include "util_tdb.h"
34
35#undef DBGC_CLASS
36#define DBGC_CLASS DBGC_PASSDB
37
38static struct db_context *db_ctx;
39
40/**
41 * Use a TDB to store an incrementing random seed.
42 *
43 * Initialised to the current pid, the very first time Samba starts,
44 * and incremented by one each time it is needed.
45 *
46 * @note Not called by systems with a working /dev/urandom.
47 */
48static void get_rand_seed(void *userdata, int *new_seed)
49{
50 *new_seed = sys_getpid();
51 if (db_ctx) {
52 dbwrap_trans_change_int32_atomic(db_ctx, "INFO/random_seed",
53 new_seed, 1);
54 }
55}
56
57/* open up the secrets database */
58bool secrets_init(void)
59{
60 char *fname = NULL;
61 unsigned char dummy;
62
63 if (db_ctx != NULL)
64 return True;
65
66 fname = talloc_asprintf(talloc_tos(), "%s/secrets.tdb",
67 lp_private_dir());
68 if (fname == NULL) {
69 return false;
70 }
71
72 db_ctx = db_open(NULL, fname, 0,
73 TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
74
75 if (db_ctx == NULL) {
76 DEBUG(0,("Failed to open %s\n", fname));
77 TALLOC_FREE(fname);
78 return False;
79 }
80
81 TALLOC_FREE(fname);
82
83 /**
84 * Set a reseed function for the crypto random generator
85 *
86 * This avoids a problem where systems without /dev/urandom
87 * could send the same challenge to multiple clients
88 */
89 set_rand_reseed_callback(get_rand_seed, NULL);
90
91 /* Ensure that the reseed is done now, while we are root, etc */
92 generate_random_buffer(&dummy, sizeof(dummy));
93
94 return True;
95}
96
97struct db_context *secrets_db_ctx(void)
98{
99 if (!secrets_init()) {
100 return NULL;
101 }
102
103 return db_ctx;
104}
105
106/*
107 * close secrets.tdb
108 */
109void secrets_shutdown(void)
110{
111 TALLOC_FREE(db_ctx);
112}
113
114/* read a entry from the secrets database - the caller must free the result
115 if size is non-null then the size of the entry is put in there
116 */
117void *secrets_fetch(const char *key, size_t *size)
118{
119 TDB_DATA dbuf;
120 void *result;
121
122 if (!secrets_init()) {
123 return NULL;
124 }
125
126 if (db_ctx->fetch(db_ctx, talloc_tos(), string_tdb_data(key),
127 &dbuf) != 0) {
128 return NULL;
129 }
130
131 result = memdup(dbuf.dptr, dbuf.dsize);
132 if (result == NULL) {
133 return NULL;
134 }
135 TALLOC_FREE(dbuf.dptr);
136
137 if (size) {
138 *size = dbuf.dsize;
139 }
140
141 return result;
142}
143
144/* store a secrets entry
145 */
146bool secrets_store(const char *key, const void *data, size_t size)
147{
148 NTSTATUS status;
149
150 if (!secrets_init()) {
151 return false;
152 }
153
154 status = dbwrap_trans_store(db_ctx, string_tdb_data(key),
155 make_tdb_data((const uint8 *)data, size),
156 TDB_REPLACE);
157 return NT_STATUS_IS_OK(status);
158}
159
160
161/* delete a secets database entry
162 */
163bool secrets_delete(const char *key)
164{
165 NTSTATUS status;
166 if (!secrets_init()) {
167 return false;
168 }
169
170 status = dbwrap_trans_delete(db_ctx, string_tdb_data(key));
171
172 return NT_STATUS_IS_OK(status);
173}
174
175/**
176 * Form a key for fetching a trusted domain password
177 *
178 * @param domain trusted domain name
179 *
180 * @return stored password's key
181 **/
182static char *trustdom_keystr(const char *domain)
183{
184 char *keystr;
185
186 keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
187 SECRETS_DOMTRUST_ACCT_PASS,
188 domain);
189 SMB_ASSERT(keystr != NULL);
190 return keystr;
191}
192
193/************************************************************************
194 Routine to get account password to trusted domain
195************************************************************************/
196
197bool secrets_fetch_trusted_domain_password(const char *domain, char** pwd,
198 struct dom_sid *sid, time_t *pass_last_set_time)
199{
200 struct TRUSTED_DOM_PASS pass;
201 enum ndr_err_code ndr_err;
202
203 /* unpacking structures */
204 DATA_BLOB blob;
205
206 /* fetching trusted domain password structure */
207 if (!(blob.data = (uint8_t *)secrets_fetch(trustdom_keystr(domain),
208 &blob.length))) {
209 DEBUG(5, ("secrets_fetch failed!\n"));
210 return False;
211 }
212
213 /* unpack trusted domain password */
214 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &pass,
215 (ndr_pull_flags_fn_t)ndr_pull_TRUSTED_DOM_PASS);
216
217 SAFE_FREE(blob.data);
218
219 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
220 return false;
221 }
222
223
224 /* the trust's password */
225 if (pwd) {
226 *pwd = SMB_STRDUP(pass.pass);
227 if (!*pwd) {
228 return False;
229 }
230 }
231
232 /* last change time */
233 if (pass_last_set_time) *pass_last_set_time = pass.mod_time;
234
235 /* domain sid */
236 if (sid != NULL) sid_copy(sid, &pass.domain_sid);
237
238 return True;
239}
240
241/**
242 * Routine to store the password for trusted domain
243 *
244 * @param domain remote domain name
245 * @param pwd plain text password of trust relationship
246 * @param sid remote domain sid
247 *
248 * @return true if succeeded
249 **/
250
251bool secrets_store_trusted_domain_password(const char* domain, const char* pwd,
252 const struct dom_sid *sid)
253{
254 bool ret;
255
256 /* packing structures */
257 DATA_BLOB blob;
258 enum ndr_err_code ndr_err;
259 struct TRUSTED_DOM_PASS pass;
260 ZERO_STRUCT(pass);
261
262 pass.uni_name = domain;
263 pass.uni_name_len = strlen(domain)+1;
264
265 /* last change time */
266 pass.mod_time = time(NULL);
267
268 /* password of the trust */
269 pass.pass_len = strlen(pwd);
270 pass.pass = pwd;
271
272 /* domain sid */
273 sid_copy(&pass.domain_sid, sid);
274
275 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &pass,
276 (ndr_push_flags_fn_t)ndr_push_TRUSTED_DOM_PASS);
277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
278 return false;
279 }
280
281 ret = secrets_store(trustdom_keystr(domain), blob.data, blob.length);
282
283 data_blob_free(&blob);
284
285 return ret;
286}
287
288/************************************************************************
289 Routine to delete the password for trusted domain
290************************************************************************/
291
292bool trusted_domain_password_delete(const char *domain)
293{
294 return secrets_delete(trustdom_keystr(domain));
295}
296
297bool secrets_store_ldap_pw(const char* dn, char* pw)
298{
299 char *key = NULL;
300 bool ret;
301
302 if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, dn) < 0) {
303 DEBUG(0, ("secrets_store_ldap_pw: asprintf failed!\n"));
304 return False;
305 }
306
307 ret = secrets_store(key, pw, strlen(pw)+1);
308
309 SAFE_FREE(key);
310 return ret;
311}
312
313/*******************************************************************
314 Find the ldap password.
315******************************************************************/
316
317bool fetch_ldap_pw(char **dn, char** pw)
318{
319 char *key = NULL;
320 size_t size = 0;
321
322 *dn = smb_xstrdup(lp_ldap_admin_dn());
323
324 if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
325 SAFE_FREE(*dn);
326 DEBUG(0, ("fetch_ldap_pw: asprintf failed!\n"));
327 return false;
328 }
329
330 *pw=(char *)secrets_fetch(key, &size);
331 SAFE_FREE(key);
332
333 if (!size) {
334 /* Upgrade 2.2 style entry */
335 char *p;
336 char* old_style_key = SMB_STRDUP(*dn);
337 char *data;
338 fstring old_style_pw;
339
340 if (!old_style_key) {
341 DEBUG(0, ("fetch_ldap_pw: strdup failed!\n"));
342 return False;
343 }
344
345 for (p=old_style_key; *p; p++)
346 if (*p == ',') *p = '/';
347
348 data=(char *)secrets_fetch(old_style_key, &size);
349 if ((data == NULL) || (size < sizeof(old_style_pw))) {
350 DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
351 SAFE_FREE(old_style_key);
352 SAFE_FREE(*dn);
353 SAFE_FREE(data);
354 return False;
355 }
356
357 size = MIN(size, sizeof(fstring)-1);
358 strncpy(old_style_pw, data, size);
359 old_style_pw[size] = 0;
360
361 SAFE_FREE(data);
362
363 if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
364 DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
365 SAFE_FREE(old_style_key);
366 SAFE_FREE(*dn);
367 return False;
368 }
369 if (!secrets_delete(old_style_key)) {
370 DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
371 }
372
373 SAFE_FREE(old_style_key);
374
375 *pw = smb_xstrdup(old_style_pw);
376 }
377
378 return True;
379}
380
381/**
382 * Get trusted domains info from secrets.tdb.
383 **/
384
385struct list_trusted_domains_state {
386 uint32 num_domains;
387 struct trustdom_info **domains;
388};
389
390static int list_trusted_domain(struct db_record *rec, void *private_data)
391{
392 const size_t prefix_len = strlen(SECRETS_DOMTRUST_ACCT_PASS);
393 struct TRUSTED_DOM_PASS pass;
394 enum ndr_err_code ndr_err;
395 DATA_BLOB blob;
396 struct trustdom_info *dom_info;
397
398 struct list_trusted_domains_state *state =
399 (struct list_trusted_domains_state *)private_data;
400
401 if ((rec->key.dsize < prefix_len)
402 || (strncmp((char *)rec->key.dptr, SECRETS_DOMTRUST_ACCT_PASS,
403 prefix_len) != 0)) {
404 return 0;
405 }
406
407 blob = data_blob_const(rec->value.dptr, rec->value.dsize);
408
409 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &pass,
410 (ndr_pull_flags_fn_t)ndr_pull_TRUSTED_DOM_PASS);
411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
412 return false;
413 }
414
415 if (pass.domain_sid.num_auths != 4) {
416 DEBUG(0, ("SID %s is not a domain sid, has %d "
417 "auths instead of 4\n",
418 sid_string_dbg(&pass.domain_sid),
419 pass.domain_sid.num_auths));
420 return 0;
421 }
422
423 if (!(dom_info = TALLOC_P(state->domains, struct trustdom_info))) {
424 DEBUG(0, ("talloc failed\n"));
425 return 0;
426 }
427
428 dom_info->name = talloc_strdup(dom_info, pass.uni_name);
429 if (!dom_info->name) {
430 TALLOC_FREE(dom_info);
431 return 0;
432 }
433
434 sid_copy(&dom_info->sid, &pass.domain_sid);
435
436 ADD_TO_ARRAY(state->domains, struct trustdom_info *, dom_info,
437 &state->domains, &state->num_domains);
438
439 if (state->domains == NULL) {
440 state->num_domains = 0;
441 return -1;
442 }
443 return 0;
444}
445
446NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32 *num_domains,
447 struct trustdom_info ***domains)
448{
449 struct list_trusted_domains_state state;
450
451 if (!secrets_init()) {
452 return NT_STATUS_ACCESS_DENIED;
453 }
454
455 state.num_domains = 0;
456
457 /*
458 * Make sure that a talloc context for the trustdom_info structs
459 * exists
460 */
461
462 if (!(state.domains = TALLOC_ARRAY(
463 mem_ctx, struct trustdom_info *, 1))) {
464 return NT_STATUS_NO_MEMORY;
465 }
466
467 db_ctx->traverse_read(db_ctx, list_trusted_domain, (void *)&state);
468
469 *num_domains = state.num_domains;
470 *domains = state.domains;
471 return NT_STATUS_OK;
472}
473
474/*******************************************************************************
475 Store a complete AFS keyfile into secrets.tdb.
476*******************************************************************************/
477
478bool secrets_store_afs_keyfile(const char *cell, const struct afs_keyfile *keyfile)
479{
480 fstring key;
481
482 if ((cell == NULL) || (keyfile == NULL))
483 return False;
484
485 if (ntohl(keyfile->nkeys) > SECRETS_AFS_MAXKEYS)
486 return False;
487
488 slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
489 return secrets_store(key, keyfile, sizeof(struct afs_keyfile));
490}
491
492/*******************************************************************************
493 Fetch the current (highest) AFS key from secrets.tdb
494*******************************************************************************/
495bool secrets_fetch_afs_key(const char *cell, struct afs_key *result)
496{
497 fstring key;
498 struct afs_keyfile *keyfile;
499 size_t size = 0;
500 uint32 i;
501
502 slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
503
504 keyfile = (struct afs_keyfile *)secrets_fetch(key, &size);
505
506 if (keyfile == NULL)
507 return False;
508
509 if (size != sizeof(struct afs_keyfile)) {
510 SAFE_FREE(keyfile);
511 return False;
512 }
513
514 i = ntohl(keyfile->nkeys);
515
516 if (i > SECRETS_AFS_MAXKEYS) {
517 SAFE_FREE(keyfile);
518 return False;
519 }
520
521 *result = keyfile->entry[i-1];
522
523 result->kvno = ntohl(result->kvno);
524
525 SAFE_FREE(keyfile);
526
527 return True;
528}
529
530/******************************************************************************
531 When kerberos is not available, choose between anonymous or
532 authenticated connections.
533
534 We need to use an authenticated connection if DCs have the
535 RestrictAnonymous registry entry set > 0, or the "Additional
536 restrictions for anonymous connections" set in the win2k Local
537 Security Policy.
538
539 Caller to free() result in domain, username, password
540*******************************************************************************/
541void secrets_fetch_ipc_userpass(char **username, char **domain, char **password)
542{
543 *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
544 *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
545 *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
546
547 if (*username && **username) {
548
549 if (!*domain || !**domain)
550 *domain = smb_xstrdup(lp_workgroup());
551
552 if (!*password || !**password)
553 *password = smb_xstrdup("");
554
555 DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
556 *domain, *username));
557
558 } else {
559 DEBUG(3, ("IPC$ connections done anonymously\n"));
560 *username = smb_xstrdup("");
561 *domain = smb_xstrdup("");
562 *password = smb_xstrdup("");
563 }
564}
565
566bool secrets_store_generic(const char *owner, const char *key, const char *secret)
567{
568 char *tdbkey = NULL;
569 bool ret;
570
571 if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
572 DEBUG(0, ("asprintf failed!\n"));
573 return False;
574 }
575
576 ret = secrets_store(tdbkey, secret, strlen(secret)+1);
577
578 SAFE_FREE(tdbkey);
579 return ret;
580}
581
582bool secrets_delete_generic(const char *owner, const char *key)
583{
584 char *tdbkey = NULL;
585 bool ret;
586
587 if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
588 DEBUG(0, ("asprintf failed!\n"));
589 return False;
590 }
591
592 ret = secrets_delete(tdbkey);
593
594 SAFE_FREE(tdbkey);
595 return ret;
596}
597
598/*******************************************************************
599 Find the ldap password.
600******************************************************************/
601
602char *secrets_fetch_generic(const char *owner, const char *key)
603{
604 char *secret = NULL;
605 char *tdbkey = NULL;
606
607 if (( ! owner) || ( ! key)) {
608 DEBUG(1, ("Invalid Parameters"));
609 return NULL;
610 }
611
612 if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
613 DEBUG(0, ("Out of memory!\n"));
614 return NULL;
615 }
616
617 secret = (char *)secrets_fetch(tdbkey, NULL);
618 SAFE_FREE(tdbkey);
619
620 return secret;
621}
622
Note: See TracBrowser for help on using the repository browser.