Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/passdb/secrets.c
Line
Count
Source
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 "../libcli/auth/libcli_auth.h"
28
#include "librpc/gen_ndr/ndr_secrets.h"
29
#include "secrets.h"
30
#include "dbwrap/dbwrap.h"
31
#include "dbwrap/dbwrap_open.h"
32
#include "../libcli/security/security.h"
33
#include "util_tdb.h"
34
#include "auth/credentials/credentials.h"
35
36
#undef DBGC_CLASS
37
0
#define DBGC_CLASS DBGC_PASSDB
38
39
static struct db_context *db_ctx;
40
41
/* open up the secrets database with specified private_dir path */
42
bool secrets_init_path(const char *private_dir)
43
0
{
44
0
  char *fname = NULL;
45
0
  TALLOC_CTX *frame;
46
47
0
  if (db_ctx != NULL) {
48
0
    return True;
49
0
  }
50
51
0
  if (private_dir == NULL) {
52
0
    return False;
53
0
  }
54
55
0
  frame = talloc_stackframe();
56
0
  fname = talloc_asprintf(frame, "%s/secrets.tdb", private_dir);
57
0
  if (fname == NULL) {
58
0
    TALLOC_FREE(frame);
59
0
    return False;
60
0
  }
61
62
0
  db_ctx = db_open(NULL, fname, 0,
63
0
       TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
64
0
       DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
65
66
0
  if (db_ctx == NULL) {
67
0
    DEBUG(0,("Failed to open %s\n", fname));
68
0
    TALLOC_FREE(frame);
69
0
    return False;
70
0
  }
71
72
0
  TALLOC_FREE(frame);
73
0
  return True;
74
0
}
75
76
/* open up the secrets database */
77
bool secrets_init(void)
78
0
{
79
0
  return secrets_init_path(lp_private_dir());
80
0
}
81
82
struct db_context *secrets_db_ctx(void)
83
0
{
84
0
  if (!secrets_init()) {
85
0
    return NULL;
86
0
  }
87
88
0
  return db_ctx;
89
0
}
90
91
/*
92
 * close secrets.tdb
93
 */
94
void secrets_shutdown(void)
95
0
{
96
0
  TALLOC_FREE(db_ctx);
97
0
}
98
99
/* read a entry from the secrets database - the caller must free the result
100
   if size is non-null then the size of the entry is put in there
101
 */
102
void *secrets_fetch(const char *key, size_t *size)
103
0
{
104
0
  TDB_DATA dbuf;
105
0
  void *result;
106
0
  NTSTATUS status;
107
108
0
  if (!secrets_init()) {
109
0
    return NULL;
110
0
  }
111
112
0
  status = dbwrap_fetch(db_ctx, talloc_tos(), string_tdb_data(key),
113
0
            &dbuf);
114
0
  if (!NT_STATUS_IS_OK(status)) {
115
0
    return NULL;
116
0
  }
117
118
0
  result = smb_memdup(dbuf.dptr, dbuf.dsize);
119
0
  if (result == NULL) {
120
0
    return NULL;
121
0
  }
122
  /*
123
   * secrets_fetch() is a generic code and may be used for sensitive data,
124
   * so clear the local dbuf.dptr memory via BURN_PTR_SIZE().
125
   * The future plan is to convert secrets_fetch() to talloc.
126
   * That would improve performance via:
127
   * - avoid smb_memdup() above, instead directly return dbuf.dptr
128
   * - BURN_PTR_SIZE() will be done not here but in the caller and only
129
   *   if the caller asks for sensitive data.
130
   */
131
0
  BURN_PTR_SIZE(dbuf.dptr, dbuf.dsize);
132
0
  TALLOC_FREE(dbuf.dptr);
133
134
0
  if (size) {
135
0
    *size = dbuf.dsize;
136
0
  }
137
138
0
  return result;
139
0
}
140
141
/* store a secrets entry
142
 */
143
bool secrets_store(const char *key, const void *data, size_t size)
144
0
{
145
0
  NTSTATUS status;
146
147
0
  if (!secrets_init()) {
148
0
    return false;
149
0
  }
150
151
0
  status = dbwrap_trans_store(db_ctx, string_tdb_data(key),
152
0
            make_tdb_data((const uint8_t *)data, size),
153
0
            TDB_REPLACE);
154
0
  return NT_STATUS_IS_OK(status);
155
0
}
156
157
bool secrets_store_creds(struct cli_credentials *creds)
158
0
{
159
0
  const char *p = NULL;
160
0
  bool ok;
161
162
0
  p = cli_credentials_get_username(creds);
163
0
  if (p == NULL) {
164
0
    return false;
165
0
  }
166
167
0
  ok = secrets_store(SECRETS_AUTH_USER, p, strlen(p) + 1);
168
0
  if (!ok) {
169
0
    DBG_ERR("Failed storing auth user name\n");
170
0
    return false;
171
0
  }
172
173
174
0
  p = cli_credentials_get_domain(creds);
175
0
  if (p == NULL) {
176
0
    return false;
177
0
  }
178
179
0
  ok = secrets_store(SECRETS_AUTH_DOMAIN, p, strlen(p) + 1);
180
0
  if (!ok) {
181
0
    DBG_ERR("Failed storing auth domain name\n");
182
0
    return false;
183
0
  }
184
185
186
0
  p = cli_credentials_get_password(creds);
187
0
  if (p == NULL) {
188
0
    return false;
189
0
  }
190
191
0
  ok = secrets_store(SECRETS_AUTH_PASSWORD, p, strlen(p) + 1);
192
0
  if (!ok) {
193
0
    DBG_ERR("Failed storing auth password\n");
194
0
    return false;
195
0
  }
196
197
0
  return true;
198
0
}
199
200
201
/* delete a secets database entry
202
 */
203
bool secrets_delete_entry(const char *key)
204
0
{
205
0
  NTSTATUS status;
206
0
  if (!secrets_init()) {
207
0
    return false;
208
0
  }
209
210
0
  status = dbwrap_trans_delete(db_ctx, string_tdb_data(key));
211
212
0
  return NT_STATUS_IS_OK(status);
213
0
}
214
215
/*
216
 * Deletes the key if it exists.
217
 */
218
bool secrets_delete(const char *key)
219
0
{
220
0
  bool exists;
221
222
0
  if (!secrets_init()) {
223
0
    return false;
224
0
  }
225
226
0
  exists = dbwrap_exists(db_ctx, string_tdb_data(key));
227
0
  if (!exists) {
228
0
    return true;
229
0
  }
230
231
0
  return secrets_delete_entry(key);
232
0
}
233
234
/**
235
 * Form a key for fetching a trusted domain password
236
 *
237
 * @param domain trusted domain name
238
 *
239
 * @return stored password's key
240
 **/
241
static char *trustdom_keystr(const char *domain)
242
0
{
243
0
  char *keystr;
244
245
0
  keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
246
0
              SECRETS_DOMTRUST_ACCT_PASS,
247
0
              domain);
248
0
  SMB_ASSERT(keystr != NULL);
249
0
  return keystr;
250
0
}
251
252
/************************************************************************
253
 Routine to get account password to trusted domain
254
************************************************************************/
255
256
bool secrets_fetch_trusted_domain_password(const char *domain, char** pwd,
257
                                           struct dom_sid *sid, time_t *pass_last_set_time)
