Path: blob/main/crypto/krb5/src/plugins/kdb/test/kdb_test.c
34914 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* plugins/kdb/test/kdb_test.c - Test KDB module */2/*3* Copyright (C) 2015 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* * Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in15* the documentation and/or other materials provided with the16* distribution.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29* OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132/*33* This is a read-only KDB module intended to help test KDC behavior which34* cannot be exercised with the DB2 module. Responses are read from the35* dbmodules subsection according to this example:36*37* [dbmodules]38* test = {39* alias = {40* aliasname = canonname41* # For cross-realm aliases, only the realm part will42* # matter to the client.43* aliasname = @FOREIGN_REALM44* enterprise@PRINC = @FOREIGN_REALM45* }46* princs = {47* krbtgt/KRBTEST.COM = {48* flags = +preauth +ok-to-auth-as-delegate49* maxlife = 1d50* maxrenewlife = 7d51* expiration = 14d # relative to current time52* pwexpiration = 1h53* # Initial number is kvno; defaults to 1.54* keys = 3 aes256-cts aes128-cts:normal55* keys = 2 rc4-hmac56* strings = key1:value157* strings = key2:value258* }59* }60* delegation = {61* # Traditional constrained delegation; target_service62* # must be in the same realm.63* intermediate_service = target_service64* }65* rbcd = {66* # Resource-based constrained delegation;67* # intermediate_service may be in a different realm.68* target_service = intermediate_service69* }70* }71*72* Key values are generated using a hash of the kvno, enctype, salt type,73* principal name, and lookup realm. This module does not use master key74* encryption, so it serves as a partial test of the DAL's ability to avoid75* that.76*77* Inbound cross-realm TGT entries are currently implicit; they will use the78* same configuration and key enctypes as the local krbtgt principal, although79* they will use different keys (because the lookup realm is hashed in).80* Outgoing cross-realm TGT entries must be added explicitly81* (krbtgt/OTHER_REALM).82*/8384#include "k5-int.h"85#include "kdb5.h"86#include "adm_proto.h"87#include <ctype.h>8889#define TEST_AD_TYPE -4569091#define IS_TGS_PRINC(p) ((p)->length == 2 && \92data_eq_string((p)->data[0], KRB5_TGS_NAME))9394typedef struct {95void *profile;96char *section;97const char *names[6];98} *testhandle;99100static void *101ealloc(size_t sz)102{103void *p = calloc(sz, 1);104105if (p == NULL)106abort();107return p;108}109110static char *111estrdup(const char *s)112{113char *copy = strdup(s);114115if (copy == NULL)116abort();117return copy;118}119120static void121check(krb5_error_code code)122{123if (code != 0)124abort();125}126127/* Set up for a profile query using h->names. Look up s1 -> s2 -> s3 (some of128* which may be NULL) within this database's dbmodules section. */129static void130set_names(testhandle h, const char *s1, const char *s2, const char *s3)131{132h->names[0] = KDB_MODULE_SECTION;133h->names[1] = h->section;134h->names[2] = s1;135h->names[3] = s2;136h->names[4] = s3;137h->names[5] = NULL;138}139140/* Look up a string within this database's dbmodules section. */141static char *142get_string(testhandle h, const char *s1, const char *s2, const char *s3)143{144krb5_error_code ret;145char **values, *val;146147set_names(h, s1, s2, s3);148ret = profile_get_values(h->profile, h->names, &values);149if (ret == PROF_NO_RELATION)150return NULL;151if (ret)152abort();153val = estrdup(values[0]);154profile_free_list(values);155return val;156}157158/* Look up a duration within this database's dbmodules section. */159static krb5_deltat160get_duration(testhandle h, const char *s1, const char *s2, const char *s3)161{162char *strval = get_string(h, s1, s2, s3);163krb5_deltat val;164165if (strval == NULL)166return 0;167check(krb5_string_to_deltat(strval, &val));168free(strval);169return val;170}171172/* Look up an absolute time within this database's dbmodules section. The time173* is expressed in the profile as an interval relative to the current time. */174static krb5_timestamp175get_time(testhandle h, const char *s1, const char *s2, const char *s3)176{177char *strval = get_string(h, s1, s2, s3);178krb5_deltat val;179180if (strval == NULL)181return 0;182check(krb5_string_to_deltat(strval, &val));183free(strval);184return val + time(NULL);185}186187/* Initialize kb_out with a key of type etype, using a hash of kvno, etype,188* salttype, and princstr for the key bytes. */189static void190make_keyblock(krb5_kvno kvno, krb5_enctype etype, int32_t salttype,191const char *princstr, const krb5_data *realm,192krb5_keyblock *kb_out)193{194size_t keybytes, keylength, pos, n;195char *hashstr;196krb5_data d, rndin;197krb5_checksum cksum;198199check(krb5_c_keylengths(NULL, etype, &keybytes, &keylength));200alloc_data(&rndin, keybytes);201202/* Hash the kvno, enctype, salt type, and principal name together. */203if (asprintf(&hashstr, "%d %d %d %s %.*s", (int)kvno, (int)etype,204(int)salttype, princstr, (int)realm->length, realm->data) < 0)205abort();206d = string2data(hashstr);207check(krb5_c_make_checksum(NULL, CKSUMTYPE_SHA1, NULL, 0, &d, &cksum));208209/* Make the appropriate number of input bytes from the hash result. */210for (pos = 0; pos < keybytes; pos += n) {211n = (cksum.length < keybytes - pos) ? cksum.length : keybytes - pos;212memcpy(rndin.data + pos, cksum.contents, n);213}214215kb_out->enctype = etype;216kb_out->length = keylength;217kb_out->contents = ealloc(keylength);218check(krb5_c_random_to_key(NULL, etype, &rndin, kb_out));219free(cksum.contents);220free(rndin.data);221free(hashstr);222}223224/* Return key data for the given key/salt tuple strings, using hashes of the225* enctypes, salts, and princstr for the key contents. */226static void227make_keys(char **strings, const char *princstr, const krb5_data *realm,228krb5_db_entry *ent)229{230krb5_key_data *key_data, *kd;231krb5_keyblock kb;232int32_t *ks_list_sizes, nstrings, nkeys, i, j;233krb5_key_salt_tuple **ks_lists, *ks;234krb5_kvno *kvnos;235char *s;236237for (nstrings = 0; strings[nstrings] != NULL; nstrings++);238ks_lists = ealloc(nstrings * sizeof(*ks_lists));239ks_list_sizes = ealloc(nstrings * sizeof(*ks_list_sizes));240kvnos = ealloc(nstrings * sizeof(*kvnos));241242/* Convert each string into a key/salt tuple list and count the total243* number of key data structures needed. */244nkeys = 0;245for (i = 0; i < nstrings; i++) {246s = strings[i];247/* Read a leading kvno if present; otherwise assume kvno 1. */248if (isdigit(*s)) {249kvnos[i] = strtol(s, &s, 10);250while (isspace(*s))251s++;252} else {253kvnos[i] = 1;254}255check(krb5_string_to_keysalts(s, NULL, NULL, FALSE, &ks_lists[i],256&ks_list_sizes[i]));257nkeys += ks_list_sizes[i];258}259260/* Turn each key/salt tuple into a key data entry. */261kd = key_data = ealloc(nkeys * sizeof(*kd));262for (i = 0; i < nstrings; i++) {263ks = ks_lists[i];264for (j = 0; j < ks_list_sizes[i]; j++) {265make_keyblock(kvnos[i], ks[j].ks_enctype, ks[j].ks_salttype,266princstr, realm, &kb);267kd->key_data_ver = 2;268kd->key_data_kvno = kvnos[i];269kd->key_data_type[0] = ks[j].ks_enctype;270kd->key_data_length[0] = kb.length;271kd->key_data_contents[0] = kb.contents;272kd->key_data_type[1] = ks[j].ks_salttype;273kd++;274}275}276277for (i = 0; i < nstrings; i++)278free(ks_lists[i]);279free(ks_lists);280free(ks_list_sizes);281free(kvnos);282ent->key_data = key_data;283ent->n_key_data = nkeys;284}285286static void287make_strings(char **stringattrs, krb5_db_entry *ent)288{289struct k5buf buf;290char **p;291const char *str, *sep;292krb5_tl_data *tl;293294k5_buf_init_dynamic(&buf);295for (p = stringattrs; *p != NULL; p++) {296str = *p;297sep = strchr(str, ':');298assert(sep != NULL);299k5_buf_add_len(&buf, str, sep - str);300k5_buf_add_len(&buf, "\0", 1);301k5_buf_add_len(&buf, sep + 1, strlen(sep + 1) + 1);302}303assert(buf.data != NULL);304305tl = ealloc(sizeof(*ent->tl_data));306tl->tl_data_next = NULL;307tl->tl_data_type = KRB5_TL_STRING_ATTRS;308tl->tl_data_length = buf.len;309tl->tl_data_contents = buf.data;310ent->tl_data = tl;311}312313static krb5_error_code314test_init(void)315{316return 0;317}318319static krb5_error_code320test_cleanup(void)321{322return 0;323}324325static krb5_error_code326test_open(krb5_context context, char *conf_section, char **db_args, int mode)327{328testhandle h;329330h = ealloc(sizeof(*h));331h->profile = context->profile;332h->section = estrdup(conf_section);333context->dal_handle->db_context = h;334return 0;335}336337static krb5_error_code338test_close(krb5_context context)339{340testhandle h = context->dal_handle->db_context;341342free(h->section);343free(h);344return 0;345}346347/* Return the principal name krbtgt/tgs_realm@our_realm. */348static krb5_principal349tgtname(krb5_context context, const krb5_data *tgs_realm,350const krb5_data *our_realm)351{352krb5_principal princ;353354check(krb5_build_principal_ext(context, &princ,355our_realm->length, our_realm->data,356KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,357tgs_realm->length, tgs_realm->data, 0));358princ->type = KRB5_NT_SRV_INST;359return princ;360}361362/* Return true if search_for is within context's default realm or is an363* incoming cross-realm TGS name. */364static krb5_boolean365request_for_us(krb5_context context, krb5_const_principal search_for)366{367char *defrealm;368krb5_data realm;369krb5_boolean for_us;370krb5_principal local_tgs;371372check(krb5_get_default_realm(context, &defrealm));373realm = string2data(defrealm);374local_tgs = tgtname(context, &realm, &realm);375krb5_free_default_realm(context, defrealm);376377for_us = krb5_realm_compare(context, local_tgs, search_for) ||378krb5_principal_compare_any_realm(context, local_tgs, search_for);379krb5_free_principal(context, local_tgs);380return for_us;381}382383static krb5_error_code384test_get_principal(krb5_context context, krb5_const_principal search_for,385unsigned int flags, krb5_db_entry **entry)386{387krb5_error_code ret;388krb5_principal princ = NULL, tgtprinc;389krb5_principal_data empty_princ = { KV5M_PRINCIPAL };390testhandle h = context->dal_handle->db_context;391char *search_name = NULL, *canon = NULL, *flagstr;392char **names, **key_strings, **stringattrs;393const char *ename;394krb5_db_entry *ent;395396*entry = NULL;397398if (!request_for_us(context, search_for))399return KRB5_KDB_NOENTRY;400401check(krb5_unparse_name_flags(context, search_for,402KRB5_PRINCIPAL_UNPARSE_NO_REALM,403&search_name));404canon = get_string(h, "alias", search_name, NULL);405if (canon != NULL) {406check(krb5_parse_name(context, canon, &princ));407if (!krb5_realm_compare(context, search_for, princ)) {408/* Out of realm */409if ((flags & KRB5_KDB_FLAG_CLIENT) &&410(flags & KRB5_KDB_FLAG_REFERRAL_OK)) {411/* Return a client referral by creating an entry with only the412* principal set. */413*entry = ealloc(sizeof(**entry));414(*entry)->princ = princ;415princ = NULL;416ret = 0;417goto cleanup;418} else if (flags & KRB5_KDB_FLAG_REFERRAL_OK) {419/* Generate a server referral by looking up the TGT for the420* canonical name's realm. */421tgtprinc = tgtname(context, &princ->realm, &search_for->realm);422krb5_free_principal(context, princ);423princ = tgtprinc;424425krb5_free_unparsed_name(context, search_name);426check(krb5_unparse_name_flags(context, princ,427KRB5_PRINCIPAL_UNPARSE_NO_REALM,428&search_name));429ename = search_name;430} else {431ret = KRB5_KDB_NOENTRY;432goto cleanup;433}434} else {435ename = canon;436}437} else {438check(krb5_copy_principal(context, search_for, &princ));439ename = search_name;440}441442/* Check that the entry exists. */443set_names(h, "princs", ename, NULL);444ret = profile_get_relation_names(h->profile, h->names, &names);445if (ret == PROF_NO_RELATION) {446ret = KRB5_KDB_NOENTRY;447goto cleanup;448}449profile_free_list(names);450451/* No error exits after this point. */452453ent = ealloc(sizeof(*ent));454ent->princ = princ;455princ = NULL;456457flagstr = get_string(h, "princs", ename, "flags");458if (flagstr != NULL) {459check(krb5_flagspec_to_mask(flagstr, &ent->attributes,460&ent->attributes));461}462free(flagstr);463464ent->max_life = get_duration(h, "princs", ename, "maxlife");465ent->max_renewable_life = get_duration(h, "princs", ename, "maxrenewlife");466ent->expiration = get_time(h, "princs", ename, "expiration");467ent->pw_expiration = get_time(h, "princs", ename, "pwexpiration");468469/* Leave last_success, last_failed, fail_auth_count zeroed. */470/* Leave e_data empty. */471472set_names(h, "princs", ename, "keys");473ret = profile_get_values(h->profile, h->names, &key_strings);474if (ret != PROF_NO_RELATION) {475make_keys(key_strings, ename, &search_for->realm, ent);476profile_free_list(key_strings);477}478479set_names(h, "princs", ename, "strings");480ret = profile_get_values(h->profile, h->names, &stringattrs);481if (ret != PROF_NO_RELATION) {482make_strings(stringattrs, ent);483profile_free_list(stringattrs);484}485486/* We must include mod-princ data or kadm5_get_principal() won't work and487* we can't extract keys with kadmin.local. */488check(krb5_dbe_update_mod_princ_data(context, ent, 0, &empty_princ));489490*entry = ent;491ret = 0;492493cleanup:494krb5_free_unparsed_name(context, search_name);495krb5_free_principal(context, princ);496free(canon);497return ret;498}499500static void501lookup_princ_by_cert(krb5_context context, const krb5_data *client_cert,502krb5_principal *princ)503{504krb5_error_code ret;505char *cert_princ_name;506507/* The test client sends a principal string instead of a cert. */508cert_princ_name = k5memdup0(client_cert->data, client_cert->length, &ret);509check(ret);510511check(krb5_parse_name_flags(context, cert_princ_name,512KRB5_PRINCIPAL_PARSE_ENTERPRISE, princ));513free(cert_princ_name);514}515516static krb5_error_code517test_get_s4u_x509_principal(krb5_context context, const krb5_data *client_cert,518krb5_const_principal princ, unsigned int flags,519krb5_db_entry **entry)520{521krb5_error_code ret;522krb5_principal cert_princ, canon_princ;523testhandle h = context->dal_handle->db_context;524krb5_boolean match;525char *canon, *princ_name;526527lookup_princ_by_cert(context, client_cert, &cert_princ);528529ret = test_get_principal(context, cert_princ, flags, entry);530krb5_free_principal(context, cert_princ);531if (ret || (flags & KRB5_KDB_FLAG_REFERRAL_OK))532return ret;533534if (!krb5_realm_compare(context, princ, (*entry)->princ))535abort();536537if (princ->length == 0 ||538krb5_principal_compare(context, princ, (*entry)->princ))539return 0;540541match = FALSE;542check(krb5_unparse_name_flags(context, princ,543KRB5_PRINCIPAL_UNPARSE_NO_REALM,544&princ_name));545canon = get_string(h, "alias", princ_name, NULL);546krb5_free_unparsed_name(context, princ_name);547if (canon != NULL) {548check(krb5_parse_name(context, canon, &canon_princ));549match = krb5_principal_compare(context, canon_princ, (*entry)->princ);550krb5_free_principal(context, canon_princ);551}552553free(canon);554return match ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH;555}556557static krb5_error_code558test_fetch_master_key(krb5_context context, krb5_principal mname,559krb5_keyblock *key_out, krb5_kvno *kvno_out,560char *db_args)561{562memset(key_out, 0, sizeof(*key_out));563*kvno_out = 0;564return 0;565}566567static krb5_error_code568test_fetch_master_key_list(krb5_context context, krb5_principal mname,569const krb5_keyblock *key,570krb5_keylist_node **mkeys_out)571{572/* krb5_dbe_get_mkvno() returns an error if we produce NULL, so return an573* empty node to make kadm5_get_principal() work. */574*mkeys_out = ealloc(sizeof(**mkeys_out));575return 0;576}577578static krb5_error_code579test_decrypt_key_data(krb5_context context, const krb5_keyblock *mkey,580const krb5_key_data *kd, krb5_keyblock *key_out,581krb5_keysalt *salt_out)582{583key_out->magic = KV5M_KEYBLOCK;584key_out->enctype = kd->key_data_type[0];585key_out->length = kd->key_data_length[0];586key_out->contents = ealloc(key_out->length);587memcpy(key_out->contents, kd->key_data_contents[0], key_out->length);588if (salt_out != NULL) {589salt_out->type = (kd->key_data_ver > 1) ? kd->key_data_type[1] :590KRB5_KDB_SALTTYPE_NORMAL;591salt_out->data = empty_data();592}593return 0;594}595596static krb5_error_code597test_encrypt_key_data(krb5_context context, const krb5_keyblock *mkey,598const krb5_keyblock *key, const krb5_keysalt *salt,599int kvno, krb5_key_data *kd_out)600{601memset(kd_out, 0, sizeof(*kd_out));602kd_out->key_data_ver = 2;603kd_out->key_data_kvno = kvno;604kd_out->key_data_type[0] = key->enctype;605kd_out->key_data_length[0] = key->length;606kd_out->key_data_contents[0] = ealloc(key->length);607memcpy(kd_out->key_data_contents[0], key->contents, key->length);608kd_out->key_data_type[1] = (salt != NULL) ? salt->type :609KRB5_KDB_SALTTYPE_NORMAL;610return 0;611}612613static void614change_auth_indicators(krb5_context context, krb5_data ***auth_indicators)615{616krb5_data **inds, d;617size_t i;618int val;619620/* If we see an auth indicator "dbincrX", replace the whole indicator list621* with "dbincr{X+1}". */622inds = *auth_indicators;623for (i = 0; inds != NULL && inds[i] != NULL; i++) {624if (inds[i]->length == 7 && memcmp(inds[i]->data, "dbincr", 6) == 0) {625val = inds[i]->data[6];626k5_free_data_ptr_list(inds);627inds = ealloc(2 * sizeof(*inds));628d = string2data("dbincr0");629check(krb5_copy_data(context, &d, &inds[0]));630inds[0]->data[6] = val + 1;631inds[1] = NULL;632*auth_indicators = inds;633break;634}635}636}637638static krb5_error_code639test_issue_pac(krb5_context context, unsigned int flags, krb5_db_entry *client,640krb5_keyblock *replaced_reply_key, krb5_db_entry *server,641krb5_db_entry *krb5tgt, krb5_timestamp authtime,642krb5_pac old_pac, krb5_pac new_pac,643krb5_data ***auth_indicators)644{645krb5_data data = empty_data();646krb5_boolean found_logon_info = FALSE;647krb5_ui_4 *types = NULL;648size_t num_buffers = 0, i;649650change_auth_indicators(context, auth_indicators);651652if (old_pac == NULL ||653(client != NULL && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION))) {654/* Generating an initial PAC. */655assert(client != NULL);656data = string2data("fake");657check(krb5_pac_add_buffer(context, new_pac, KRB5_PAC_LOGON_INFO,658&data));659660if (replaced_reply_key != NULL) {661/* Add a fake PAC_CREDENTIALS_INFO buffer so we can test whether662* this parameter was set. */663data = string2data("fake credinfo");664check(krb5_pac_add_buffer(context, new_pac,665KRB5_PAC_CREDENTIALS_INFO, &data));666}667return 0;668} else {669/* Field copying - my favorite! */670if (old_pac != NULL)671check(krb5_pac_get_types(context, old_pac, &num_buffers, &types));672673for (i = 0; i < num_buffers; i++) {674/* Skip buffer types handled by KDC. */675if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||676types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||677types[i] == KRB5_PAC_TICKET_CHECKSUM ||678types[i] == KRB5_PAC_CLIENT_INFO ||679types[i] == KRB5_PAC_DELEGATION_INFO)680continue;681682check(krb5_pac_get_buffer(context, old_pac, types[i], &data));683684if (types[i] == KRB5_PAC_LOGON_INFO) {685found_logon_info = TRUE;686assert(data_eq_string(data, "fake"));687}688689check(krb5_pac_add_buffer(context, new_pac, types[i], &data));690krb5_free_data_contents(context, &data);691}692693if (old_pac != NULL)694assert(found_logon_info);695696free(types);697}698699return 0;700}701702static krb5_boolean703match_in_table(krb5_context context, const char *table, const char *sprinc,704const char *tprinc)705{706testhandle h = context->dal_handle->db_context;707krb5_error_code ret;708char **values, **v;709krb5_boolean found = FALSE;710711set_names(h, table, sprinc, NULL);712ret = profile_get_values(h->profile, h->names, &values);713assert(ret == 0 || ret == PROF_NO_RELATION);714if (ret)715return FALSE;716for (v = values; *v != NULL; v++) {717if (tprinc == NULL || strcmp(*v, tprinc) == 0) {718found = TRUE;719break;720}721}722profile_free_list(values);723return found;724}725726static krb5_error_code727test_check_allowed_to_delegate(krb5_context context,728krb5_const_principal client,729const krb5_db_entry *server,730krb5_const_principal proxy)731{732char *sprinc, *tprinc = NULL;733krb5_boolean found = FALSE;734735check(krb5_unparse_name_flags(context, server->princ,736KRB5_PRINCIPAL_UNPARSE_NO_REALM, &sprinc));737if (proxy != NULL) {738check(krb5_unparse_name_flags(context, proxy,739KRB5_PRINCIPAL_UNPARSE_NO_REALM,740&tprinc));741}742found = match_in_table(context, "delegation", sprinc, tprinc);743krb5_free_unparsed_name(context, sprinc);744krb5_free_unparsed_name(context, tprinc);745return found ? 0 : KRB5KDC_ERR_BADOPTION;746}747748static krb5_error_code749test_allowed_to_delegate_from(krb5_context context,750krb5_const_principal client,751krb5_const_principal server,752krb5_pac server_pac,753const krb5_db_entry *proxy)754{755char *proxy_princ, *server_princ, *pac_client_princ, *client_princ;756krb5_boolean found = FALSE;757758assert(server_pac != NULL);759760check(krb5_unparse_name(context, proxy->princ, &proxy_princ));761check(krb5_unparse_name(context, server, &server_princ));762check(krb5_unparse_name(context, client, &client_princ));763764check(krb5_pac_get_client_info(context, server_pac, NULL,765&pac_client_princ));766767/* Skip realm portion if not present in PAC. */768assert(strncmp(pac_client_princ, server_princ,769strlen(pac_client_princ)) == 0);770771free(pac_client_princ);772773found = match_in_table(context, "rbcd", proxy_princ, server_princ);774krb5_free_unparsed_name(context, proxy_princ);775krb5_free_unparsed_name(context, server_princ);776krb5_free_unparsed_name(context, client_princ);777return found ? 0 : KRB5KDC_ERR_BADOPTION;778}779780kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_test, kdb_function_table) = {781KRB5_KDB_DAL_MAJOR_VERSION, /* major version number */7820, /* minor version number */783test_init,784test_cleanup,785test_open,786test_close,787NULL, /* create */788NULL, /* destroy */789NULL, /* get_age */790NULL, /* lock */791NULL, /* unlock */792test_get_principal,793NULL, /* put_principal */794NULL, /* delete_principal */795NULL, /* rename_principal */796NULL, /* iterate */797NULL, /* create_policy */798NULL, /* get_policy */799NULL, /* put_policy */800NULL, /* iter_policy */801NULL, /* delete_policy */802test_fetch_master_key,803test_fetch_master_key_list,804NULL, /* store_master_key_list */805NULL, /* dbe_search_enctype */806NULL, /* change_pwd */807NULL, /* promote_db */808test_decrypt_key_data,809test_encrypt_key_data,810NULL, /* check_transited_realms */811NULL, /* check_policy_as */812NULL, /* check_policy_tgs */813NULL, /* audit_as_req */814NULL, /* refresh_config */815test_check_allowed_to_delegate,816NULL, /* free_principal_e_data */817test_get_s4u_x509_principal,818test_allowed_to_delegate_from,819test_issue_pac,820};821822823