Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/kdb/kdb5.c
39566 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/*
3
* Copyright 2006, 2009, 2010, 2016 by the Massachusetts Institute of
4
* Technology.
5
* All Rights Reserved.
6
*
7
* Export of this software from the United States of America may
8
* require a specific license from the United States Government.
9
* It is the responsibility of any person or organization contemplating
10
* export to obtain such a license before exporting.
11
*
12
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
* distribute this software and its documentation for any purpose and
14
* without fee is hereby granted, provided that the above copyright
15
* notice appear in all copies and that both that copyright notice and
16
* this permission notice appear in supporting documentation, and that
17
* the name of M.I.T. not be used in advertising or publicity pertaining
18
* to distribution of the software without specific, written prior
19
* permission. Furthermore if you modify this software you must label
20
* your software as modified software and not distribute it in such a
21
* fashion that it might be confused with the original M.I.T. software.
22
* M.I.T. makes no representations about the suitability of
23
* this software for any purpose. It is provided "as is" without express
24
* or implied warranty.
25
*/
26
27
/*
28
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
29
* Use is subject to license terms.
30
*/
31
32
/*
33
* This code was based on code donated to MIT by Novell for
34
* distribution under the MIT license.
35
*/
36
37
/*
38
* Include files
39
*/
40
41
#include <k5-int.h>
42
#include "kdb5.h"
43
#include "kdb_log.h"
44
#include "kdb5int.h"
45
46
/* Currently DB2 policy related errors are exported from DAL. But
47
other databases should set_err function to return string. */
48
#include "adb_err.h"
49
50
/*
51
* internal static variable
52
*/
53
54
static k5_mutex_t db_lock = K5_MUTEX_PARTIAL_INITIALIZER;
55
56
static db_library lib_list;
57
58
/*
59
* Helper Functions
60
*/
61
62
MAKE_INIT_FUNCTION(kdb_init_lock_list);
63
MAKE_FINI_FUNCTION(kdb_fini_lock_list);
64
65
static void
66
free_mkey_list(krb5_context context, krb5_keylist_node *mkey_list)
67
{
68
krb5_keylist_node *cur, *next;
69
70
for (cur = mkey_list; cur != NULL; cur = next) {
71
next = cur->next;
72
krb5_free_keyblock_contents(context, &cur->keyblock);
73
free(cur);
74
}
75
}
76
77
int
78
kdb_init_lock_list(void)
79
{
80
return k5_mutex_finish_init(&db_lock);
81
}
82
83
static int
84
kdb_lock_list(void)
85
{
86
int err;
87
err = CALL_INIT_FUNCTION (kdb_init_lock_list);
88
if (err)
89
return err;
90
k5_mutex_lock(&db_lock);
91
return 0;
92
}
93
94
void
95
kdb_fini_lock_list(void)
96
{
97
if (INITIALIZER_RAN(kdb_init_lock_list))
98
k5_mutex_destroy(&db_lock);
99
}
100
101
static void
102
kdb_unlock_list(void)
103
{
104
k5_mutex_unlock(&db_lock);
105
}
106
107
/* Return true if the ulog is mapped in the primary role. */
108
static inline krb5_boolean
109
logging(krb5_context context)
110
{
111
kdb_log_context *log_ctx = context->kdblog_context;
112
113
return log_ctx != NULL && log_ctx->iproprole == IPROP_PRIMARY &&
114
log_ctx->ulog != NULL;
115
}
116
117
void
118
krb5_dbe_free_key_data_contents(krb5_context context, krb5_key_data *key)
119
{
120
int i, idx;
121
122
if (key) {
123
idx = (key->key_data_ver == 1 ? 1 : 2);
124
for (i = 0; i < idx; i++) {
125
if (key->key_data_contents[i]) {
126
zap(key->key_data_contents[i], key->key_data_length[i]);
127
free(key->key_data_contents[i]);
128
}
129
}
130
}
131
return;
132
}
133
134
void
135
krb5_dbe_free_key_list(krb5_context context, krb5_keylist_node *val)
136
{
137
krb5_keylist_node *temp = val, *prev;
138
139
while (temp != NULL) {
140
prev = temp;
141
temp = temp->next;
142
krb5_free_keyblock_contents(context, &(prev->keyblock));
143
free(prev);
144
}
145
}
146
147
void
148
krb5_dbe_free_actkvno_list(krb5_context context, krb5_actkvno_node *val)
149
{
150
krb5_actkvno_node *temp = val, *prev;
151
152
while (temp != NULL) {
153
prev = temp;
154
temp = temp->next;
155
free(prev);
156
}
157
}
158
159
void
160
krb5_dbe_free_mkey_aux_list(krb5_context context, krb5_mkey_aux_node *val)
161
{
162
krb5_mkey_aux_node *temp = val, *prev;
163
164
while (temp != NULL) {
165
prev = temp;
166
temp = temp->next;
167
krb5_dbe_free_key_data_contents(context, &prev->latest_mkey);
168
free(prev);
169
}
170
}
171
172
void
173
krb5_dbe_free_tl_data(krb5_context context, krb5_tl_data *tl_data)
174
{
175
if (tl_data) {
176
if (tl_data->tl_data_contents)
177
free(tl_data->tl_data_contents);
178
free(tl_data);
179
}
180
}
181
182
void
183
krb5_dbe_free_strings(krb5_context context, krb5_string_attr *strings,
184
int count)
185
{
186
int i;
187
188
if (strings == NULL)
189
return;
190
for (i = 0; i < count; i++) {
191
free(strings[i].key);
192
free(strings[i].value);
193
}
194
free(strings);
195
}
196
197
void
198
krb5_dbe_free_string(krb5_context context, char *string)
199
{
200
free(string);
201
}
202
203
/* Set *section to the appropriate section to use for a database module's
204
* profile queries. The caller must free the result. */
205
static krb5_error_code
206
get_conf_section(krb5_context context, char **section)
207
{
208
krb5_error_code status;
209
char *result = NULL, *value = NULL, *defrealm;
210
211
*section = NULL;
212
213
status = krb5_get_default_realm(context, &defrealm);
214
if (status) {
215
k5_setmsg(context, KRB5_KDB_SERVER_INTERNAL_ERR,
216
_("No default realm set; cannot initialize KDB"));
217
return KRB5_KDB_SERVER_INTERNAL_ERR;
218
}
219
status = profile_get_string(context->profile,
220
/* realms */
221
KDB_REALM_SECTION,
222
defrealm,
223
/* under the realm name, database_module */
224
KDB_MODULE_POINTER,
225
/* default value is the realm name itself */
226
defrealm,
227
&value);
228
krb5_free_default_realm(context, defrealm);
229
if (status)
230
return status;
231
result = strdup(value);
232
profile_release_string(value);
233
if (result == NULL)
234
return ENOMEM;
235
*section = result;
236
return 0;
237
}
238
239
static krb5_error_code
240
kdb_get_library_name(krb5_context kcontext, char **libname_out)
241
{
242
krb5_error_code status = 0;
243
char *value = NULL, *lib = NULL, *defrealm = NULL;
244
245
*libname_out = NULL;
246
247
status = krb5_get_default_realm(kcontext, &defrealm);
248
if (status)
249
goto clean_n_exit;
250
status = profile_get_string(kcontext->profile,
251
/* realms */
252
KDB_REALM_SECTION,
253
defrealm,
254
/* under the realm name, database_module */
255
KDB_MODULE_POINTER,
256
/* default value is the realm name itself */
257
defrealm,
258
&value);
259
if (status)
260
goto clean_n_exit;
261
262
#define DB2_NAME "db2"
263
/* we got the module section. Get the library name from the module */
264
status = profile_get_string(kcontext->profile, KDB_MODULE_SECTION, value,
265
KDB_LIB_POINTER,
266
/* default to db2 */
267
DB2_NAME,
268
&lib);
269
270
if (status) {
271
goto clean_n_exit;
272
}
273
274
*libname_out = strdup(lib);
275
if (*libname_out == NULL)
276
status = ENOMEM;
277
278
clean_n_exit:
279
krb5_free_default_realm(kcontext, defrealm);
280
profile_release_string(value);
281
profile_release_string(lib);
282
return status;
283
}
284
285
static void
286
copy_vtable(const kdb_vftabl *in, kdb_vftabl *out)
287
{
288
/* Copy fields for minor version 0. */
289
out->maj_ver = in->maj_ver;
290
out->min_ver = in->min_ver;
291
out->init_library = in->init_library;
292
out->fini_library = in->fini_library;
293
out->init_module = in->init_module;
294
out->fini_module = in->fini_module;
295
out->create = in->create;
296
out->destroy = in->destroy;
297
out->get_age = in->get_age;
298
out->lock = in->lock;
299
out->unlock = in->unlock;
300
out->get_principal = in->get_principal;
301
out->put_principal = in->put_principal;
302
out->delete_principal = in->delete_principal;
303
out->rename_principal = in->rename_principal;
304
out->iterate = in->iterate;
305
out->create_policy = in->create_policy;
306
out->get_policy = in->get_policy;
307
out->put_policy = in->put_policy;
308
out->iter_policy = in->iter_policy;
309
out->delete_policy = in->delete_policy;
310
out->fetch_master_key = in->fetch_master_key;
311
out->fetch_master_key_list = in->fetch_master_key_list;
312
out->store_master_key_list = in->store_master_key_list;
313
out->dbe_search_enctype = in->dbe_search_enctype;
314
out->change_pwd = in->change_pwd;
315
out->promote_db = in->promote_db;
316
out->decrypt_key_data = in->decrypt_key_data;
317
out->encrypt_key_data = in->encrypt_key_data;
318
out->check_transited_realms = in->check_transited_realms;
319
out->check_policy_as = in->check_policy_as;
320
out->check_policy_tgs = in->check_policy_tgs;
321
out->audit_as_req = in->audit_as_req;
322
out->refresh_config = in->refresh_config;
323
out->check_allowed_to_delegate = in->check_allowed_to_delegate;
324
out->free_principal_e_data = in->free_principal_e_data;
325
out->get_s4u_x509_principal = in->get_s4u_x509_principal;
326
out->allowed_to_delegate_from = in->allowed_to_delegate_from;
327
out->issue_pac = in->issue_pac;
328
329
/* Set defaults for optional fields. */
330
if (out->fetch_master_key == NULL)
331
out->fetch_master_key = krb5_db_def_fetch_mkey;
332
if (out->fetch_master_key_list == NULL)
333
out->fetch_master_key_list = krb5_def_fetch_mkey_list;
334
if (out->store_master_key_list == NULL)
335
out->store_master_key_list = krb5_def_store_mkey_list;
336
if (out->dbe_search_enctype == NULL)
337
out->dbe_search_enctype = krb5_dbe_def_search_enctype;
338
if (out->change_pwd == NULL)
339
out->change_pwd = krb5_dbe_def_cpw;
340
if (out->decrypt_key_data == NULL)
341
out->decrypt_key_data = krb5_dbe_def_decrypt_key_data;
342
if (out->encrypt_key_data == NULL)
343
out->encrypt_key_data = krb5_dbe_def_encrypt_key_data;
344
if (out->rename_principal == NULL)
345
out->rename_principal = krb5_db_def_rename_principal;
346
}
347
348
#ifdef STATIC_PLUGINS
349
350
extern kdb_vftabl krb5_db2_kdb_function_table;
351
#ifdef ENABLE_LDAP
352
extern kdb_vftabl krb5_ldap_kdb_function_table;
353
#endif
354
355
static krb5_error_code
356
load_library(krb5_context kcontext, const char *lib_name, db_library *libptr)
357
{
358
krb5_error_code status;
359
db_library lib;
360
kdb_vftabl *vftabl_addr = NULL;
361
362
if (strcmp(lib_name, "db2") == 0)
363
vftabl_addr = &krb5_db2_kdb_function_table;
364
#ifdef ENABLE_LDAP
365
if (strcmp(lib_name, "kldap") == 0)
366
vftabl_addr = &krb5_ldap_kdb_function_table;
367
#endif
368
if (!vftabl_addr) {
369
k5_setmsg(kcontext, KRB5_KDB_DBTYPE_NOTFOUND,
370
_("Unable to find requested database type: %s"), lib_name);
371
return KRB5_PLUGIN_OP_NOTSUPP;
372
}
373
374
lib = calloc(1, sizeof(*lib));
375
if (lib == NULL)
376
return ENOMEM;
377
378
strlcpy(lib->name, lib_name, sizeof(lib->name));
379
copy_vtable(vftabl_addr, &lib->vftabl);
380
381
status = lib->vftabl.init_library();
382
if (status)
383
goto cleanup;
384
385
*libptr = lib;
386
return 0;
387
388
cleanup:
389
free(lib);
390
return status;
391
}
392
393
#else /* KDB5_STATIC_LINK*/
394
395
static char *db_dl_location[] = DEFAULT_KDB_LIB_PATH;
396
#define db_dl_n_locations (sizeof(db_dl_location) / sizeof(db_dl_location[0]))
397
398
static krb5_error_code
399
load_library(krb5_context kcontext, const char *lib_name, db_library *lib)
400
{
401
krb5_error_code status = 0;
402
int ndx;
403
void **vftabl_addrs = NULL;
404
/* N.B.: If this is "const" but not "static", the Solaris 10
405
native compiler has trouble building the library because of
406
absolute relocations needed in read-only section ".rodata".
407
When it's static, it goes into ".picdata", which is
408
read-write. */
409
static const char *const dbpath_names[] = {
410
KDB_MODULE_SECTION, KRB5_CONF_DB_MODULE_DIR, NULL,
411
};
412
const char *filebases[2];
413
char **profpath = NULL;
414
char **path = NULL;
415
416
filebases[0] = lib_name;
417
filebases[1] = NULL;
418
419
*lib = calloc((size_t) 1, sizeof(**lib));
420
if (*lib == NULL)
421
return ENOMEM;
422
423
strlcpy((*lib)->name, lib_name, sizeof((*lib)->name));
424
425
/* Fetch the list of directories specified in the config
426
file(s) first. */
427
status = profile_get_values(kcontext->profile, dbpath_names, &profpath);
428
if (status != 0 && status != PROF_NO_RELATION)
429
goto clean_n_exit;
430
ndx = 0;
431
if (profpath)
432
while (profpath[ndx] != NULL)
433
ndx++;
434
435
path = calloc(ndx + db_dl_n_locations, sizeof (char *));
436
if (path == NULL) {
437
status = ENOMEM;
438
goto clean_n_exit;
439
}
440
if (ndx)
441
memcpy(path, profpath, ndx * sizeof(profpath[0]));
442
memcpy(path + ndx, db_dl_location, db_dl_n_locations * sizeof(char *));
443
status = 0;
444
445
if ((status = krb5int_open_plugin_dirs ((const char **) path,
446
filebases,
447
&(*lib)->dl_dir_handle, &kcontext->err))) {
448
status = KRB5_KDB_DBTYPE_NOTFOUND;
449
k5_prependmsg(kcontext, status,
450
_("Unable to find requested database type"));
451
goto clean_n_exit;
452
}
453
454
if ((status = krb5int_get_plugin_dir_data (&(*lib)->dl_dir_handle, "kdb_function_table",
455
&vftabl_addrs, &kcontext->err))) {
456
status = KRB5_KDB_DBTYPE_INIT;
457
k5_prependmsg(kcontext, status,
458
_("plugin symbol 'kdb_function_table' lookup failed"));
459
goto clean_n_exit;
460
}
461
462
if (vftabl_addrs[0] == NULL) {
463
/* No plugins! */
464
status = KRB5_KDB_DBTYPE_NOTFOUND;
465
k5_setmsg(kcontext, status,
466
_("Unable to load requested database module '%s': plugin "
467
"symbol 'kdb_function_table' not found"), lib_name);
468
goto clean_n_exit;
469
}
470
471
if (((kdb_vftabl *)vftabl_addrs[0])->maj_ver !=
472
KRB5_KDB_DAL_MAJOR_VERSION) {
473
status = KRB5_KDB_DBTYPE_MISMATCH;
474
goto clean_n_exit;
475
}
476
477
copy_vtable(vftabl_addrs[0], &(*lib)->vftabl);
478
479
if ((status = (*lib)->vftabl.init_library()))
480
goto clean_n_exit;
481
482
clean_n_exit:
483
krb5int_free_plugin_dir_data(vftabl_addrs);
484
/* Both of these DTRT with NULL. */
485
profile_free_list(profpath);
486
free(path);
487
if (status && *lib) {
488
if (PLUGIN_DIR_OPEN((&(*lib)->dl_dir_handle)))
489
krb5int_close_plugin_dirs (&(*lib)->dl_dir_handle);
490
free(*lib);
491
*lib = NULL;
492
}
493
return status;
494
}
495
496
#endif /* end of _KDB5_STATIC_LINK */
497
498
static krb5_error_code
499
find_library(krb5_context kcontext, const char *lib_name, db_library *lib)
500
{
501
/* lock here so that no two threads try to do the same at the same time */
502
krb5_error_code status = 0;
503
int locked = 0;
504
db_library curr_elt, prev_elt = NULL;
505
static int kdb_db2_pol_err_loaded = 0;
506
507
if (!strcmp(DB2_NAME, lib_name) && (kdb_db2_pol_err_loaded == 0)) {
508
initialize_adb_error_table();
509
kdb_db2_pol_err_loaded = 1;
510
}
511
512
if ((status = kdb_lock_list()) != 0)
513
goto clean_n_exit;
514
locked = 1;
515
516
curr_elt = lib_list;
517
while (curr_elt != NULL) {
518
if (strcmp(lib_name, curr_elt->name) == 0) {
519
*lib = curr_elt;
520
goto clean_n_exit;
521
}
522
prev_elt = curr_elt;
523
curr_elt = curr_elt->next;
524
}
525
526
/* module not found. create and add to list */
527
status = load_library(kcontext, lib_name, lib);
528
if (status)
529
goto clean_n_exit;
530
531
if (prev_elt) {
532
/* prev_elt points to the last element in the list */
533
prev_elt->next = *lib;
534
(*lib)->prev = prev_elt;
535
} else {
536
lib_list = *lib;
537
}
538
539
clean_n_exit:
540
if (*lib)
541
(*lib)->reference_cnt++;
542
543
if (locked)
544
kdb_unlock_list();
545
546
return status;
547
}
548
549
static krb5_error_code
550
kdb_free_library(db_library lib)
551
{
552
krb5_error_code status = 0;
553
int locked = 0;
554
555
if ((status = kdb_lock_list()) != 0)
556
goto clean_n_exit;
557
locked = 1;
558
559
lib->reference_cnt--;
560
561
if (lib->reference_cnt == 0) {
562
status = lib->vftabl.fini_library();
563
if (status)
564
goto clean_n_exit;
565
566
/* close the library */
567
if (PLUGIN_DIR_OPEN((&lib->dl_dir_handle)))
568
krb5int_close_plugin_dirs (&lib->dl_dir_handle);
569
570
if (lib->prev == NULL)
571
lib_list = lib->next; /* first element in the list */
572
else
573
lib->prev->next = lib->next;
574
575
if (lib->next)
576
lib->next->prev = lib->prev;
577
free(lib);
578
}
579
580
clean_n_exit:
581
if (locked)
582
kdb_unlock_list();
583
584
return status;
585
}
586
587
krb5_error_code
588
krb5_db_load_module(krb5_context kcontext, const char *name)
589
{
590
krb5_error_code ret;
591
db_library lib = NULL;
592
kdb5_dal_handle *dal_handle = NULL;
593
594
if (name == NULL)
595
return EINVAL;
596
if (kcontext->dal_handle != NULL)
597
return EEXIST;
598
599
dal_handle = k5alloc(sizeof(*dal_handle), &ret);
600
if (dal_handle == NULL)
601
goto cleanup;
602
603
ret = find_library(kcontext, name, &lib);
604
if (ret)
605
goto cleanup;
606
607
dal_handle->lib_handle = lib;
608
kcontext->dal_handle = dal_handle;
609
lib = NULL;
610
dal_handle = NULL;
611
612
cleanup:
613
free(dal_handle);
614
if (lib != NULL)
615
kdb_free_library(lib);
616
return ret;
617
}
618
619
krb5_error_code
620
krb5_db_setup_lib_handle(krb5_context kcontext)
621
{
622
char *library = NULL;
623
krb5_error_code ret;
624
625
ret = kdb_get_library_name(kcontext, &library);
626
if (library == NULL) {
627
k5_prependmsg(kcontext, ret, _("Cannot initialize database library"));
628
return ret;
629
}
630
631
ret = krb5_db_load_module(kcontext, library);
632
free(library);
633
return ret;
634
}
635
636
static krb5_error_code
637
kdb_free_lib_handle(krb5_context kcontext)
638
{
639
krb5_error_code status = 0;
640
641
status = kdb_free_library(kcontext->dal_handle->lib_handle);
642
if (status)
643
return status;
644
645
free_mkey_list(kcontext, kcontext->dal_handle->master_keylist);
646
krb5_free_principal(kcontext, kcontext->dal_handle->master_princ);
647
free(kcontext->dal_handle);
648
kcontext->dal_handle = NULL;
649
return 0;
650
}
651
652
static krb5_error_code
653
get_vftabl(krb5_context kcontext, kdb_vftabl **vftabl_ptr)
654
{
655
krb5_error_code status;
656
657
*vftabl_ptr = NULL;
658
if (kcontext->dal_handle == NULL) {
659
status = krb5_db_setup_lib_handle(kcontext);
660
if (status)
661
return status;
662
}
663
*vftabl_ptr = &kcontext->dal_handle->lib_handle->vftabl;
664
return 0;
665
}
666
667
/*
668
* External functions... DAL API
669
*/
670
krb5_error_code
671
krb5_db_open(krb5_context kcontext, char **db_args, int mode)
672
{
673
krb5_error_code status;
674
char *section;
675
kdb_vftabl *v;
676
677
status = get_vftabl(kcontext, &v);
678
if (status)
679
return status;
680
status = get_conf_section(kcontext, &section);
681
if (status)
682
return status;
683
status = v->init_module(kcontext, section, db_args, mode);
684
free(section);
685
if (status)
686
(void)krb5_db_fini(kcontext);
687
return status;
688
}
689
690
krb5_error_code
691
krb5_db_inited(krb5_context kcontext)
692
{
693
return !(kcontext && kcontext->dal_handle &&
694
kcontext->dal_handle->db_context);
695
}
696
697
krb5_error_code
698
krb5_db_create(krb5_context kcontext, char **db_args)
699
{
700
krb5_error_code status;
701
char *section;
702
kdb_vftabl *v;
703
704
status = get_vftabl(kcontext, &v);
705
if (status)
706
return status;
707
if (v->create == NULL)
708
return KRB5_PLUGIN_OP_NOTSUPP;
709
status = get_conf_section(kcontext, &section);
710
if (status)
711
return status;
712
status = v->create(kcontext, section, db_args);
713
free(section);
714
if (status)
715
(void)krb5_db_fini(kcontext);
716
return status;
717
}
718
719
krb5_error_code
720
krb5_db_fini(krb5_context kcontext)
721
{
722
krb5_error_code status = 0;
723
kdb_vftabl *v;
724
725
/* Do nothing if module was never loaded. */
726
if (kcontext->dal_handle == NULL)
727
return 0;
728
729
v = &kcontext->dal_handle->lib_handle->vftabl;
730
status = v->fini_module(kcontext);
731
732
if (status)
733
return status;
734
735
return kdb_free_lib_handle(kcontext);
736
}
737
738
krb5_error_code
739
krb5_db_destroy(krb5_context kcontext, char **db_args)
740
{
741
krb5_error_code status;
742
char *section;
743
kdb_vftabl *v;
744
745
status = get_vftabl(kcontext, &v);
746
if (status)
747
return status;
748
if (v->destroy == NULL)
749
return KRB5_PLUGIN_OP_NOTSUPP;
750
status = get_conf_section(kcontext, &section);
751
if (status)
752
return status;
753
status = v->destroy(kcontext, section, db_args);
754
free(section);
755
return status;
756
}
757
758
krb5_error_code
759
krb5_db_get_age(krb5_context kcontext, char *db_name, time_t *t)
760
{
761
krb5_error_code status = 0;
762
kdb_vftabl *v;
763
764
status = get_vftabl(kcontext, &v);
765
if (status)
766
return status;
767
if (v->get_age == NULL)
768
return KRB5_PLUGIN_OP_NOTSUPP;
769
return v->get_age(kcontext, db_name, t);
770
}
771
772
krb5_error_code
773
krb5_db_lock(krb5_context kcontext, int lock_mode)
774
{
775
krb5_error_code status = 0;
776
kdb_vftabl *v;
777
778
status = get_vftabl(kcontext, &v);
779
if (status)
780
return status;
781
if (v->lock == NULL)
782
return KRB5_PLUGIN_OP_NOTSUPP;
783
return v->lock(kcontext, lock_mode);
784
}
785
786
krb5_error_code
787
krb5_db_unlock(krb5_context kcontext)
788
{
789
krb5_error_code status = 0;
790
kdb_vftabl *v;
791
792
status = get_vftabl(kcontext, &v);
793
if (status)
794
return status;
795
if (v->unlock == NULL)
796
return KRB5_PLUGIN_OP_NOTSUPP;
797
return v->unlock(kcontext);
798
}
799
800
#define MAX_ALIAS_DEPTH 10
801
802
krb5_error_code
803
krb5_db_get_principal(krb5_context kcontext, krb5_const_principal search_for,
804
unsigned int flags, krb5_db_entry **entry_out)
805
{
806
krb5_error_code status = 0;
807
kdb_vftabl *v;
808
krb5_db_entry *entry;
809
krb5_principal alias_target;
810
int alias_depth = 0;
811
812
*entry_out = NULL;
813
status = get_vftabl(kcontext, &v);
814
if (status)
815
return status;
816
if (v->get_principal == NULL)
817
return KRB5_PLUGIN_OP_NOTSUPP;
818
819
status = v->get_principal(kcontext, search_for, flags, &entry);
820
if (status)
821
return status;
822
823
/* Resolve any aliases up to the maximum depth. */
824
for (;;) {
825
status = krb5_dbe_read_alias(kcontext, entry, &alias_target);
826
if (status)
827
return status;
828
if (alias_target == NULL)
829
break;
830
krb5_db_free_principal(kcontext, entry);
831
status = (++alias_depth > MAX_ALIAS_DEPTH) ? KRB5_KDB_NOENTRY :
832
v->get_principal(kcontext, alias_target, flags, &entry);
833
krb5_free_principal(kcontext, alias_target);
834
if (status)
835
return status;
836
}
837
838
/* Sort the keys in the db entry as some parts of krb5 expect it to be. */
839
if (entry->key_data != NULL)
840
krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data);
841
842
*entry_out = entry;
843
return 0;
844
}
845
846
static void
847
free_tl_data(krb5_tl_data *list)
848
{
849
krb5_tl_data *next;
850
851
for (; list != NULL; list = next) {
852
next = list->tl_data_next;
853
free(list->tl_data_contents);
854
free(list);
855
}
856
}
857
858
void
859
krb5_db_free_principal(krb5_context kcontext, krb5_db_entry *entry)
860
{
861
kdb_vftabl *v;
862
int i;
863
864
if (entry == NULL)
865
return;
866
if (entry->e_data != NULL) {
867
if (get_vftabl(kcontext, &v) == 0 && v->free_principal_e_data != NULL)
868
v->free_principal_e_data(kcontext, entry->e_data);
869
else
870
free(entry->e_data);
871
}
872
krb5_free_principal(kcontext, entry->princ);
873
free_tl_data(entry->tl_data);
874
for (i = 0; i < entry->n_key_data; i++)
875
krb5_dbe_free_key_data_contents(kcontext, &entry->key_data[i]);
876
free(entry->key_data);
877
free(entry);
878
}
879
880
static void
881
free_db_args(char **db_args)
882
{
883
size_t i;
884
885
if (db_args) {
886
for (i = 0; db_args[i]; i++)
887
free(db_args[i]);
888
free(db_args);
889
}
890
}
891
892
static krb5_error_code
893
extract_db_args_from_tl_data(krb5_context kcontext, krb5_tl_data **start,
894
krb5_int16 *count, char ***db_argsp)
895
{
896
char **db_args = NULL;
897
size_t db_args_size = 0;
898
krb5_tl_data *prev, *curr, *next;
899
krb5_error_code status;
900
901
/* Giving db_args as part of tl data causes db2 to store the
902
tl_data as such. To prevent this, tl_data is collated and
903
passed as a separate argument. Currently supports only one
904
principal, but passing it as a separate argument makes it
905
difficult for kadmin remote to pass arguments to server. */
906
prev = NULL, curr = *start;
907
while (curr) {
908
if (curr->tl_data_type == KRB5_TL_DB_ARGS) {
909
char **t;
910
/* Since this is expected to be NULL terminated string and
911
this could come from any client, do a check before
912
passing it to db. */
913
if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] !=
914
'\0') {
915
/* Not null terminated. Dangerous input. */
916
status = EINVAL;
917
goto clean_n_exit;
918
}
919
920
db_args_size++;
921
t = realloc(db_args, sizeof(char *) * (db_args_size + 1)); /* 1 for NULL */
922
if (t == NULL) {
923
status = ENOMEM;
924
goto clean_n_exit;
925
}
926
927
db_args = t;
928
db_args[db_args_size - 1] = (char *) curr->tl_data_contents;
929
db_args[db_args_size] = NULL;
930
931
next = curr->tl_data_next;
932
if (prev == NULL) {
933
/* current node is the first in the linked list. remove it */
934
*start = curr->tl_data_next;
935
} else {
936
prev->tl_data_next = curr->tl_data_next;
937
}
938
(*count)--;
939
free(curr);
940
941
/* previous does not change */
942
curr = next;
943
} else {
944
prev = curr;
945
curr = curr->tl_data_next;
946
}
947
}
948
status = 0;
949
clean_n_exit:
950
if (status != 0) {
951
free_db_args(db_args);
952
db_args = NULL;
953
}
954
*db_argsp = db_args;
955
return status;
956
}
957
958
krb5_error_code
959
krb5int_put_principal_no_log(krb5_context kcontext, krb5_db_entry *entry)
960
{
961
kdb_vftabl *v;
962
krb5_error_code status;
963
char **db_args;
964
965
status = get_vftabl(kcontext, &v);
966
if (status)
967
return status;
968
if (v->put_principal == NULL)
969
return KRB5_PLUGIN_OP_NOTSUPP;
970
status = extract_db_args_from_tl_data(kcontext, &entry->tl_data,
971
&entry->n_tl_data,
972
&db_args);
973
if (status)
974
return status;
975
status = v->put_principal(kcontext, entry, db_args);
976
free_db_args(db_args);
977
return status;
978
}
979
980
krb5_error_code
981
krb5_db_put_principal(krb5_context kcontext, krb5_db_entry *entry)
982
{
983
krb5_error_code status = 0;
984
kdb_incr_update_t *upd = NULL;
985
char *princ_name = NULL;
986
987
if (logging(kcontext)) {
988
upd = k5alloc(sizeof(*upd), &status);
989
if (upd == NULL)
990
goto cleanup;
991
if ((status = ulog_conv_2logentry(kcontext, entry, upd)))
992
goto cleanup;
993
994
status = krb5_unparse_name(kcontext, entry->princ, &princ_name);
995
if (status != 0)
996
goto cleanup;
997
998
upd->kdb_princ_name.utf8str_t_val = princ_name;
999
upd->kdb_princ_name.utf8str_t_len = strlen(princ_name);
1000
}
1001
1002
status = krb5int_put_principal_no_log(kcontext, entry);
1003
if (status)
1004
goto cleanup;
1005
1006
if (logging(kcontext))
1007
status = ulog_add_update(kcontext, upd);
1008
1009
cleanup:
1010
ulog_free_entries(upd, 1);
1011
return status;
1012
}
1013
1014
krb5_error_code
1015
krb5int_delete_principal_no_log(krb5_context kcontext,
1016
krb5_principal search_for)
1017
{
1018
kdb_vftabl *v;
1019
krb5_error_code status;
1020
1021
status = get_vftabl(kcontext, &v);
1022
if (status)
1023
return status;
1024
if (v->delete_principal == NULL)
1025
return KRB5_PLUGIN_OP_NOTSUPP;
1026
return v->delete_principal(kcontext, search_for);
1027
}
1028
1029
krb5_error_code
1030
krb5_db_delete_principal(krb5_context kcontext, krb5_principal search_for)
1031
{
1032
krb5_error_code status = 0;
1033
kdb_incr_update_t upd;
1034
char *princ_name = NULL;
1035
1036
status = krb5int_delete_principal_no_log(kcontext, search_for);
1037
if (status || !logging(kcontext))
1038
return status;
1039
1040
status = krb5_unparse_name(kcontext, search_for, &princ_name);
1041
if (status)
1042
return status;
1043
1044
memset(&upd, 0, sizeof(kdb_incr_update_t));
1045
upd.kdb_princ_name.utf8str_t_val = princ_name;
1046
upd.kdb_princ_name.utf8str_t_len = strlen(princ_name);
1047
upd.kdb_deleted = TRUE;
1048
1049
status = ulog_add_update(kcontext, &upd);
1050
free(princ_name);
1051
return status;
1052
}
1053
1054
krb5_error_code
1055
krb5_db_rename_principal(krb5_context kcontext, krb5_principal source,
1056
krb5_principal target)
1057
{
1058
kdb_vftabl *v;
1059
krb5_error_code status;
1060
krb5_db_entry *entry;
1061
krb5_boolean eq;
1062
1063
status = get_vftabl(kcontext, &v);
1064
if (status)
1065
return status;
1066
1067
/*
1068
* If the default rename function isn't used and logging is enabled, iprop
1069
* would fail since it doesn't formally support renaming. In that case
1070
* return KRB5_PLUGIN_OP_NOTSUPP.
1071
*/
1072
if (v->rename_principal != krb5_db_def_rename_principal &&
1073
logging(kcontext))
1074
return KRB5_PLUGIN_OP_NOTSUPP;
1075
1076
/* Disallow the operation if source is an alias. */
1077
status = krb5_db_get_principal(kcontext, source, 0, &entry);
1078
if (status)
1079
return status;
1080
eq = krb5_principal_compare(kcontext, entry->princ, source);
1081
krb5_db_free_principal(kcontext, entry);
1082
if (!eq)
1083
return KRB5_KDB_ALIAS_UNSUPPORTED;
1084
1085
status = krb5_db_get_principal(kcontext, target, 0, &entry);
1086
if (status == 0) {
1087
krb5_db_free_principal(kcontext, entry);
1088
return KRB5_KDB_INUSE;
1089
}
1090
1091
return v->rename_principal(kcontext, source, target);
1092
}
1093
1094
/*
1095
* Use a proxy function for iterate so that we can sort the keys before sending
1096
* them to the callback.
1097
*/
1098
struct callback_proxy_args {
1099
int (*func)(krb5_pointer, krb5_db_entry *);
1100
krb5_pointer func_arg;
1101
};
1102
1103
static int
1104
sort_entry_callback_proxy(krb5_pointer func_arg, krb5_db_entry *entry)
1105
{
1106
struct callback_proxy_args *args = (struct callback_proxy_args *)func_arg;
1107
1108
/* Sort the keys in the db entry as some parts of krb5 expect it to be. */
1109
if (entry && entry->key_data)
1110
krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data);
1111
return args->func(args->func_arg, entry);
1112
}
1113
1114
krb5_error_code
1115
krb5_db_iterate(krb5_context kcontext, char *match_entry,
1116
int (*func)(krb5_pointer, krb5_db_entry *),
1117
krb5_pointer func_arg, krb5_flags iterflags)
1118
{
1119
krb5_error_code status = 0;
1120
kdb_vftabl *v;
1121
struct callback_proxy_args proxy_args;
1122
1123
status = get_vftabl(kcontext, &v);
1124
if (status)
1125
return status;
1126
if (v->iterate == NULL)
1127
return KRB5_PLUGIN_OP_NOTSUPP;
1128
1129
/* Use the proxy function to sort key data before passing entries to
1130
* callback. */
1131
proxy_args.func = func;
1132
proxy_args.func_arg = func_arg;
1133
return v->iterate(kcontext, match_entry, sort_entry_callback_proxy,
1134
&proxy_args, iterflags);
1135
}
1136
1137
/* Return a read only pointer alias to mkey list. Do not free this! */
1138
krb5_keylist_node *
1139
krb5_db_mkey_list_alias(krb5_context kcontext)
1140
{
1141
return kcontext->dal_handle->master_keylist;
1142
}
1143
1144
krb5_error_code
1145
krb5_db_fetch_mkey_list(krb5_context context, krb5_principal mname,
1146
const krb5_keyblock *mkey)
1147
{
1148
kdb_vftabl *v;
1149
krb5_error_code status = 0;
1150
krb5_keylist_node *local_keylist;
1151
1152
status = get_vftabl(context, &v);
1153
if (status)
1154
return status;
1155
1156
if (!context->dal_handle->master_princ) {
1157
status = krb5_copy_principal(context, mname,
1158
&context->dal_handle->master_princ);
1159
if (status)
1160
return status;
1161
}
1162
1163
status = v->fetch_master_key_list(context, mname, mkey, &local_keylist);
1164
if (status == 0) {
1165
free_mkey_list(context, context->dal_handle->master_keylist);
1166
context->dal_handle->master_keylist = local_keylist;
1167
}
1168
return status;
1169
}
1170
1171
krb5_error_code
1172
krb5_db_store_master_key(krb5_context kcontext, char *keyfile,
1173
krb5_principal mname, krb5_kvno kvno,
1174
krb5_keyblock * key, char *master_pwd)
1175
{
1176
krb5_error_code status = 0;
1177
kdb_vftabl *v;
1178
krb5_keylist_node list;
1179
1180
status = get_vftabl(kcontext, &v);
1181
if (status)
1182
return status;
1183
1184
if (v->store_master_key_list == NULL)
1185
return KRB5_KDB_DBTYPE_NOSUP;
1186
1187
list.kvno = kvno;
1188
list.keyblock = *key;
1189
list.next = NULL;
1190
1191
return v->store_master_key_list(kcontext, keyfile, mname,
1192
&list, master_pwd);
1193
}
1194
1195
krb5_error_code
1196
krb5_db_store_master_key_list(krb5_context kcontext, char *keyfile,
1197
krb5_principal mname, char *master_pwd)
1198
{
1199
krb5_error_code status = 0;
1200
kdb_vftabl *v;
1201
1202
status = get_vftabl(kcontext, &v);
1203
if (status)
1204
return status;
1205
1206
if (v->store_master_key_list == NULL)
1207
return KRB5_KDB_DBTYPE_NOSUP;
1208
1209
if (kcontext->dal_handle->master_keylist == NULL)
1210
return KRB5_KDB_DBNOTINITED;
1211
1212
return v->store_master_key_list(kcontext, keyfile, mname,
1213
kcontext->dal_handle->master_keylist,
1214
master_pwd);
1215
}
1216
1217
char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1;
1218
char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2;
1219
1220
krb5_error_code
1221
krb5_db_fetch_mkey(krb5_context context, krb5_principal mname,
1222
krb5_enctype etype, krb5_boolean fromkeyboard,
1223
krb5_boolean twice, char *db_args, krb5_kvno *kvno,
1224
krb5_data *salt, krb5_keyblock *key)
1225
{
1226
krb5_error_code retval;
1227
char password[BUFSIZ];
1228
krb5_data pwd;
1229
unsigned int size = sizeof(password);
1230
krb5_keyblock tmp_key;
1231
1232
memset(&tmp_key, 0, sizeof(tmp_key));
1233
1234
if (fromkeyboard) {
1235
krb5_data scratch;
1236
1237
if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1,
1238
twice ? krb5_mkey_pwd_prompt2 : 0,
1239
password, &size))) {
1240
goto clean_n_exit;
1241
}
1242
1243
pwd.data = password;
1244
pwd.length = size;
1245
if (!salt) {
1246
retval = krb5_principal2salt(context, mname, &scratch);
1247
if (retval)
1248
goto clean_n_exit;
1249
}
1250
retval =
1251
krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch,
1252
key);
1253
/*
1254
* If a kvno pointer was passed in and it dereferences the IGNORE_VNO
1255
* value then it should be assigned the value of the kvno associated
1256
* with the current mkey princ key if that princ entry is available
1257
* otherwise assign 1 which is the default kvno value for the mkey
1258
* princ.
1259
*/
1260
if (kvno != NULL && *kvno == IGNORE_VNO) {
1261
krb5_error_code rc;
1262
krb5_db_entry *master_entry;
1263
1264
rc = krb5_db_get_principal(context, mname, 0, &master_entry);
1265
if (rc == 0 && master_entry->n_key_data > 0)
1266
*kvno = (krb5_kvno) master_entry->key_data->key_data_kvno;
1267
else
1268
*kvno = 1;
1269
if (rc == 0)
1270
krb5_db_free_principal(context, master_entry);
1271
}
1272
1273
if (!salt)
1274
free(scratch.data);
1275
zap(password, sizeof(password)); /* erase it */
1276
1277
} else {
1278
kdb_vftabl *v;
1279
1280
if (context->dal_handle == NULL) {
1281
retval = krb5_db_setup_lib_handle(context);
1282
if (retval)
1283
goto clean_n_exit;
1284
}
1285
1286
/* get the enctype from the stash */
1287
tmp_key.enctype = ENCTYPE_UNKNOWN;
1288
1289
v = &context->dal_handle->lib_handle->vftabl;
1290
retval = v->fetch_master_key(context, mname, &tmp_key, kvno, db_args);
1291
1292
if (retval)
1293
goto clean_n_exit;
1294
1295
key->contents = k5memdup(tmp_key.contents, tmp_key.length, &retval);
1296
if (key->contents == NULL)
1297
goto clean_n_exit;
1298
1299
key->magic = tmp_key.magic;
1300
key->enctype = tmp_key.enctype;
1301
key->length = tmp_key.length;
1302
}
1303
1304
clean_n_exit:
1305
zapfree(tmp_key.contents, tmp_key.length);
1306
return retval;
1307
}
1308
1309
krb5_error_code
1310
krb5_dbe_fetch_act_key_list(krb5_context context, krb5_principal princ,
1311
krb5_actkvno_node **act_key_list)
1312
{
1313
krb5_error_code retval = 0;
1314
krb5_db_entry *entry;
1315
1316
if (act_key_list == NULL)
1317
return (EINVAL);
1318
1319
retval = krb5_db_get_principal(context, princ, 0, &entry);
1320
if (retval == KRB5_KDB_NOENTRY)
1321
return KRB5_KDB_NOMASTERKEY;
1322
else if (retval)
1323
return retval;
1324
1325
retval = krb5_dbe_lookup_actkvno(context, entry, act_key_list);
1326
krb5_db_free_principal(context, entry);
1327
return retval;
1328
}
1329
1330
/* Find the most recent entry in list (which must not be empty) for the given
1331
* timestamp, and return its kvno. */
1332
static krb5_kvno
1333
find_actkvno(krb5_actkvno_node *list, krb5_timestamp now)
1334
{
1335
/*
1336
* The list is sorted in ascending order of time. Return the kvno of the
1337
* predecessor of the first entry whose time is in the future. If
1338
* (contrary to the safety checks in kdb5_util use_mkey) all of the entries
1339
* are in the future, we will return the first node; if all are in the
1340
* past, we will return the last node.
1341
*/
1342
while (list->next != NULL && !ts_after(list->next->act_time, now))
1343
list = list->next;
1344
return list->act_kvno;
1345
}
1346
1347
/* Search the master keylist for the master key with the specified kvno.
1348
* Return the keyblock of the matching entry or NULL if it does not exist. */
1349
static krb5_keyblock *
1350
find_master_key(krb5_context context, krb5_kvno kvno)
1351
{
1352
krb5_keylist_node *n;
1353
1354
for (n = context->dal_handle->master_keylist; n != NULL; n = n->next) {
1355
if (n->kvno == kvno)
1356
return &n->keyblock;
1357
}
1358
return NULL;
1359
}
1360
1361
/*
1362
* Locates the "active" mkey used when encrypting a princ's keys. Note, the
1363
* caller must NOT free the output act_mkey.
1364
*/
1365
1366
krb5_error_code
1367
krb5_dbe_find_act_mkey(krb5_context context, krb5_actkvno_node *act_mkey_list,
1368
krb5_kvno *act_kvno, krb5_keyblock **act_mkey)
1369
{
1370
krb5_kvno kvno;
1371
krb5_error_code retval;
1372
krb5_keyblock *mkey, *cur_mkey;
1373
krb5_timestamp now;
1374
1375
if (act_mkey_list == NULL) {
1376
*act_kvno = 0;
1377
*act_mkey = NULL;
1378
return 0;
1379
}
1380
1381
if (context->dal_handle->master_keylist == NULL)
1382
return KRB5_KDB_DBNOTINITED;
1383
1384
/* Find the currently active master key version. */
1385
if ((retval = krb5_timeofday(context, &now)))
1386
return (retval);
1387
kvno = find_actkvno(act_mkey_list, now);
1388
1389
/* Find the corresponding master key. */
1390
mkey = find_master_key(context, kvno);
1391
if (mkey == NULL) {
1392
/* Reload the master key list and try again. */
1393
cur_mkey = &context->dal_handle->master_keylist->keyblock;
1394
if (krb5_db_fetch_mkey_list(context, context->dal_handle->master_princ,
1395
cur_mkey) == 0)
1396
mkey = find_master_key(context, kvno);
1397
}
1398
if (mkey == NULL)
1399
return KRB5_KDB_NO_MATCHING_KEY;
1400
1401
*act_mkey = mkey;
1402
if (act_kvno != NULL)
1403
*act_kvno = kvno;
1404
return 0;
1405
}
1406
1407
/*
1408
* Locates the mkey used to protect a princ's keys. Note, the caller must not
1409
* free the output key.
1410
*/
1411
krb5_error_code
1412
krb5_dbe_find_mkey(krb5_context context, krb5_db_entry *entry,
1413
krb5_keyblock **mkey)
1414
{
1415
krb5_kvno mkvno;
1416
krb5_error_code retval;
1417
krb5_keylist_node *cur_keyblock = context->dal_handle->master_keylist;
1418
1419
if (!cur_keyblock)
1420
return KRB5_KDB_DBNOTINITED;
1421
1422
retval = krb5_dbe_get_mkvno(context, entry, &mkvno);
1423
if (retval)
1424
return (retval);
1425
1426
while (cur_keyblock && cur_keyblock->kvno != mkvno)
1427
cur_keyblock = cur_keyblock->next;
1428
1429
if (cur_keyblock) {
1430
*mkey = &cur_keyblock->keyblock;
1431
return (0);
1432
} else {
1433
return KRB5_KDB_NO_MATCHING_KEY;
1434
}
1435
}
1436
1437
void *
1438
krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size)
1439
{
1440
return realloc(ptr, size);
1441
}
1442
1443
void
1444
krb5_db_free(krb5_context kcontext, void *ptr)
1445
{
1446
free(ptr);
1447
}
1448
1449
/* has to be modified */
1450
1451
krb5_error_code
1452
krb5_dbe_find_enctype(krb5_context kcontext, krb5_db_entry *dbentp,
1453
krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno,
1454
krb5_key_data **kdatap)
1455
{
1456
krb5_int32 start = 0;
1457
return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype,
1458
kvno, kdatap);
1459
}
1460
1461
krb5_error_code
1462
krb5_dbe_search_enctype(krb5_context kcontext, krb5_db_entry *dbentp,
1463
krb5_int32 *start, krb5_int32 ktype, krb5_int32 stype,
1464
krb5_int32 kvno, krb5_key_data ** kdatap)
1465
{
1466
krb5_error_code status = 0;
1467
kdb_vftabl *v;
1468
1469
status = get_vftabl(kcontext, &v);
1470
if (status)
1471
return status;
1472
return v->dbe_search_enctype(kcontext, dbentp, start, ktype, stype, kvno,
1473
kdatap);
1474
}
1475
1476
#define REALM_SEP_STRING "@"
1477
1478
krb5_error_code
1479
krb5_db_setup_mkey_name(krb5_context context, const char *keyname,
1480
const char *realm, char **fullname,
1481
krb5_principal *principal)
1482
{
1483
krb5_error_code retval;
1484
char *fname;
1485
1486
if (!keyname)
1487
keyname = KRB5_KDB_M_NAME; /* XXX external? */
1488
1489
if (asprintf(&fname, "%s%s%s", keyname, REALM_SEP_STRING, realm) < 0)
1490
return ENOMEM;
1491
1492
retval = krb5_parse_name(context, fname, principal);
1493
if (retval) {
1494
free(fname);
1495
return retval;
1496
}
1497
if (fullname)
1498
*fullname = fname;
1499
else
1500
free(fname);
1501
return 0;
1502
}
1503
1504
krb5_error_code
1505
krb5_dbe_lookup_last_pwd_change(krb5_context context, krb5_db_entry *entry,
1506
krb5_timestamp *stamp)
1507
{
1508
krb5_tl_data tl_data;
1509
krb5_error_code code;
1510
krb5_int32 tmp;
1511
1512
tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
1513
1514
if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1515
return (code);
1516
1517
if (tl_data.tl_data_length != 4) {
1518
*stamp = 0;
1519
return (0);
1520
}
1521
1522
krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
1523
1524
*stamp = (krb5_timestamp) tmp;
1525
1526
return (0);
1527
}
1528
1529
krb5_error_code
1530
krb5_dbe_lookup_last_admin_unlock(krb5_context context, krb5_db_entry *entry,
1531
krb5_timestamp *stamp)
1532
{
1533
krb5_tl_data tl_data;
1534
krb5_error_code code;
1535
krb5_int32 tmp;
1536
1537
tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK;
1538
1539
if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1540
return (code);
1541
1542
if (tl_data.tl_data_length != 4) {
1543
*stamp = 0;
1544
return (0);
1545
}
1546
1547
krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
1548
1549
*stamp = (krb5_timestamp) tmp;
1550
1551
return (0);
1552
}
1553
1554
krb5_error_code
1555
krb5_dbe_lookup_tl_data(krb5_context context, krb5_db_entry *entry,
1556
krb5_tl_data *ret_tl_data)
1557
{
1558
krb5_tl_data *tl_data;
1559
1560
for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
1561
if (tl_data->tl_data_type == ret_tl_data->tl_data_type) {
1562
*ret_tl_data = *tl_data;
1563
return (0);
1564
}
1565
}
1566
1567
/*
1568
* If the requested record isn't found, return zero bytes. If it
1569
* ever means something to have a zero-length tl_data, this code
1570
* and its callers will have to be changed.
1571
*/
1572
1573
ret_tl_data->tl_data_length = 0;
1574
ret_tl_data->tl_data_contents = NULL;
1575
return (0);
1576
}
1577
1578
krb5_error_code
1579
krb5_dbe_create_key_data(krb5_context context, krb5_db_entry *entry)
1580
{
1581
krb5_key_data *newptr;
1582
1583
newptr = realloc(entry->key_data,
1584
(entry->n_key_data + 1) * sizeof(*entry->key_data));
1585
if (newptr == NULL)
1586
return ENOMEM;
1587
entry->key_data = newptr;
1588
1589
memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data));
1590
entry->n_key_data++;
1591
1592
return 0;
1593
}
1594
1595
krb5_error_code
1596
krb5_dbe_update_mod_princ_data(krb5_context context, krb5_db_entry *entry,
1597
krb5_timestamp mod_date,
1598
krb5_const_principal mod_princ)
1599
{
1600
krb5_tl_data tl_data;
1601
1602
krb5_error_code retval = 0;
1603
krb5_octet *nextloc = 0;
1604
char *unparse_mod_princ = 0;
1605
unsigned int unparse_mod_princ_size;
1606
1607
if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ)))
1608
return (retval);
1609
1610
unparse_mod_princ_size = strlen(unparse_mod_princ) + 1;
1611
1612
if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
1613
== NULL) {
1614
free(unparse_mod_princ);
1615
return (ENOMEM);
1616
}
1617
1618
tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
1619
tl_data.tl_data_length = unparse_mod_princ_size + 4;
1620
tl_data.tl_data_contents = nextloc;
1621
1622
/* Mod Date */
1623
krb5_kdb_encode_int32(mod_date, nextloc);
1624
1625
/* Mod Princ */
1626
memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size);
1627
1628
retval = krb5_dbe_update_tl_data(context, entry, &tl_data);
1629
1630
free(unparse_mod_princ);
1631
free(nextloc);
1632
1633
return (retval);
1634
}
1635
1636
krb5_error_code
1637
krb5_dbe_lookup_mod_princ_data(krb5_context context, krb5_db_entry *entry,
1638
krb5_timestamp *mod_time,
1639
krb5_principal *mod_princ)
1640
{
1641
krb5_tl_data tl_data;
1642
krb5_error_code code;
1643
1644
*mod_princ = NULL;
1645
*mod_time = 0;
1646
1647
tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
1648
1649
if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1650
return (code);
1651
1652
if ((tl_data.tl_data_length < 5) ||
1653
(tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0'))
1654
return (KRB5_KDB_TRUNCATED_RECORD);
1655
1656
/* Mod Date */
1657
krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time);
1658
1659
/* Mod Princ */
1660
if ((code = krb5_parse_name(context,
1661
(const char *) (tl_data.tl_data_contents + 4),
1662
mod_princ)))
1663
return (code);
1664
1665
return (0);
1666
}
1667
1668
krb5_error_code
1669
krb5_dbe_lookup_mkvno(krb5_context context, krb5_db_entry *entry,
1670
krb5_kvno *mkvno)
1671
{
1672
krb5_tl_data tl_data;
1673
krb5_error_code code;
1674
krb5_int16 tmp;
1675
1676
tl_data.tl_data_type = KRB5_TL_MKVNO;
1677
1678
if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1679
return (code);
1680
1681
if (tl_data.tl_data_length == 0) {
1682
*mkvno = 0; /* Indicates KRB5_TL_MKVNO data not present */
1683
return (0);
1684
} else if (tl_data.tl_data_length != 2) {
1685
return (KRB5_KDB_TRUNCATED_RECORD);
1686
}
1687
1688
krb5_kdb_decode_int16(tl_data.tl_data_contents, tmp);
1689
*mkvno = (krb5_kvno) tmp;
1690
return (0);
1691
}
1692
1693
krb5_error_code
1694
krb5_dbe_get_mkvno(krb5_context context, krb5_db_entry *entry,
1695
krb5_kvno *mkvno)
1696
{
1697
krb5_error_code code;
1698
krb5_kvno kvno;
1699
krb5_keylist_node *mkey_list = context->dal_handle->master_keylist;
1700
1701
if (mkey_list == NULL)
1702
return KRB5_KDB_DBNOTINITED;
1703
1704
/* Output the value from entry tl_data if present. */
1705
code = krb5_dbe_lookup_mkvno(context, entry, &kvno);
1706
if (code != 0)
1707
return code;
1708
if (kvno != 0) {
1709
*mkvno = kvno;
1710
return 0;
1711
}
1712
1713
/* Determine the minimum kvno in mkey_list and output that. */
1714
kvno = (krb5_kvno) -1;
1715
while (mkey_list != NULL) {
1716
if (mkey_list->kvno < kvno)
1717
kvno = mkey_list->kvno;
1718
mkey_list = mkey_list->next;
1719
}
1720
*mkvno = kvno;
1721
return 0;
1722
}
1723
1724
krb5_error_code
1725
krb5_dbe_update_mkvno(krb5_context context, krb5_db_entry *entry,
1726
krb5_kvno mkvno)
1727
{
1728
krb5_tl_data tl_data;
1729
krb5_octet buf[2]; /* this is the encoded size of an int16 */
1730
krb5_int16 tmp_kvno = (krb5_int16) mkvno;
1731
1732
tl_data.tl_data_type = KRB5_TL_MKVNO;
1733
tl_data.tl_data_length = sizeof(buf);
1734
krb5_kdb_encode_int16(tmp_kvno, buf);
1735
tl_data.tl_data_contents = buf;
1736
1737
return (krb5_dbe_update_tl_data(context, entry, &tl_data));
1738
}
1739
1740
krb5_error_code
1741
krb5_dbe_lookup_mkey_aux(krb5_context context, krb5_db_entry *entry,
1742
krb5_mkey_aux_node **mkey_aux_data_list)
1743
{
1744
krb5_tl_data tl_data;
1745
krb5_int16 version, mkey_kvno;
1746
krb5_mkey_aux_node *head_data = NULL, *new_data = NULL,
1747
*prev_data = NULL;
1748
krb5_octet *curloc; /* current location pointer */
1749
krb5_error_code code;
1750
1751
tl_data.tl_data_type = KRB5_TL_MKEY_AUX;
1752
if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1753
return (code);
1754
1755
if (tl_data.tl_data_contents == NULL) {
1756
*mkey_aux_data_list = NULL;
1757
return (0);
1758
} else {
1759
/* get version to determine how to parse the data */
1760
krb5_kdb_decode_int16(tl_data.tl_data_contents, version);
1761
if (version == 1) {
1762
/* variable size, must be at least 10 bytes */
1763
if (tl_data.tl_data_length < 10)
1764
return (KRB5_KDB_TRUNCATED_RECORD);
1765
1766
/* curloc points to first tuple entry in the tl_data_contents */
1767
curloc = tl_data.tl_data_contents + sizeof(version);
1768
1769
while (curloc < (tl_data.tl_data_contents + tl_data.tl_data_length)) {
1770
1771
new_data = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node));
1772
if (new_data == NULL) {
1773
krb5_dbe_free_mkey_aux_list(context, head_data);
1774
return (ENOMEM);
1775
}
1776
memset(new_data, 0, sizeof(krb5_mkey_aux_node));
1777
1778
krb5_kdb_decode_int16(curloc, mkey_kvno);
1779
new_data->mkey_kvno = mkey_kvno;
1780
curloc += sizeof(krb5_ui_2);
1781
krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_kvno);
1782
curloc += sizeof(krb5_ui_2);
1783
krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_type[0]);
1784
curloc += sizeof(krb5_ui_2);
1785
krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_length[0]);
1786
curloc += sizeof(krb5_ui_2);
1787
1788
new_data->latest_mkey.key_data_contents[0] = (krb5_octet *)
1789
malloc(new_data->latest_mkey.key_data_length[0]);
1790
1791
if (new_data->latest_mkey.key_data_contents[0] == NULL) {
1792
krb5_dbe_free_mkey_aux_list(context, head_data);
1793
free(new_data);
1794
return (ENOMEM);
1795
}
1796
memcpy(new_data->latest_mkey.key_data_contents[0], curloc,
1797
new_data->latest_mkey.key_data_length[0]);
1798
curloc += new_data->latest_mkey.key_data_length[0];
1799
1800
/* always using key data ver 1 for mkeys */
1801
new_data->latest_mkey.key_data_ver = 1;
1802
1803
new_data->next = NULL;
1804
if (prev_data != NULL)
1805
prev_data->next = new_data;
1806
else
1807
head_data = new_data;
1808
prev_data = new_data;
1809
}
1810
} else {
1811
k5_setmsg(context, KRB5_KDB_BAD_VERSION,
1812
_("Illegal version number for KRB5_TL_MKEY_AUX %d\n"),
1813
version);
1814
return (KRB5_KDB_BAD_VERSION);
1815
}
1816
}
1817
*mkey_aux_data_list = head_data;
1818
return (0);
1819
}
1820
1821
#if KRB5_TL_MKEY_AUX_VER == 1
1822
krb5_error_code
1823
krb5_dbe_update_mkey_aux(krb5_context context, krb5_db_entry *entry,
1824
krb5_mkey_aux_node *mkey_aux_data_list)
1825
{
1826
krb5_error_code status;
1827
krb5_tl_data tl_data;
1828
krb5_int16 version, tmp_kvno;
1829
unsigned char *nextloc;
1830
krb5_mkey_aux_node *aux_data_entry;
1831
1832
if (!mkey_aux_data_list) {
1833
/* delete the KRB5_TL_MKEY_AUX from the entry */
1834
krb5_dbe_delete_tl_data(context, entry, KRB5_TL_MKEY_AUX);
1835
return (0);
1836
}
1837
1838
memset(&tl_data, 0, sizeof(tl_data));
1839
tl_data.tl_data_type = KRB5_TL_MKEY_AUX;
1840
/*
1841
* determine out how much space to allocate. Note key_data_ver not stored
1842
* as this is hard coded to one and is accounted for in
1843
* krb5_dbe_lookup_mkey_aux.
1844
*/
1845
tl_data.tl_data_length = sizeof(version); /* version */
1846
for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
1847
aux_data_entry = aux_data_entry->next) {
1848
1849
tl_data.tl_data_length += (sizeof(krb5_ui_2) + /* mkey_kvno */
1850
sizeof(krb5_ui_2) + /* latest_mkey kvno */
1851
sizeof(krb5_ui_2) + /* latest_mkey enctype */
1852
sizeof(krb5_ui_2) + /* latest_mkey length */
1853
aux_data_entry->latest_mkey.key_data_length[0]);
1854
}
1855
1856
tl_data.tl_data_contents = (krb5_octet *) malloc(tl_data.tl_data_length);
1857
if (tl_data.tl_data_contents == NULL)
1858
return (ENOMEM);
1859
1860
nextloc = tl_data.tl_data_contents;
1861
version = KRB5_TL_MKEY_AUX_VER;
1862
krb5_kdb_encode_int16(version, nextloc);
1863
nextloc += sizeof(krb5_ui_2);
1864
1865
for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
1866
aux_data_entry = aux_data_entry->next) {
1867
1868
tmp_kvno = (krb5_int16) aux_data_entry->mkey_kvno;
1869
krb5_kdb_encode_int16(tmp_kvno, nextloc);
1870
nextloc += sizeof(krb5_ui_2);
1871
1872
krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_kvno,
1873
nextloc);
1874
nextloc += sizeof(krb5_ui_2);
1875
1876
krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_type[0],
1877
nextloc);
1878
nextloc += sizeof(krb5_ui_2);
1879
1880
krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_length[0],
1881
nextloc);
1882
nextloc += sizeof(krb5_ui_2);
1883
1884
if (aux_data_entry->latest_mkey.key_data_length[0] > 0) {
1885
memcpy(nextloc, aux_data_entry->latest_mkey.key_data_contents[0],
1886
aux_data_entry->latest_mkey.key_data_length[0]);
1887
nextloc += aux_data_entry->latest_mkey.key_data_length[0];
1888
}
1889
}
1890
1891
status = krb5_dbe_update_tl_data(context, entry, &tl_data);
1892
free(tl_data.tl_data_contents);
1893
return status;
1894
}
1895
#endif /* KRB5_TL_MKEY_AUX_VER == 1 */
1896
1897
#if KRB5_TL_ACTKVNO_VER == 1
1898
/*
1899
* If version of the KRB5_TL_ACTKVNO data is KRB5_TL_ACTKVNO_VER == 1 then size of
1900
* a actkvno tuple {act_kvno, act_time} entry is:
1901
*/
1902
#define ACTKVNO_TUPLE_SIZE (sizeof(krb5_int16) + sizeof(krb5_int32))
1903
#define act_kvno(cp) (cp) /* return pointer to start of act_kvno data */
1904
#define act_time(cp) ((cp) + sizeof(krb5_int16)) /* return pointer to start of act_time data */
1905
#endif
1906
1907
krb5_error_code
1908
krb5_dbe_lookup_actkvno(krb5_context context, krb5_db_entry *entry,
1909
krb5_actkvno_node **actkvno_list)
1910
{
1911
krb5_tl_data tl_data;
1912
krb5_error_code code;
1913
krb5_int16 version, tmp_kvno;
1914
krb5_actkvno_node *head_data = NULL, *new_data = NULL, *prev_data = NULL;
1915
unsigned int num_actkvno, i;
1916
krb5_octet *next_tuple;
1917
krb5_kvno earliest_kvno;
1918
1919
memset(&tl_data, 0, sizeof(tl_data));
1920
tl_data.tl_data_type = KRB5_TL_ACTKVNO;
1921
1922
if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1923
return (code);
1924
1925
if (tl_data.tl_data_contents == NULL) {
1926
/*
1927
* If there is no KRB5_TL_ACTKVNO data (likely because the KDB was
1928
* created prior to 1.7), synthesize the list which should have been
1929
* created at KDB initialization, making the earliest master key
1930
* active.
1931
*/
1932
1933
/* Get the earliest master key version. */
1934
if (entry->n_key_data == 0)
1935
return KRB5_KDB_NOMASTERKEY;
1936
earliest_kvno = entry->key_data[entry->n_key_data - 1].key_data_kvno;
1937
1938
head_data = malloc(sizeof(*head_data));
1939
if (head_data == NULL)
1940
return ENOMEM;
1941
memset(head_data, 0, sizeof(*head_data));
1942
head_data->act_time = 0; /* earliest time possible */
1943
head_data->act_kvno = earliest_kvno;
1944
} else {
1945
/* get version to determine how to parse the data */
1946
krb5_kdb_decode_int16(tl_data.tl_data_contents, version);
1947
if (version == 1) {
1948
1949
/* variable size, must be at least 8 bytes */
1950
if (tl_data.tl_data_length < 8)
1951
return (KRB5_KDB_TRUNCATED_RECORD);
1952
1953
/*
1954
* Find number of tuple entries, remembering to account for version
1955
* field.
1956
*/
1957
num_actkvno = (tl_data.tl_data_length - sizeof(version)) /
1958
ACTKVNO_TUPLE_SIZE;
1959
prev_data = NULL;
1960
/* next_tuple points to first tuple entry in the tl_data_contents */
1961
next_tuple = tl_data.tl_data_contents + sizeof(version);
1962
for (i = 0; i < num_actkvno; i++) {
1963
new_data = (krb5_actkvno_node *) malloc(sizeof(krb5_actkvno_node));
1964
if (new_data == NULL) {
1965
krb5_dbe_free_actkvno_list(context, head_data);
1966
return (ENOMEM);
1967
}
1968
memset(new_data, 0, sizeof(krb5_actkvno_node));
1969
1970
/* using tmp_kvno to avoid type mismatch */
1971
krb5_kdb_decode_int16(act_kvno(next_tuple), tmp_kvno);
1972
new_data->act_kvno = (krb5_kvno) tmp_kvno;
1973
krb5_kdb_decode_int32(act_time(next_tuple), new_data->act_time);
1974
1975
if (prev_data != NULL)
1976
prev_data->next = new_data;
1977
else
1978
head_data = new_data;
1979
prev_data = new_data;
1980
next_tuple += ACTKVNO_TUPLE_SIZE;
1981
}
1982
} else {
1983
k5_setmsg(context, KRB5_KDB_BAD_VERSION,
1984
_("Illegal version number for KRB5_TL_ACTKVNO %d\n"),
1985
version);
1986
return (KRB5_KDB_BAD_VERSION);
1987
}
1988
}
1989
*actkvno_list = head_data;
1990
return (0);
1991
}
1992
1993
/*
1994
* Add KRB5_TL_ACTKVNO TL data entries to krb5_db_entry *entry
1995
*/
1996
#if KRB5_TL_ACTKVNO_VER == 1
1997
krb5_error_code
1998
krb5_dbe_update_actkvno(krb5_context context, krb5_db_entry *entry,
1999
const krb5_actkvno_node *actkvno_list)
2000
{
2001
krb5_error_code retval = 0;
2002
krb5_int16 version, tmp_kvno;
2003
krb5_tl_data new_tl_data;
2004
unsigned char *nextloc;
2005
const krb5_actkvno_node *cur_actkvno;
2006
krb5_octet *tmpptr;
2007
2008
if (actkvno_list == NULL)
2009
return EINVAL;
2010
2011
memset(&new_tl_data, 0, sizeof(new_tl_data));
2012
/* allocate initial KRB5_TL_ACTKVNO tl_data entry */
2013
new_tl_data.tl_data_length = sizeof(version);
2014
new_tl_data.tl_data_contents = (krb5_octet *) malloc(new_tl_data.tl_data_length);
2015
if (new_tl_data.tl_data_contents == NULL)
2016
return ENOMEM;
2017
2018
/* add the current version # for the data format used for KRB5_TL_ACTKVNO */
2019
version = KRB5_TL_ACTKVNO_VER;
2020
krb5_kdb_encode_int16(version, (unsigned char *) new_tl_data.tl_data_contents);
2021
2022
for (cur_actkvno = actkvno_list; cur_actkvno != NULL;
2023
cur_actkvno = cur_actkvno->next) {
2024
2025
new_tl_data.tl_data_length += ACTKVNO_TUPLE_SIZE;
2026
tmpptr = realloc(new_tl_data.tl_data_contents, new_tl_data.tl_data_length);
2027
if (tmpptr == NULL) {
2028
free(new_tl_data.tl_data_contents);
2029
return ENOMEM;
2030
} else {
2031
new_tl_data.tl_data_contents = tmpptr;
2032
}
2033
2034
/*
2035
* Using realloc so tl_data_contents is required to correctly calculate
2036
* next location to store new tuple.
2037
*/
2038
nextloc = new_tl_data.tl_data_contents + new_tl_data.tl_data_length - ACTKVNO_TUPLE_SIZE;
2039
/* using tmp_kvno to avoid type mismatch issues */
2040
tmp_kvno = (krb5_int16) cur_actkvno->act_kvno;
2041
krb5_kdb_encode_int16(tmp_kvno, nextloc);
2042
nextloc += sizeof(krb5_ui_2);
2043
krb5_kdb_encode_int32((krb5_ui_4)cur_actkvno->act_time, nextloc);
2044
}
2045
2046
new_tl_data.tl_data_type = KRB5_TL_ACTKVNO;
2047
retval = krb5_dbe_update_tl_data(context, entry, &new_tl_data);
2048
free(new_tl_data.tl_data_contents);
2049
2050
return (retval);
2051
}
2052
#endif /* KRB5_TL_ACTKVNO_VER == 1 */
2053
2054
krb5_error_code
2055
krb5_dbe_update_last_pwd_change(krb5_context context, krb5_db_entry *entry,
2056
krb5_timestamp stamp)
2057
{
2058
krb5_tl_data tl_data;
2059
krb5_octet buf[4]; /* this is the encoded size of an int32 */
2060
2061
tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
2062
tl_data.tl_data_length = sizeof(buf);
2063
krb5_kdb_encode_int32((krb5_int32) stamp, buf);
2064
tl_data.tl_data_contents = buf;
2065
2066
return (krb5_dbe_update_tl_data(context, entry, &tl_data));
2067
}
2068
2069
krb5_error_code
2070
krb5_dbe_update_last_admin_unlock(krb5_context context, krb5_db_entry *entry,
2071
krb5_timestamp stamp)
2072
{
2073
krb5_tl_data tl_data;
2074
krb5_octet buf[4]; /* this is the encoded size of an int32 */
2075
2076
tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK;
2077
tl_data.tl_data_length = sizeof(buf);
2078
krb5_kdb_encode_int32((krb5_int32) stamp, buf);
2079
tl_data.tl_data_contents = buf;
2080
2081
return (krb5_dbe_update_tl_data(context, entry, &tl_data));
2082
}
2083
2084
/*
2085
* Prepare to iterate over the string attributes of entry. The returned
2086
* pointers are aliases into entry's tl_data (or into an empty string literal)
2087
* and remain valid until the entry's tl_data is changed.
2088
*/
2089
static krb5_error_code
2090
begin_attrs(krb5_context context, krb5_db_entry *entry, const char **pos_out,
2091
const char **end_out)
2092
{
2093
krb5_error_code code;
2094
krb5_tl_data tl_data;
2095
2096
*pos_out = *end_out = NULL;
2097
tl_data.tl_data_type = KRB5_TL_STRING_ATTRS;
2098
code = krb5_dbe_lookup_tl_data(context, entry, &tl_data);
2099
if (code)
2100
return code;
2101
2102
/* Copy the current mapping to buf, updating key with value if found. */
2103
*pos_out = (const char *)tl_data.tl_data_contents;
2104
*end_out = *pos_out + tl_data.tl_data_length;
2105
return 0;
2106
}
2107
2108
/* Find the next key and value pair in *pos and update *pos. */
2109
static krb5_boolean
2110
next_attr(const char **pos, const char *end, const char **key_out,
2111
const char **val_out)
2112
{
2113
const char *key, *key_end, *val, *val_end;
2114
2115
*key_out = *val_out = NULL;
2116
if (*pos == end)
2117
return FALSE;
2118
key = *pos;
2119
key_end = memchr(key, '\0', end - key);
2120
if (key_end == NULL) /* Malformed representation; give up. */
2121
return FALSE;
2122
val = key_end + 1;
2123
val_end = memchr(val, '\0', end - val);
2124
if (val_end == NULL) /* Malformed representation; give up. */
2125
return FALSE;
2126
2127
*key_out = key;
2128
*val_out = val;
2129
*pos = val_end + 1;
2130
return TRUE;
2131
}
2132
2133
krb5_error_code
2134
krb5_dbe_get_strings(krb5_context context, krb5_db_entry *entry,
2135
krb5_string_attr **strings_out, int *count_out)
2136
{
2137
krb5_error_code code;
2138
const char *pos, *end, *mapkey, *mapval;
2139
char *key = NULL, *val = NULL;
2140
krb5_string_attr *strings = NULL, *newstrings;
2141
int count = 0;
2142
2143
*strings_out = NULL;
2144
*count_out = 0;
2145
code = begin_attrs(context, entry, &pos, &end);
2146
if (code)
2147
return code;
2148
2149
while (next_attr(&pos, end, &mapkey, &mapval)) {
2150
/* Add a copy of mapkey and mapvalue to strings. */
2151
newstrings = realloc(strings, (count + 1) * sizeof(*strings));
2152
if (newstrings == NULL)
2153
goto oom;
2154
strings = newstrings;
2155
key = strdup(mapkey);
2156
val = strdup(mapval);
2157
if (key == NULL || val == NULL)
2158
goto oom;
2159
strings[count].key = key;
2160
strings[count].value = val;
2161
count++;
2162
}
2163
2164
*strings_out = strings;
2165
*count_out = count;
2166
return 0;
2167
2168
oom:
2169
free(key);
2170
free(val);
2171
krb5_dbe_free_strings(context, strings, count);
2172
return ENOMEM;
2173
}
2174
2175
krb5_error_code
2176
krb5_dbe_get_string(krb5_context context, krb5_db_entry *entry,
2177
const char *key, char **value_out)
2178
{
2179
krb5_error_code code;
2180
const char *pos, *end, *mapkey, *mapval;
2181
2182
*value_out = NULL;
2183
code = begin_attrs(context, entry, &pos, &end);
2184
if (code)
2185
return code;
2186
while (next_attr(&pos, end, &mapkey, &mapval)) {
2187
if (strcmp(mapkey, key) == 0) {
2188
*value_out = strdup(mapval);
2189
return (*value_out == NULL) ? ENOMEM : 0;
2190
}
2191
}
2192
2193
return 0;
2194
}
2195
2196
krb5_error_code
2197
krb5_dbe_set_string(krb5_context context, krb5_db_entry *entry,
2198
const char *key, const char *value)
2199
{
2200
krb5_error_code code;
2201
const char *pos, *end, *mapkey, *mapval;
2202
struct k5buf buf = EMPTY_K5BUF;
2203
krb5_boolean found = FALSE;
2204
krb5_tl_data tl_data;
2205
2206
/* Copy the current mapping to buf, updating key with value if found. */
2207
code = begin_attrs(context, entry, &pos, &end);
2208
if (code)
2209
return code;
2210
k5_buf_init_dynamic(&buf);
2211
while (next_attr(&pos, end, &mapkey, &mapval)) {
2212
if (strcmp(mapkey, key) == 0) {
2213
if (value != NULL) {
2214
k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1);
2215
k5_buf_add_len(&buf, value, strlen(value) + 1);
2216
}
2217
found = TRUE;
2218
} else {
2219
k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1);
2220
k5_buf_add_len(&buf, mapval, strlen(mapval) + 1);
2221
}
2222
}
2223
2224
/* If key wasn't found in the map, add a new entry for it. */
2225
if (!found && value != NULL) {
2226
k5_buf_add_len(&buf, key, strlen(key) + 1);
2227
k5_buf_add_len(&buf, value, strlen(value) + 1);
2228
}
2229
2230
if (k5_buf_status(&buf) != 0)
2231
return ENOMEM;
2232
if (buf.len > 65535) {
2233
code = KRB5_KDB_STRINGS_TOOLONG;
2234
goto cleanup;
2235
}
2236
tl_data.tl_data_type = KRB5_TL_STRING_ATTRS;
2237
tl_data.tl_data_contents = buf.data;
2238
tl_data.tl_data_length = buf.len;
2239
2240
code = krb5_dbe_update_tl_data(context, entry, &tl_data);
2241
2242
cleanup:
2243
k5_buf_free(&buf);
2244
return code;
2245
}
2246
2247
krb5_error_code
2248
krb5_dbe_delete_tl_data(krb5_context context, krb5_db_entry *entry,
2249
krb5_int16 tl_data_type)
2250
{
2251
krb5_tl_data *tl_data, *prev_tl_data, *free_tl_data;
2252
2253
/*
2254
* Find existing entries of the specified type and remove them from the
2255
* entry's tl_data list.
2256
*/
2257
2258
for (prev_tl_data = tl_data = entry->tl_data; tl_data != NULL;) {
2259
if (tl_data->tl_data_type == tl_data_type) {
2260
if (tl_data == entry->tl_data) {
2261
/* remove from head */
2262
entry->tl_data = tl_data->tl_data_next;
2263
prev_tl_data = entry->tl_data;
2264
} else if (tl_data->tl_data_next == NULL) {
2265
/* remove from tail */
2266
prev_tl_data->tl_data_next = NULL;
2267
} else {
2268
/* remove in between */
2269
prev_tl_data->tl_data_next = tl_data->tl_data_next;
2270
}
2271
free_tl_data = tl_data;
2272
tl_data = tl_data->tl_data_next;
2273
krb5_dbe_free_tl_data(context, free_tl_data);
2274
entry->n_tl_data--;
2275
} else {
2276
prev_tl_data = tl_data;
2277
tl_data = tl_data->tl_data_next;
2278
}
2279
}
2280
2281
return (0);
2282
}
2283
2284
krb5_error_code
2285
krb5_db_update_tl_data(krb5_context context, krb5_int16 *n_tl_datap,
2286
krb5_tl_data **tl_datap, krb5_tl_data *new_tl_data)
2287
{
2288
krb5_tl_data *tl_data = NULL;
2289
krb5_octet *tmp;
2290
2291
/*
2292
* Copy the new data first, so we can fail cleanly if malloc()
2293
* fails.
2294
*/
2295
tmp = malloc(new_tl_data->tl_data_length);
2296
if (tmp == NULL)
2297
return (ENOMEM);
2298
2299
/*
2300
* Find an existing entry of the specified type and point at
2301
* it, or NULL if not found.
2302
*/
2303
2304
if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */
2305
for (tl_data = *tl_datap; tl_data;
2306
tl_data = tl_data->tl_data_next)
2307
if (tl_data->tl_data_type == new_tl_data->tl_data_type)
2308
break;
2309
}
2310
2311
/* If necessary, chain a new record in the beginning and point at it. */
2312
2313
if (!tl_data) {
2314
tl_data = calloc(1, sizeof(*tl_data));
2315
if (tl_data == NULL) {
2316
free(tmp);
2317
return (ENOMEM);
2318
}
2319
tl_data->tl_data_next = *tl_datap;
2320
*tl_datap = tl_data;
2321
(*n_tl_datap)++;
2322
}
2323
2324
/* fill in the record */
2325
2326
free(tl_data->tl_data_contents);
2327
2328
tl_data->tl_data_type = new_tl_data->tl_data_type;
2329
tl_data->tl_data_length = new_tl_data->tl_data_length;
2330
tl_data->tl_data_contents = tmp;
2331
memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
2332
2333
return (0);
2334
}
2335
2336
krb5_error_code
2337
krb5_dbe_update_tl_data(krb5_context context, krb5_db_entry *entry,
2338
krb5_tl_data *new_tl_data)
2339
{
2340
return krb5_db_update_tl_data(context, &entry->n_tl_data, &entry->tl_data,
2341
new_tl_data);
2342
}
2343
2344
krb5_error_code
2345
krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key,
2346
krb5_const_principal princ, krb5_int16 *salttype_out,
2347
krb5_data **salt_out)
2348
{
2349
krb5_error_code retval;
2350
krb5_int16 stype;
2351
krb5_data *salt, sdata;
2352
2353
stype = (key->key_data_ver < 2) ? KRB5_KDB_SALTTYPE_NORMAL :
2354
key->key_data_type[1];
2355
*salttype_out = stype;
2356
*salt_out = NULL;
2357
2358
/* Place computed salt into sdata, or directly into salt_out and return. */
2359
switch (stype) {
2360
case KRB5_KDB_SALTTYPE_NORMAL:
2361
retval = krb5_principal2salt(context, princ, &sdata);
2362
if (retval)
2363
return retval;
2364
break;
2365
case KRB5_KDB_SALTTYPE_NOREALM:
2366
retval = krb5_principal2salt_norealm(context, princ, &sdata);
2367
if (retval)
2368
return retval;
2369
break;
2370
case KRB5_KDB_SALTTYPE_ONLYREALM:
2371
return krb5_copy_data(context, &princ->realm, salt_out);
2372
case KRB5_KDB_SALTTYPE_SPECIAL:
2373
sdata = make_data(key->key_data_contents[1], key->key_data_length[1]);
2374
return krb5_copy_data(context, &sdata, salt_out);
2375
default:
2376
return KRB5_KDB_BAD_SALTTYPE;
2377
}
2378
2379
/* Make a container for sdata. */
2380
salt = malloc(sizeof(*salt));
2381
if (salt == NULL) {
2382
free(sdata.data);
2383
return ENOMEM;
2384
}
2385
*salt = sdata;
2386
*salt_out = salt;
2387
return 0;
2388
}
2389
2390
krb5_error_code
2391
krb5_dbe_specialize_salt(krb5_context context, krb5_db_entry *entry)
2392
{
2393
krb5_int16 stype, i;
2394
krb5_data *salt;
2395
krb5_error_code ret;
2396
2397
if (context == NULL || entry == NULL)
2398
return EINVAL;
2399
2400
/*
2401
* Store salt values explicitly so that they don't depend on the principal
2402
* name.
2403
*/
2404
for (i = 0; i < entry->n_key_data; i++) {
2405
ret = krb5_dbe_compute_salt(context, &entry->key_data[i], entry->princ,
2406
&stype, &salt);
2407
if (ret)
2408
return ret;
2409
2410
/* Steal the data pointer from salt and free the container. */
2411
if (entry->key_data[i].key_data_ver >= 2)
2412
free(entry->key_data[i].key_data_contents[1]);
2413
entry->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
2414
entry->key_data[i].key_data_contents[1] = (uint8_t *)salt->data;
2415
entry->key_data[i].key_data_length[1] = salt->length;
2416
entry->key_data[i].key_data_ver = 2;
2417
free(salt);
2418
}
2419
2420
return 0;
2421
}
2422
2423
/* change password functions */
2424
krb5_error_code
2425
krb5_dbe_cpw(krb5_context kcontext, krb5_keyblock *master_key,
2426
krb5_key_salt_tuple *ks_tuple, int ks_tuple_count, char *passwd,
2427
int new_kvno, krb5_boolean keepold, krb5_db_entry *db_entry)
2428
{
2429
krb5_error_code status = 0;
2430
kdb_vftabl *v;
2431
2432
status = get_vftabl(kcontext, &v);
2433
if (status)
2434
return status;
2435
return v->change_pwd(kcontext, master_key, ks_tuple, ks_tuple_count,
2436
passwd, new_kvno, keepold, db_entry);
2437
}
2438
2439
/* policy management functions */
2440
krb5_error_code
2441
krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
2442
{
2443
krb5_error_code status = 0;
2444
kdb_vftabl *v;
2445
2446
status = get_vftabl(kcontext, &v);
2447
if (status)
2448
return status;
2449
if (v->create_policy == NULL)
2450
return KRB5_PLUGIN_OP_NOTSUPP;
2451
2452
status = v->create_policy(kcontext, policy);
2453
/* iprop does not support policy mods; force full resync. */
2454
if (!status && logging(kcontext))
2455
status = ulog_init_header(kcontext);
2456
return status;
2457
}
2458
2459
krb5_error_code
2460
krb5_db_get_policy(krb5_context kcontext, char *name, osa_policy_ent_t *policy)
2461
{
2462
krb5_error_code status = 0;
2463
kdb_vftabl *v;
2464
2465
status = get_vftabl(kcontext, &v);
2466
if (status)
2467
return status;
2468
if (v->get_policy == NULL)
2469
return KRB5_PLUGIN_OP_NOTSUPP;
2470
return v->get_policy(kcontext, name, policy);
2471
}
2472
2473
krb5_error_code
2474
krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
2475
{
2476
krb5_error_code status = 0;
2477
kdb_vftabl *v;
2478
2479
status = get_vftabl(kcontext, &v);
2480
if (status)
2481
return status;
2482
if (v->put_policy == NULL)
2483
return KRB5_PLUGIN_OP_NOTSUPP;
2484
2485
status = v->put_policy(kcontext, policy);
2486
/* iprop does not support policy mods; force full resync. */
2487
if (!status && logging(kcontext))
2488
status = ulog_init_header(kcontext);
2489
return status;
2490
}
2491
2492
krb5_error_code
2493
krb5_db_iter_policy(krb5_context kcontext, char *match_entry,
2494
osa_adb_iter_policy_func func, void *data)
2495
{
2496
krb5_error_code status = 0;
2497
kdb_vftabl *v;
2498
2499
status = get_vftabl(kcontext, &v);
2500
if (status)
2501
return status;
2502
if (v->iter_policy == NULL)
2503
return 0;
2504
return v->iter_policy(kcontext, match_entry, func, data);
2505
}
2506
2507
krb5_error_code
2508
krb5_db_delete_policy(krb5_context kcontext, char *policy)
2509
{
2510
krb5_error_code status = 0;
2511
kdb_vftabl *v;
2512
2513
status = get_vftabl(kcontext, &v);
2514
if (status)
2515
return status;
2516
if (v->delete_policy == NULL)
2517
return KRB5_PLUGIN_OP_NOTSUPP;
2518
2519
status = v->delete_policy(kcontext, policy);
2520
/* iprop does not support policy mods; force full resync. */
2521
if (!status && logging(kcontext))
2522
status = ulog_init_header(kcontext);
2523
return status;
2524
}
2525
2526
void
2527
krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy)
2528
{
2529
if (policy == NULL)
2530
return;
2531
free(policy->name);
2532
free(policy->allowed_keysalts);
2533
free_tl_data(policy->tl_data);
2534
free(policy);
2535
}
2536
2537
krb5_error_code
2538
krb5_db_promote(krb5_context kcontext, char **db_args)
2539
{
2540
krb5_error_code status;
2541
char *section;
2542
kdb_vftabl *v;
2543
2544
status = get_vftabl(kcontext, &v);
2545
if (status)
2546
return status;
2547
if (v->promote_db == NULL)
2548
return KRB5_PLUGIN_OP_NOTSUPP;
2549
status = get_conf_section(kcontext, &section);
2550
if (status)
2551
return status;
2552
status = v->promote_db(kcontext, section, db_args);
2553
free(section);
2554
return status;
2555
}
2556
2557
static krb5_error_code
2558
decrypt_iterator(krb5_context kcontext, const krb5_key_data * key_data,
2559
krb5_keyblock *dbkey, krb5_keysalt *keysalt)
2560
{
2561
krb5_error_code status = 0;
2562
kdb_vftabl *v;
2563
krb5_keylist_node *n = kcontext->dal_handle->master_keylist;
2564
2565
status = get_vftabl(kcontext, &v);
2566
if (status)
2567
return status;
2568
for (; n; n = n->next) {
2569
krb5_clear_error_message(kcontext);
2570
status = v->decrypt_key_data(kcontext, &n->keyblock, key_data, dbkey,
2571
keysalt);
2572
if (status == 0)
2573
return 0;
2574
}
2575
return status;
2576
}
2577
2578
krb5_error_code
2579
krb5_dbe_decrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey,
2580
const krb5_key_data *key_data, krb5_keyblock *dbkey,
2581
krb5_keysalt *keysalt)
2582
{
2583
krb5_error_code status = 0;
2584
kdb_vftabl *v;
2585
krb5_keyblock *cur_mkey;
2586
2587
status = get_vftabl(kcontext, &v);
2588
if (status)
2589
return status;
2590
if (mkey || kcontext->dal_handle->master_keylist == NULL)
2591
return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt);
2592
status = decrypt_iterator(kcontext, key_data, dbkey, keysalt);
2593
if (status == 0)
2594
return 0;
2595
if (kcontext->dal_handle->master_keylist) {
2596
/* Try reloading master keys. */
2597
cur_mkey = &kcontext->dal_handle->master_keylist->keyblock;
2598
if (krb5_db_fetch_mkey_list(kcontext,
2599
kcontext->dal_handle->master_princ,
2600
cur_mkey) == 0)
2601
return decrypt_iterator(kcontext, key_data, dbkey, keysalt);
2602
}
2603
return status;
2604
}
2605
2606
krb5_error_code
2607
krb5_dbe_encrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey,
2608
const krb5_keyblock *dbkey,
2609
const krb5_keysalt *keysalt, int keyver,
2610
krb5_key_data *key_data)
2611
{
2612
krb5_error_code status = 0;
2613
kdb_vftabl *v;
2614
2615
status = get_vftabl(kcontext, &v);
2616
if (status)
2617
return status;
2618
return v->encrypt_key_data(kcontext, mkey, dbkey, keysalt, keyver,
2619
key_data);
2620
}
2621
2622
krb5_error_code
2623
krb5_db_get_context(krb5_context context, void **db_context)
2624
{
2625
*db_context = KRB5_DB_GET_DB_CONTEXT(context);
2626
if (*db_context == NULL)
2627
return KRB5_KDB_DBNOTINITED;
2628
return 0;
2629
}
2630
2631
krb5_error_code
2632
krb5_db_set_context(krb5_context context, void *db_context)
2633
{
2634
KRB5_DB_GET_DB_CONTEXT(context) = db_context;
2635
2636
return 0;
2637
}
2638
2639
krb5_error_code
2640
krb5_db_check_transited_realms(krb5_context kcontext,
2641
const krb5_data *tr_contents,
2642
const krb5_data *client_realm,
2643
const krb5_data *server_realm)
2644
{
2645
krb5_error_code status;
2646
kdb_vftabl *v;
2647
2648
status = get_vftabl(kcontext, &v);
2649
if (status)
2650
return status;
2651
if (v->check_transited_realms == NULL)
2652
return KRB5_PLUGIN_OP_NOTSUPP;
2653
return v->check_transited_realms(kcontext, tr_contents, client_realm,
2654
server_realm);
2655
}
2656
2657
krb5_error_code
2658
krb5_db_check_policy_as(krb5_context kcontext, krb5_kdc_req *request,
2659
krb5_db_entry *client, krb5_db_entry *server,
2660
krb5_timestamp kdc_time, const char **status,
2661
krb5_pa_data ***e_data)
2662
{
2663
krb5_error_code ret;
2664
kdb_vftabl *v;
2665
2666
*status = NULL;
2667
*e_data = NULL;
2668
ret = get_vftabl(kcontext, &v);
2669
if (ret)
2670
return ret;
2671
if (v->check_policy_as == NULL)
2672
return KRB5_PLUGIN_OP_NOTSUPP;
2673
return v->check_policy_as(kcontext, request, client, server, kdc_time,
2674
status, e_data);
2675
}
2676
2677
krb5_error_code
2678
krb5_db_check_policy_tgs(krb5_context kcontext, krb5_kdc_req *request,
2679
krb5_db_entry *server, krb5_ticket *ticket,
2680
const char **status, krb5_pa_data ***e_data)
2681
{
2682
krb5_error_code ret;
2683
kdb_vftabl *v;
2684
2685
*status = NULL;
2686
*e_data = NULL;
2687
ret = get_vftabl(kcontext, &v);
2688
if (ret)
2689
return ret;
2690
if (v->check_policy_tgs == NULL)
2691
return KRB5_PLUGIN_OP_NOTSUPP;
2692
return v->check_policy_tgs(kcontext, request, server, ticket, status,
2693
e_data);
2694
}
2695
2696
void
2697
krb5_db_audit_as_req(krb5_context kcontext, krb5_kdc_req *request,
2698
const krb5_address *local_addr,
2699
const krb5_address *remote_addr, krb5_db_entry *client,
2700
krb5_db_entry *server, krb5_timestamp authtime,
2701
krb5_error_code error_code)
2702
{
2703
krb5_error_code status;
2704
kdb_vftabl *v;
2705
2706
status = get_vftabl(kcontext, &v);
2707
if (status || v->audit_as_req == NULL)
2708
return;
2709
v->audit_as_req(kcontext, request, local_addr, remote_addr,
2710
client, server, authtime, error_code);
2711
}
2712
2713
void
2714
krb5_db_refresh_config(krb5_context kcontext)
2715
{
2716
krb5_error_code status;
2717
kdb_vftabl *v;
2718
2719
status = get_vftabl(kcontext, &v);
2720
if (status || v->refresh_config == NULL)
2721
return;
2722
v->refresh_config(kcontext);
2723
}
2724
2725
krb5_error_code
2726
krb5_db_check_allowed_to_delegate(krb5_context kcontext,
2727
krb5_const_principal client,
2728
const krb5_db_entry *server,
2729
krb5_const_principal proxy)
2730
{
2731
krb5_error_code ret;
2732
kdb_vftabl *v;
2733
2734
ret = get_vftabl(kcontext, &v);
2735
if (ret)
2736
return ret;
2737
if (v->check_allowed_to_delegate == NULL)
2738
return KRB5_PLUGIN_OP_NOTSUPP;
2739
return v->check_allowed_to_delegate(kcontext, client, server, proxy);
2740
}
2741
2742
krb5_error_code
2743
krb5_db_get_s4u_x509_principal(krb5_context kcontext,
2744
const krb5_data *client_cert,
2745
krb5_const_principal in_princ,
2746
unsigned int flags, krb5_db_entry **entry)
2747
{
2748
krb5_error_code ret;
2749
kdb_vftabl *v;
2750
2751
ret = get_vftabl(kcontext, &v);
2752
if (ret)
2753
return ret;
2754
if (v->get_s4u_x509_principal == NULL)
2755
return KRB5_PLUGIN_OP_NOTSUPP;
2756
ret = v->get_s4u_x509_principal(kcontext, client_cert, in_princ, flags,
2757
entry);
2758
if (ret)
2759
return ret;
2760
2761
/* Sort the keys in the db entry, same as get_principal(). */
2762
if ((*entry)->key_data != NULL)
2763
krb5_dbe_sort_key_data((*entry)->key_data, (*entry)->n_key_data);
2764
2765
return 0;
2766
}
2767
2768
krb5_error_code
2769
krb5_db_allowed_to_delegate_from(krb5_context kcontext,
2770
krb5_const_principal client,
2771
krb5_const_principal server,
2772
krb5_pac server_pac,
2773
const krb5_db_entry *proxy)
2774
{
2775
krb5_error_code ret;
2776
kdb_vftabl *v;
2777
2778
ret = get_vftabl(kcontext, &v);
2779
if (ret)
2780
return ret;
2781
if (v->allowed_to_delegate_from == NULL)
2782
return KRB5_PLUGIN_OP_NOTSUPP;
2783
return v->allowed_to_delegate_from(kcontext, client, server, server_pac,
2784
proxy);
2785
}
2786
2787
void
2788
krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length)
2789
{
2790
size_t i, j;
2791
krb5_key_data tmp;
2792
2793
/* Use insertion sort as a stable sort. */
2794
for (i = 1; i < key_data_length; i++) {
2795
j = i;
2796
while (j > 0 &&
2797
key_data[j - 1].key_data_kvno < key_data[j].key_data_kvno) {
2798
tmp = key_data[j];
2799
key_data[j] = key_data[j - 1];
2800
key_data[j - 1] = tmp;
2801
j--;
2802
}
2803
}
2804
}
2805
2806
krb5_error_code
2807
krb5_db_issue_pac(krb5_context context, unsigned int flags,
2808
krb5_db_entry *client, krb5_keyblock *replaced_reply_key,
2809
krb5_db_entry *server, krb5_db_entry *krbtgt,
2810
krb5_timestamp authtime, krb5_pac old_pac, krb5_pac new_pac,
2811
krb5_data ***auth_indicators)
2812
{
2813
krb5_error_code ret;
2814
kdb_vftabl *v;
2815
2816
ret = get_vftabl(context, &v);
2817
if (ret)
2818
return ret;
2819
if (v->issue_pac == NULL)
2820
return KRB5_PLUGIN_OP_NOTSUPP;
2821
return v->issue_pac(context, flags, client, replaced_reply_key, server,
2822
krbtgt, authtime, old_pac, new_pac, auth_indicators);
2823
}
2824
2825
krb5_error_code
2826
krb5_dbe_make_alias_entry(krb5_context context, krb5_const_principal alias,
2827
krb5_const_principal target, krb5_db_entry **out)
2828
{
2829
krb5_error_code ret;
2830
krb5_principal princ = NULL;
2831
char *target_str = NULL;
2832
krb5_tl_data *tl = NULL;
2833
krb5_db_entry *ent;
2834
2835
*out = NULL;
2836
2837
ret = krb5_copy_principal(context, alias, &princ);
2838
if (ret)
2839
goto cleanup;
2840
2841
ret = krb5_unparse_name(context, target, &target_str);
2842
if (ret)
2843
goto cleanup;
2844
tl = k5alloc(sizeof(*tl), &ret);
2845
if (tl == NULL)
2846
goto cleanup;
2847
tl->tl_data_next = NULL;
2848
tl->tl_data_type = KRB5_TL_ALIAS_TARGET;
2849
tl->tl_data_length = strlen(target_str) + 1;
2850
tl->tl_data_contents = (uint8_t *)target_str;
2851
2852
ent = k5alloc(sizeof(*ent), &ret);
2853
if (ent == NULL)
2854
goto cleanup;
2855
ent->len = KRB5_KDB_V1_BASE_LENGTH;
2856
ent->attributes = KRB5_KDB_DISALLOW_ALL_TIX;
2857
ent->princ = princ;
2858
ent->tl_data = tl;
2859
ent->n_tl_data = 1;
2860
princ = NULL;
2861
target_str = NULL;
2862
tl = NULL;
2863
*out = ent;
2864
2865
cleanup:
2866
krb5_free_principal(context, princ);
2867
krb5_free_unparsed_name(context, target_str);
2868
free(tl);
2869
return ret;
2870
}
2871
2872
krb5_error_code
2873
krb5_dbe_read_alias(krb5_context context, krb5_db_entry *entry,
2874
krb5_principal *target_out)
2875
{
2876
krb5_error_code ret;
2877
krb5_tl_data tl;
2878
2879
*target_out = NULL;
2880
2881
tl.tl_data_type = KRB5_TL_ALIAS_TARGET;
2882
ret = krb5_dbe_lookup_tl_data(context, entry, &tl);
2883
if (ret)
2884
return ret;
2885
2886
if (tl.tl_data_length == 0)
2887
return 0;
2888
2889
if (tl.tl_data_contents[tl.tl_data_length - 1] != '\0')
2890
return KRB5_KDB_TRUNCATED_RECORD;
2891
2892
return krb5_parse_name(context, (char *)tl.tl_data_contents, target_out);
2893
}
2894
2895