258
0
{
259
0
  struct TRUSTED_DOM_PASS pass;
260
0
  enum ndr_err_code ndr_err;
261
262
  /* unpacking structures */
263
0
  DATA_BLOB blob;
264
265
  /* fetching trusted domain password structure */
266
0
  if (!(blob.data = (uint8_t *)secrets_fetch(trustdom_keystr(domain),
267
0
               &blob.length))) {
268
0
    DEBUG(5, ("secrets_fetch failed!\n"));
269
0
    return False;
270
0
  }
271
272
  /* unpack trusted domain password */
273
0
  ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &pass,
274
0
      (ndr_pull_flags_fn_t)ndr_pull_TRUSTED_DOM_PASS);
275
276
  /* This blob is NOT talloc based! */
277
0
  BURN_FREE(blob.data, blob.length);
278
279
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
280
0
    return false;
281
0
  }
282
283
0
  if (pass.pass != NULL) {
284
0
    talloc_keep_secret(discard_const_p(char, pass.pass));
285
0
  }
286
287
  /* the trust's password */
288
0
  if (pwd) {
289
0
    *pwd = SMB_STRDUP(pass.pass);
290
0
    if (!*pwd) {
291
0
      return False;
292
0
    }
293
0
  }
294
295
  /* last change time */
296
0
  if (pass_last_set_time) *pass_last_set_time = pass.mod_time;
