/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* Copyright 2006, 2009 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*/
/*
*/
/*
* This code was based on code donated to MIT by Novell for
* distribution under the MIT license.
*/
/*
* Include files
*/
#include <stdio.h>
#include <string.h>
#include <k5-int.h>
#include <osconf.h>
#include "kdb5.h"
#include <assert.h>
#include "kdb_log.h"
#include "kdb5int.h"
/* Currently DB2 policy related errors are exported from DAL. But
other databases should set_err function to return string. */
#include "adb_err.h"
/*
* Type definitions
*/
/*
* internal static variable
*/
/*
* Helper Functions
*/
static void
{
}
}
int
{
return k5_mutex_finish_init(&db_lock);
}
static int
{
int err;
if (err)
return err;
return k5_mutex_lock(&db_lock);
}
void
{
}
static int
{
return k5_mutex_unlock(&db_lock);
}
/*
* XXX eventually this should be consolidated with krb5_free_key_data_contents
* so there is only a single version.
*/
void
{
int i, idx;
if (key) {
for (i = 0; i < idx; i++) {
if (key->key_data_contents[i]) {
}
}
}
return;
}
void
{
}
}
void
{
}
}
void
{
}
}
void
{
if (tl_data) {
if (tl_data->tl_data_contents)
}
}
/* Caller must free result*/
static char *
{
return NULL;
/* The profile has to have been initialized. If the profile was
not initialized, expect nothing less than a crash. */
/* realms */
/* under the realm name, database_module */
/* default value is the realm name itself */
&value);
if (status) {
/* some problem */
/* let NULL be handled by the caller */
} else {
/* free profile string */
}
return result;
}
static char *
{
/* realms */
/* under the realm name, database_module */
/* default value is the realm name itself */
&value);
if (status)
goto clean_n_exit;
/* we got the module section. Get the library name from the module */
/* default to db2 */
&lib);
if (status) {
goto clean_n_exit;
}
return result;
}
static void
{
}
#ifdef STATIC_PLUGINS
#ifdef ENABLE_LDAP
#endif
static krb5_error_code
{
#ifdef ENABLE_LDAP
#endif
if (!vftabl_addr) {
"Unable to find requested database type: %s",
lib_name);
return KRB5_KDB_DBTYPE_NOSUP;
}
return ENOMEM;
if (status)
goto cleanup;
return 0;
return status;
}
#else /* KDB5_STATIC_LINK*/
static krb5_error_code
{
int ndx;
/* N.B.: If this is "const" but not "static", the Solaris 10
native compiler has trouble building the library because of
absolute relocations needed in read-only section ".rodata".
When it's static, it goes into ".picdata", which is
read-write. */
static const char *const dbpath_names[] = {
};
return ENOMEM;
/* Fetch the list of directories specified in the config
file(s) first. */
goto clean_n_exit;
ndx = 0;
if (profpath)
ndx++;
goto clean_n_exit;
}
if (ndx)
status = 0;
"Unable to find requested database type: %s", err_str);
goto clean_n_exit;
}
"plugin symbol 'kdb_function_table' lookup failed: %s", err_str);
goto clean_n_exit;
}
if (vftabl_addrs[0] == NULL) {
/* No plugins! */
_("Unable to load requested database module '%s': plugin symbol 'kdb_function_table' not found"),
lib_name);
goto clean_n_exit;
}
goto clean_n_exit;
/* Both of these DTRT with NULL. */
}
return status;
}
#endif /* end of _KDB5_STATIC_LINK */
static krb5_error_code
{
/* lock here so that no two threads try to do the same at the same time */
int locked = 0;
static int kdb_db2_pol_err_loaded = 0;
}
if ((status = kdb_lock_list()) != 0)
goto clean_n_exit;
locked = 1;
goto clean_n_exit;
}
}
/* module not found. create and add to list */
if (status)
goto clean_n_exit;
if (prev_elt) {
/* prev_elt points to the last element in the list */
} else {
}
if (*lib)
(*lib)->reference_cnt++;
if (locked)
return status;
}
static krb5_error_code
{
int locked = 0;
if ((status = kdb_lock_list()) != 0)
goto clean_n_exit;
locked = 1;
lib->reference_cnt--;
if (lib->reference_cnt == 0) {
if (status)
goto clean_n_exit;
/* close the library */
else
}
if (locked)
return status;
}
{
if (dal_handle == NULL) {
goto clean_n_exit;
}
goto clean_n_exit;
}
if (status)
goto clean_n_exit;
if (status) {
if (lib)
}
return status;
}
static krb5_error_code
{
if (status)
return status;
return 0;
}
static void
{
kdb_vftabl *v;
const char *e;
if (err_code == 0)
return;
if (v->errcode_2_string == NULL)
return;
if (v->release_errcode_string)
v->release_errcode_string(kcontext, e);
}
static krb5_error_code
{
*vftabl_ptr = NULL;
if (status)
return status;
}
return 0;
}
/*
* External functions... DAL API
*/
{
kdb_vftabl *v;
"unable to determine configuration section for realm %s\n",
goto clean_n_exit;
}
if (status)
goto clean_n_exit;
if (section)
return status;
}
{
}
{
kdb_vftabl *v;
"unable to determine configuration section for realm %s\n",
goto clean_n_exit;
}
if (status)
goto clean_n_exit;
goto clean_n_exit;
}
if (section)
return status;
}
{
kdb_vftabl *v;
/* Do nothing if module was never loaded. */
return 0;
if (status)
return status;
return kdb_free_lib_handle(kcontext);
}
{
kdb_vftabl *v;
"unable to determine configuration section for realm %s\n",
goto clean_n_exit;
}
if (status)
goto clean_n_exit;
if (v->db_destroy == NULL) {
goto clean_n_exit;
}
if (section)
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_get_age == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_set_option == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_get_principal == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
more);
return status;
}
unsigned int flags,
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_get_principal == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_free_principal == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
static void
{
int i;
if (db_args) {
/* XXX Is this right? Or are we borrowing storage from
the caller? */
for (i = 0; db_args[i]; i++)
}
}
static krb5_error_code
char ***db_argsp)
{
int db_args_size = 0;
/* Giving db_args as part of tl data causes db2 to store the
tl_data as such. To prevent this, tl_data is collated and
passed as a separate argument. Currently supports only one
principal, but passing it as a separate argument makes it
difficult for kadmin remote to pass arguments to server. */
while (curr) {
char **t;
/* Since this is expected to be NULL terminated string and
this could come from any client, do a check before
passing it to db. */
'\0') {
/* Not null terminated. Dangerous input. */
goto clean_n_exit;
}
db_args_size++;
if (t == NULL) {
goto clean_n_exit;
}
db_args = t;
/* current node is the first in the linked list. remove it */
} else {
}
(*count)--;
/* previous does not change */
} else {
}
}
status = 0;
if (status != 0) {
}
return status;
}
{
kdb_vftabl *v;
char **db_args;
if (status)
return status;
if (v->db_put_principal == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
&db_args);
if (status)
return status;
return status;
}
{
kdb_vftabl *v;
int i;
int ulog_locked = 0;
if (status)
goto clean_n_exit;
&db_args);
if (status)
goto clean_n_exit;
if (!(upd = (kdb_incr_update_t *)
goto err_lock;
}
goto err_lock;
}
if (status != 0)
goto err_lock;
ulog_locked = 1;
for (i = 0; i < *nentries; i++) {
if (fupd) {
&princ_name)))
goto err_lock;
goto err_lock;
upd++;
}
}
if (v->db_put_principal == NULL) {
goto err_lock;
}
for (i = 0; i < *nentries; i++) {
upd++;
}
}
if (ulog_locked)
return status;
}
int *nentries)
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_delete_principal == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (status)
return status;
/*
* We'll be sharing the same locks as db for logging
*/
return status;
}
return status;
}
}
if (v->db_delete_principal == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
/*
* We need to commit our update upon success
*/
if (!status)
return status;
}
char *match_entry,
/* Solaris Kerberos: adding support for db_args */
char **db_args)
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_iterate == NULL)
return 0;
/* Solaris Kerberos: adding support for db_args */
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_supported_realms == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_free_supported_realms == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
return status;
}
{
}
{
kdb_vftabl *v;
if (status)
return status;
return status;
}
/* Solaris Kerberos: return a read only pointer alias to mkey list */
{
}
/*
* Solaris Kerberos: removed unused mkvno arg and lots of changes to fix mem
* leaks.
*/
const krb5_keyblock *mkey)
{
kdb_vftabl *v;
if (status)
return status;
if (status)
return status;
}
if (status == 0) {
} else {
}
return status;
}
char *keyfile,
{
kdb_vftabl *v;
if (status)
return status;
if (v->store_master_key == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
if (status)
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->store_master_key_list == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return KRB5_KDB_DBNOTINITED;
if (status)
return status;
}
char * db_args,
krb5_keyblock * key)
{
if (fromkeyboard) {
twice ? krb5_mkey_pwd_prompt2 : 0,
goto clean_n_exit;
}
if (!salt) {
if (retval)
goto clean_n_exit;
}
/*
* Solaris Kerberos: If the enc type is unknown then we revert back to
* the default enc type since we don't have the luxury of finding this
* in the stash file when reading the password from the keyboard.
*/
if (etype == ENCTYPE_UNKNOWN)
retval =
key);
/*
* If a kvno pointer was passed in and it dereferences the IGNORE_VNO
* value then it should be assigned the value of the kvno associated
* with the current mkey princ key if that princ entry is available
* otherwise assign 1 which is the default kvno value for the mkey
* princ.
*/
else
*kvno = 1;
}
if (!salt)
} else {
kdb_vftabl *v;
if (retval)
goto clean_n_exit;
}
/* get the enctype from the stash */
if (retval)
goto clean_n_exit;
goto clean_n_exit;
}
}
}
return retval;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->verify_master_key == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
int nprinc;
/* Solaris Kerberos: fix mem leaks */
if (act_key_list == NULL)
return (EINVAL);
nprinc = 1;
return (retval);
}
if (nprinc != 1) {
if (nprinc) {
return (KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
} else {
return(KRB5_KDB_NOMASTERKEY);
}
} else if (more) {
return (KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
}
/* Solaris Kerberos: fix mem leaks */
if (retval == 0) {
if (tmp_act_key_list == NULL) {
/*
* for mkey princ entries without KRB5_TL_ACTKVNO data provide a default
*/
if (tmp_actkvno == NULL)
return (ENOMEM);
/* use most current key */
} else {
}
}
return retval;
}
/*
* Locates the "active" mkey used when encrypting a princ's keys. Note, the
* caller must NOT free the output act_mkey.
*/
{
if (act_mkey_list == NULL) {
*act_kvno = 0;
return 0;
}
if (!cur_keyblock)
return KRB5_KDB_DBNOTINITED;
return (retval);
/*
* The list should be sorted in time, early to later so if the first entry
* is later than now, this is a problem. The fallback in this case is to
* return the earlist activation entry.
*/
if (cur_keyblock) {
return (0);
} else {
return (KRB5_KDB_NOACTMASTERKEY);
}
}
/* find the most current entry <= now */
break;
break;
}
}
if (!found) {
/*
* The end of the list was encountered and all entries are < now so use
* the latest entry.
*/
else
return KRB5_KDB_NOACTMASTERKEY; /* This shouldn't happen. */
}
if (cur_keyblock) {
*act_kvno = tmp_act_kvno;
return (0);
} else {
return KRB5_KDB_NO_MATCHING_KEY;
}
}
/*
* Locates the mkey used to protect a princ's keys. Note, the caller must not
* free the output key.
*/
krb5_keyblock ** mkey)
{
if (!cur_keyblock)
return KRB5_KDB_DBNOTINITED;
if (retval)
return (retval);
if (cur_keyblock) {
return (0);
} else {
return KRB5_KDB_NO_MATCHING_KEY;
}
}
void *
{
kdb_vftabl *v;
if (status)
return NULL;
}
void
{
kdb_vftabl *v;
if (status)
return;
}
/* has to be modified */
{
}
krb5_int32 * start,
{
kdb_vftabl *v;
if (status)
return status;
return status;
}
const char *keyname,
const char *realm,
{
char *fname;
if (!keyname)
return ENOMEM;
return retval;
if (fullname)
else
return 0;
}
{
return (code);
*stamp = 0;
return (0);
}
return (0);
}
{
*ret_tl_data = *tl_data;
return (0);
}
}
/*
* If the requested record isn't found, return zero bytes. If it
* ever means something to have a zero-length tl_data, this code
* and its callers will have to be changed.
*/
ret_tl_data->tl_data_length = 0;
return (0);
}
{
(sizeof(krb5_key_data) *
return (ENOMEM);
entry->n_key_data++;
return 0;
}
{
char *unparse_mod_princ = 0;
unsigned int unparse_mod_princ_size;
return (retval);
== NULL) {
return (ENOMEM);
}
/* Mod Date */
/* Mod Princ */
return (retval);
}
{
*mod_time = 0;
return (code);
return (KRB5_KDB_TRUNCATED_RECORD);
/* Mod Date */
/* Mod Princ */
mod_princ)))
return (code);
return (0);
}
{
return (code);
if (tl_data.tl_data_length == 0) {
*mkvno = 0; /* Indicates KRB5_TL_MKVNO data not present */
return (0);
return (KRB5_KDB_TRUNCATED_RECORD);
}
return (0);
}
{
return KRB5_KDB_DBNOTINITED;
/* Output the value from entry tl_data if present. */
if (code != 0)
return code;
if (kvno != 0) {
return 0;
}
/* Determine the minimum kvno in mkey_list and output that. */
}
return 0;
}
{
}
{
return (code);
return (0);
} else {
/* get version to determine how to parse the data */
if (version == 1) {
/* variable size, must be at least 10 bytes */
return (KRB5_KDB_TRUNCATED_RECORD);
/* curloc points to first tuple entry in the tl_data_contents */
return (ENOMEM);
}
return (ENOMEM);
}
/* always using key data ver 1 for mkeys */
else
}
} else {
"Illegal version number for KRB5_TL_MKEY_AUX %d\n",
version);
return (KRB5_KDB_BAD_VERSION);
}
}
return (0);
}
#if KRB5_TL_MKEY_AUX_VER == 1
{
unsigned char *nextloc;
if (!mkey_aux_data_list) {
/* delete the KRB5_TL_MKEY_AUX from the entry */
return (0);
}
/*
* determine out how much space to allocate. Note key_data_ver not stored
* as this is hard coded to one and is accounted for in
* krb5_dbe_lookup_mkey_aux.
*/
sizeof(krb5_ui_2) + /* latest_mkey kvno */
sizeof(krb5_ui_2) + /* latest_mkey enctype */
sizeof(krb5_ui_2) + /* latest_mkey length */
}
return (ENOMEM);
nextloc);
nextloc);
nextloc);
}
}
}
#endif /* KRB5_TL_MKEY_AUX_VER == 1 */
#if KRB5_TL_ACTKVNO_VER == 1
/*
* If version of the KRB5_TL_ACTKVNO data is KRB5_TL_ACTKVNO_VER == 1 then size of
* a actkvno tuple {act_kvno, act_time} entry is:
*/
#endif
{
unsigned int num_actkvno, i;
return (code);
*actkvno_list = NULL;
return (0);
} else {
/* get version to determine how to parse the data */
if (version == 1) {
/* variable size, must be at least 8 bytes */
return (KRB5_KDB_TRUNCATED_RECORD);
/*
* Find number of tuple entries, remembering to account for version
* field.
*/
/* next_tuple points to first tuple entry in the tl_data_contents */
for (i = 0; i < num_actkvno; i++) {
return (ENOMEM);
}
/* using tmp_kvno to avoid type mismatch */
else
}
} else {
"Illegal version number for KRB5_TL_ACTKVNO %d\n",
version);
return (KRB5_KDB_BAD_VERSION);
}
}
return (0);
}
/*
* Add KRB5_TL_ACTKVNO TL data entries to krb5_db_entry *entry
*/
#if KRB5_TL_ACTKVNO_VER == 1
const krb5_actkvno_node *actkvno_list)
{
unsigned char *nextloc;
if (actkvno_list == NULL)
return EINVAL;
/* allocate initial KRB5_TL_ACTKVNO tl_data entry */
return ENOMEM;
/* add the current version # for the data format used for KRB5_TL_ACTKVNO */
return ENOMEM;
} else {
}
/*
* Using realloc so tl_data_contents is required to correctly calculate
* next location to store new tuple.
*/
/* using tmp_kvno to avoid type mismatch issues */
}
return (retval);
}
#endif /* KRB5_TL_ACTKVNO_VER == 1 */
{
}
{
/*
* Find existing entries of the specified type and remove them from the
* entry's tl_data list.
*/
/* remove from head */
/* remove from tail */
} else {
/* remove in between */
}
} else {
}
}
return (0);
}
{
/*
* Copy the new data first, so we can fail cleanly if malloc()
* fails.
*/
if ((tmp =
return (ENOMEM);
/*
* Find an existing entry of the specified type and point at
* it, or NULL if not found.
*/
break;
}
/* If necessary, chain a new record in the beginning and point at it. */
if (!tl_data) {
return (ENOMEM);
}
}
/* fill in the record */
if (tl_data->tl_data_contents)
return (0);
}
/* change password functions */
int ks_tuple_count,
char *passwd,
{
kdb_vftabl *v;
if (status)
return status;
return status;
}
/* policy management functions */
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_create_policy == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_get_policy == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_put_policy == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_iter_policy == NULL)
return 0;
return status;
}
{
kdb_vftabl *v;
if (status)
return status;
if (v->db_delete_policy == NULL)
return KRB5_KDB_DBTYPE_NOSUP;
return status;
}
void
{
kdb_vftabl *v;
return;
}
{
kdb_vftabl *v;
"unable to determine configuration section for realm %s\n",
goto clean_n_exit;
}
if (status)
goto clean_n_exit;
return status;
}
static krb5_error_code
{
kdb_vftabl *v;
if (status)
return status;
for (; n; n = n->next) {
keysalt);
if (status == 0)
return 0;
}
return status;
}
const krb5_keyblock * mkey,
const krb5_key_data * key_data,
{
kdb_vftabl *v;
if (status)
return status;
if (status == 0)
return 0;
/* Try reloading master keys. */
cur_mkey) == 0)
}
return status;
}
const krb5_keyblock * mkey,
const krb5_keyblock * dbkey,
const krb5_keysalt * keysalt,
int keyver,
{
kdb_vftabl *v;
if (status)
return status;
key_data);
}
{
if (*db_context == NULL)
return KRB5_KDB_DBNOTINITED;
return 0;
}
{
return 0;
}
unsigned int method,
{
kdb_vftabl *v;
if (status)
return status;
return KRB5_KDB_DBTYPE_NOSUP;
}
/*
* Solaris Kerberos: support for iprop
*
* Not all KDB plugins support iprop.
*
* sets iprop_supported to 1 if iprop supportd, 0 otherwise.
*/
{
/* gtbtmp183 */
*iprop_supported = TRUE;
return status;
#if 0 /* gtbtmp183 */
if (status) {
goto clean_n_exit;
}
}
if (status) {
goto clean_n_exit;
}
return status;
#endif
}