/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* lib/kdb/keytab.c */2/*3* Copyright 1995 by the Massachusetts Institute of Technology.4* All Rights Reserved.5*6* Export of this software from the United States of America may7* require a specific license from the United States Government.8* It is the responsibility of any person or organization contemplating9* export to obtain such a license before exporting.10*11* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and12* distribute this software and its documentation for any purpose and13* without fee is hereby granted, provided that the above copyright14* notice appear in all copies and that both that copyright notice and15* this permission notice appear in supporting documentation, and that16* the name of M.I.T. not be used in advertising or publicity pertaining17* to distribution of the software without specific, written prior18* permission. Furthermore if you modify this software you must label19* your software as modified software and not distribute it in such a20* fashion that it might be confused with the original M.I.T. software.21* M.I.T. makes no representations about the suitability of22* this software for any purpose. It is provided "as is" without express23* or implied warranty.24*/2526#include <string.h>2728#include "k5-int.h"29#include "kdb_kt.h"3031static int32is_xrealm_tgt(krb5_context, krb5_const_principal);3334krb5_error_code krb5_ktkdb_close (krb5_context, krb5_keytab);3536krb5_error_code krb5_ktkdb_get_entry (krb5_context, krb5_keytab, krb5_const_principal,37krb5_kvno, krb5_enctype, krb5_keytab_entry *);3839static krb5_error_code40krb5_ktkdb_get_name(krb5_context context, krb5_keytab keytab,41char *name, unsigned int namelen)42{43if (strlcpy(name, "KDB:", namelen) >= namelen)44return KRB5_KT_NAME_TOOLONG;45return 0;46}4748krb5_kt_ops krb5_kt_kdb_ops = {490,50"KDB", /* Prefix -- this string should not appear anywhere else! */51krb5_ktkdb_resolve, /* resolve */52krb5_ktkdb_get_name, /* get_name */53krb5_ktkdb_close, /* close */54krb5_ktkdb_get_entry, /* get */55NULL, /* start_seq_get */56NULL, /* get_next */57NULL, /* end_get */58NULL, /* add (extended) */59NULL, /* remove (extended) */60};6162typedef struct krb5_ktkdb_data {63char * name;64} krb5_ktkdb_data;6566krb5_error_code67krb5_db_register_keytab(krb5_context context)68{69return krb5_kt_register(context, &krb5_kt_kdb_ops);70}7172krb5_error_code73krb5_ktkdb_resolve(krb5_context context, const char *name, krb5_keytab *id)74{75if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)76return(ENOMEM);77(*id)->ops = &krb5_kt_kdb_ops;78(*id)->magic = KV5M_KEYTAB;79return(0);80}8182krb5_error_code83krb5_ktkdb_close(krb5_context context, krb5_keytab kt)84{85/*86* This routine is responsible for freeing all memory allocated87* for this keytab. There are no system resources that need88* to be freed nor are there any open files.89*90* This routine should undo anything done by krb5_ktkdb_resolve().91*/9293kt->ops = NULL;94free(kt);9596return 0;97}9899static krb5_context ktkdb_ctx = NULL;100101/*102* Set a different context for use with ktkdb_get_entry(). This is103* primarily useful for kadmind, where the gssapi library context,104* which will be used for the keytab, will necessarily have a105* different context than that used by the kadm5 library to access the106* database for its own purposes.107*/108krb5_error_code109krb5_ktkdb_set_context(krb5_context ctx)110{111ktkdb_ctx = ctx;112return 0;113}114115krb5_error_code116krb5_ktkdb_get_entry(krb5_context in_context, krb5_keytab id,117krb5_const_principal principal, krb5_kvno kvno,118krb5_enctype enctype, krb5_keytab_entry *entry)119{120krb5_context context;121krb5_error_code kerror = 0;122krb5_key_data * key_data;123krb5_db_entry * db_entry;124int xrealm_tgt;125krb5_boolean similar;126127if (ktkdb_ctx)128context = ktkdb_ctx;129else130context = in_context;131132xrealm_tgt = is_xrealm_tgt(context, principal);133134/* Check whether database is inited. Open is commented */135if ((kerror = krb5_db_inited(context)))136return(kerror);137138/* get_principal */139kerror = krb5_db_get_principal(context, principal, 0, &db_entry);140if (kerror == KRB5_KDB_NOENTRY)141return(KRB5_KT_NOTFOUND);142if (kerror)143return(kerror);144145if (db_entry->attributes & KRB5_KDB_DISALLOW_SVR146|| db_entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX) {147kerror = KRB5_KT_NOTFOUND;148goto error;149}150151/* match key */152/* For cross realm tgts, we match whatever enctype is provided;153* for other principals, we only match the first enctype that is154* found. Since the TGS and AS code do the same thing, then we155* will only successfully decrypt tickets we have issued.*/156kerror = krb5_dbe_find_enctype(context, db_entry,157xrealm_tgt?enctype:-1,158-1, kvno, &key_data);159if (kerror == KRB5_KDB_NO_MATCHING_KEY)160kerror = KRB5_KT_KVNONOTFOUND;161if (kerror)162goto error;163164165kerror = krb5_dbe_decrypt_key_data(context, NULL, key_data,166&entry->key, NULL);167if (kerror)168goto error;169170if (enctype > 0) {171kerror = krb5_c_enctype_compare(context, enctype,172entry->key.enctype, &similar);173if (kerror)174goto error;175176if (!similar) {177kerror = KRB5_KDB_NO_PERMITTED_KEY;178goto error;179}180}181/*182* Coerce the enctype of the output keyblock in case we got an183* inexact match on the enctype.184*/185entry->key.enctype = enctype;186187kerror = krb5_copy_principal(context, principal, &entry->principal);188if (kerror)189goto error;190191/* Close database */192error:193krb5_db_free_principal(context, db_entry);194/* krb5_db_close_database(context); */195return(kerror);196}197198/*199* is_xrealm_tgt: Returns true if the principal is a cross-realm TGT200* principal-- a principal with first component krbtgt and second201* component not equal to realm.202*/203static int204is_xrealm_tgt(krb5_context context, krb5_const_principal princ)205{206krb5_data *dat;207if (krb5_princ_size(context, princ) != 2)208return 0;209dat = krb5_princ_component(context, princ, 0);210if (strncmp("krbtgt", dat->data, dat->length) != 0)211return 0;212dat = krb5_princ_component(context, princ, 1);213if (dat->length != princ->realm.length)214return 1;215if (strncmp(dat->data, princ->realm.data, dat->length) == 0)216return 0;217return 1;218219}220221222