297
298
  /* domain sid */
299
0
  if (sid != NULL) sid_copy(sid, &pass.domain_sid);
300
301
0
  return True;
302
0
}
303
304
/**
305
 * Routine to store the password for trusted domain
306
 *
307
 * @param domain remote domain name
308
 * @param pwd plain text password of trust relationship
309
 * @param sid remote domain sid
310
 *
311
 * @return true if succeeded
312
 **/
313
314
bool secrets_store_trusted_domain_password(const char* domain, const char* pwd,
315
                                           const struct dom_sid *sid)
316
0
{
317
0
  bool ret;
318
319
  /* packing structures */
320
0
  DATA_BLOB blob;
321
0
  enum ndr_err_code ndr_err;
322
0
  struct TRUSTED_DOM_PASS pass;
323
0
  ZERO_STRUCT(pass);
324
325
0
  pass.uni_name = domain;
326
0
  pass.uni_name_len = strlen(domain)+1;
327
328
  /* last change time */
329
0
  pass.mod_time = time(NULL);
330
331
  /* password of the trust */
332
0
  pass.pass_len = strlen(pwd);
333
0
  pass.pass = pwd;
334
335
  /* domain sid */
336
0
  sid_copy(&pass.domain_sid, sid);
337
338
0
  ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &pass,
339
0
      (ndr_push_flags_fn_t)ndr_push_TRUSTED_DOM_PASS);
340
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
341
0
    return false;
342
0
  }
343
344
0
  ret = secrets_store(trustdom_keystr(domain), blob.data, blob.length);
345
346
  /* This blob is talloc based. */
347
0
  data_blob_clear_free(&blob);
348
349
0
  return ret;
350
0
}
351
352
/************************************************************************
353
 Routine to delete the password for trusted domain
354
************************************************************************/
355
356
bool trusted_domain_password_delete(const char *domain)
357
0
{
358
0
  return secrets_delete_entry(trustdom_keystr(domain));
359
0
}
360
361
bool secrets_store_ldap_pw(const char* dn, char* pw)
362
0
{
363
0
  char *key = NULL;
364
0
  bool ret;
365
366
0
  if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, dn) < 0) {
367
0
    DEBUG(0, ("secrets_store_ldap_pw: asprintf failed!\n"));
368
0
    return False;
369
0
  }
370
371
0
  ret = secrets_store(key, pw, strlen(pw)+1);
372
373
0
  SAFE_FREE(key);
374
0
  return ret;
375
0
}
376
377
/*******************************************************************
378
 Find the ldap password.
379
******************************************************************/
380
381
bool fetch_ldap_pw(char **dn, char** pw)
382
0
{
383
0
  char *key = NULL;
384
0
  size_t size = 0;
385
386
0
  *dn = smb_xstrdup(lp_ldap_admin_dn());
387
388
0
  if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
389
0
    SAFE_FREE(*dn);
390
0
    DEBUG(0, ("fetch_ldap_pw: asprintf failed!\n"));
391
0
    return false;
392
0
  }
393
394
0
  *pw=(char *)secrets_fetch(key, &size);
395
0
  SAFE_FREE(key);
396
397
0
  if (*pw == NULL || size == 0 || (*pw)[size-1] != '\0') {
398
0
    DBG_ERR("No valid password for %s\n", *dn);
399
0
    BURN_FREE_STR(*pw);
400
0
    SAFE_FREE(*dn);
401
0
    return false;
402
0
  }
403
404
0
  return true;
405
0
}
406
407
/*******************************************************************************
408
 Store a complete AFS keyfile into secrets.tdb.
409
*******************************************************************************/
410
411
bool secrets_store_afs_keyfile(const char *cell, const struct afs_keyfile *keyfile)
412
0
{
413
0
  fstring key;
414
415
0
  if ((cell == NULL) || (keyfile == NULL))
416
0
    return False;
417
418
0
  if (ntohl(keyfile->nkeys) > SECRETS_AFS_MAXKEYS)
419
0
    return False;
420
421
0
  slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
422
0
  return secrets_store(key, keyfile, sizeof(struct afs_keyfile));
423
0
}
424
425
/*******************************************************************************
426
 Fetch the current (highest) AFS key from secrets.tdb
427
*******************************************************************************/
428
bool secrets_fetch_afs_key(const char *cell, struct afs_key *result)
429
0
{
430
0
  fstring key;
431
0
  struct afs_keyfile *keyfile;
432
0
  size_t size = 0;
433
0
  uint32_t i;
434
435
0
  slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
436
437
0
  keyfile = (struct afs_keyfile *)secrets_fetch(key, &size);
438
439
0
  if (keyfile == NULL)
440
0
    return False;
441
442
0
  if (size != sizeof(struct afs_keyfile)) {
443
0
    BURN_FREE(keyfile, sizeof(*keyfile));
444
0
    return False;
445
0
  }
446
447
0
  i = ntohl(keyfile->nkeys);
448
449
0
  if (i > SECRETS_AFS_MAXKEYS) {
450
0
    BURN_FREE(keyfile, sizeof(*keyfile));
451
0
    return False;
452
0
  }
453
454
0
  *result = keyfile->entry[i-1];
455
456
0
  result->kvno = ntohl(result->kvno);
457
458
0
  BURN_FREE(keyfile, sizeof(*keyfile));
459
460
0
  return True;
461
0
}
462
463
/******************************************************************************
464
  When kerberos is not available, choose between anonymous or
465
  authenticated connections.
466
467
  We need to use an authenticated connection if DCs have the
468
  RestrictAnonymous registry entry set > 0, or the "Additional
469
  restrictions for anonymous connections" set in the win2k Local
470
  Security Policy.
471
472
  Caller to free() result in domain, username, password
473
*******************************************************************************/
474
void secrets_fetch_ipc_userpass(char **username, char **domain, char **password)
475
0
{
476
0
  *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
477
0
  *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
478
0
  *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
479
480
0
  if (*username && **username) {
481
482
0
    if (!*domain || !**domain) {
483
0
      SAFE_FREE(*domain);
484
0
      *domain = smb_xstrdup(lp_workgroup());
485
0
    }
486
487
0
    if (!*password || !**password) {
488
0
      BURN_FREE_STR(*password);
489
0
      *password = smb_xstrdup("");
490
0
    }
491
492
0
    DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
493
0
        *domain, *username));
494
495
0
  } else {
496
0
    DEBUG(3, ("IPC$ connections done anonymously\n"));
497
0
    SAFE_FREE(*username);
498
0
    SAFE_FREE(*domain);
499
0
    BURN_FREE_STR(*password);
500
0
    *username = smb_xstrdup("");
501
0
    *domain = smb_xstrdup("");
502
0
    *password = smb_xstrdup("");
503
0
  }
504
0
}
505
506
bool secrets_store_generic(const char *owner, const char *key, const char *secret)
507
0
{
508
0
  char *tdbkey = NULL;
509
0
  bool ret;
510
511
0
  if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
512
0
    DEBUG(0, ("asprintf failed!\n"));
513
0
    return False;
514
0
  }
515
516
0
  ret = secrets_store(tdbkey, secret, strlen(secret)+1);
517
518
0
  SAFE_FREE(tdbkey);
519
0
  return ret;
520
0
}
521
522
/*******************************************************************
523
 Find the ldap password.
524
******************************************************************/
525
526
char *secrets_fetch_generic(const char *owner, const char *key)
527
0
{
528
0
  char *secret = NULL;
529
0
  char *tdbkey = NULL;
530
531
0
  if (( ! owner) || ( ! key)) {
532
0
    DEBUG(1, ("Invalid Parameters\n"));
533
0
    return NULL;
534
0
  }
535
536
0
  if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
537
0
    DEBUG(0, ("Out of memory!\n"));
538
0
    return NULL;
539
0
  }
540
541
0
  secret = (char *)secrets_fetch(tdbkey, NULL);
542
0
  SAFE_FREE(tdbkey);
543
544
0
  return secret;
545
0
}
546