svr_principal.c revision 661b8ac7d0f039c645db17e87130c2c1eebeda1c
/*
*/
/*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
* Openvision retains the copyright to derivative works of
* this source code. Do *NOT* create a derivative of this
* source code before consulting with your legal department.
* Do *NOT* integrate *ANY* of this source code into another
* product before consulting with your legal department.
*
* For further information, read the top-level Openvision
* copyright which is contained in the top-level MIT Kerberos
* copyright.
*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
*/
/*
* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
*
* $Header$
*/
#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header$";
#endif
#include <errno.h>
#include "server_internal.h"
#include <kdb.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <k5-int.h>
#include <kadm5/server_internal.h>
#ifdef USE_PASSWORD_SERVER
#endif
extern krb5_principal master_princ;
extern krb5_principal hist_princ;
extern krb5_keyblock hist_key;
extern krb5_db_entry master_db;
extern krb5_db_entry hist_db;
static krb5_error_code
{
register krb5_principal tempprinc;
register int i, nelems;
if (tempprinc == 0)
return ENOMEM;
return ENOMEM;
}
for (i = 0; i < nelems; i++) {
while (--i >= 0)
return ENOMEM;
}
if (len)
}
for (i = 0; i < nelems; i++)
return ENOMEM;
}
return 0;
}
static void
{
register krb5_int32 i;
if (!val)
return;
while(--i >= 0)
}
}
/*
* XXX Functions that ought to be in libkrb5.a, but aren't.
*/
{
int i, idx;
for (i = 0; i < idx; i++) {
if ( from->key_data_length[i] ) {
for (i = 0; i < idx; i++) {
if (to->key_data_contents[i]) {
to->key_data_length[i]);
}
}
return ENOMEM;
}
from->key_data_length[i]);
}
}
return 0;
}
{
krb5_tl_data *n;
if (n == NULL)
return NULL;
if (n->tl_data_contents == NULL) {
free(n);
return NULL;
}
n->tl_data_next = NULL;
return n;
}
int count;
{
int i, j;
for (i = 0; i < count; i++)
for (j = 0; j < data[i].key_data_ver; j++)
if (data[i].key_data_length[j])
}
char *password)
{
return
}
char *password)
{
unsigned int ret;
/*
* Argument sanity checking, and opening up the DB
*/
return KADM5_BAD_MASK;
if((mask & ~ALL_PRINC_MASK))
return KADM5_BAD_MASK;
return EINVAL;
/*
* Check to see if the principal exists
*/
switch(ret) {
case KADM5_UNK_PRINC:
/* Solaris Kerberos */
break;
case 0:
/*
* Solaris Kerberos: this allows an addprinc to be done on a mix-in
* princ which has no keys initially.
*/
if (kdb.n_key_data != 0) {
/* have a princ with keys, return dupe princ error */
return KADM5_DUP;
} else {
/*
* have a princ with no keys, let's replace it. Note, want to
* keep the existing kdb tl_data (specifically the LDAP plugin
* adds the DN to the tl_data which is needed to locate the dir.
* entry).
*/
}
break;
default:
return ret;
}
/*
* If a policy was specified, load it.
* If we can not find the one specified return an error
*/
if ((mask & KADM5_POLICY)) {
return KADM5_BAD_POLICY;
else
return ret;
}
}
if (mask & KADM5_POLICY)
return ret;
}
/*
* Start populating the various DB fields, using the
* "defaults" for fields that were not specified by the
* mask.
*/
if (mask & KADM5_POLICY)
return ret;
}
/*
* Solaris Kerberos:
* If KADM5_ATTRIBUTES is set, we want to rope in not only
* entry->attributes, but also the generic params.flags
* obtained previously via kadm5_get_config_params.
*/
if ((mask & KADM5_ATTRIBUTES)) {
} else {
}
if ((mask & KADM5_MAX_LIFE))
else
if (mask & KADM5_MAX_RLIFE)
else
if ((mask & KADM5_PRINC_EXPIRE_TIME))
else
kdb.pw_expiration = 0;
if ((mask & KADM5_POLICY)) {
if(polent.pw_max_life)
else
kdb.pw_expiration = 0;
}
if ((mask & KADM5_PW_EXPIRATION))
kdb.last_success = 0;
kdb.last_failed = 0;
kdb.fail_auth_count = 0;
/* this is kind of gross, but in order to free the tl data, I need
to free the entire kdb entry, and that will try to free the
principal. */
if (mask & KADM5_POLICY)
return(ret);
}
if (mask & KADM5_POLICY)
return(ret);
}
if (mask & KADM5_TL_DATA) {
/* splice entry->tl_data onto the front of kdb.tl_data */
{
if( ret )
{
if (mask & KADM5_POLICY)
return ret;
}
}
}
/* initialize the keys */
if (mask & KADM5_POLICY)
return(ret);
}
/* populate the admin-server-specific fields. In the OV server,
this used to be in a separate database. Since there's already
marshalling code for the admin fields, to keep things simple,
I'm going to keep it, and make all the admin stuff occupy a
single tl_data record, */
if ((mask & KADM5_POLICY)) {
/* this does *not* need to be strdup'ed, because adb is xdr */
/* encoded in osa_adb_create_princ, and not ever freed */
}
/* increment the policy ref count, if any */
if ((mask & KADM5_POLICY)) {
!= KADM5_OK) {
if (mask & KADM5_POLICY)
return(ret);
}
}
/* In all cases key and the principal data is set, let the database provider know */
/* store the new db entry */
if (ret) {
if ((mask & KADM5_POLICY)) {
/* decrement the policy ref count */
/*
* if this fails, there's nothing we can do anyway. the
* policy refcount wil be too high.
*/
}
if (mask & KADM5_POLICY)
return(ret);
}
if (mask & KADM5_POLICY)
return KADM5_OK;
}
{
unsigned int ret;
return EINVAL;
return(ret);
== KADM5_OK) {
!= KADM5_OK) {
return(ret);
}
}
return ret;
}
}
return ret;
}
{
(mask & KADM5_LAST_FAILED))
return KADM5_BAD_MASK;
if((mask & ~ALL_PRINC_MASK))
return KADM5_BAD_MASK;
return KADM5_BAD_MASK;
return EINVAL;
if (mask & KADM5_TL_DATA) {
while (tl_data_orig) {
return KADM5_BAD_TL_TYPE;
}
}
if (ret)
return(ret);
/*
* This is pretty much the same as create ...
*/
if ((mask & KADM5_POLICY)) {
/* get the new policy */
if (ret) {
switch (ret) {
case EINVAL:
break;
case KADM5_UNK_POLICY:
case KADM5_BAD_POLICY:
break;
}
goto done;
}
have_npol = 1;
/* if we already have a policy, get it to decrement the refcnt */
/* ... but not if the old and new are the same */
switch(ret) {
case EINVAL:
case KADM5_BAD_POLICY:
case KADM5_UNK_POLICY:
break;
case KADM5_OK:
have_opol = 1;
break;
default:
goto done;
break;
}
}
} else npol.policy_refcnt++;
/* set us up to use the new policy */
/* set pw_max_life based on new policy */
if (npol.pw_max_life) {
&(kdb.pw_expiration));
if (ret)
goto done;
} else {
kdb.pw_expiration = 0;
}
}
if ((mask & KADM5_POLICY_CLR) &&
switch(ret) {
case EINVAL:
case KADM5_BAD_POLICY:
case KADM5_UNK_POLICY:
ret = KADM5_BAD_DB;
goto done;
break;
case KADM5_OK:
have_opol = 1;
kdb.pw_expiration = 0;
break;
default:
goto done;
break;
}
}
(((have_opol) &&
(ret =
KADM5_REF_COUNT))) ||
((have_npol) &&
(ret =
KADM5_REF_COUNT)))))
goto done;
if ((mask & KADM5_ATTRIBUTES))
if ((mask & KADM5_MAX_LIFE))
if ((mask & KADM5_PRINC_EXPIRE_TIME))
if (mask & KADM5_PW_EXPIRATION)
if (mask & KADM5_MAX_RLIFE)
if (mask & KADM5_FAIL_AUTH_COUNT)
if((mask & KADM5_KVNO)) {
for (i = 0; i < kdb.n_key_data; i++)
}
if (mask & KADM5_TL_DATA) {
/* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
{
if( ret )
{
goto done;
}
}
}
/* let the mask propagate to the database provider */
done:
if (have_opol) {
}
if (have_npol) {
}
return ret;
}
{
int ret, i;
return EINVAL;
return(KADM5_DUP);
}
return ret;
/* this is kinda gross, but unavoidable */
for (i=0; i<kdb.n_key_data; i++) {
goto done;
}
}
if (ret) {
goto done;
}
goto done;
done:
return ret;
}
long in_mask)
{
krb5_error_code ret = 0;
long mask;
int i;
/*
* In version 1, all the defined fields are always returned.
* entry is a pointer to a kadm5_principal_ent_t_v1 that should be
* filled with allocated memory.
*/
entry_orig = entry;
entry = &entry_local;
} else {
}
return EINVAL;
return ret;
if ((mask & KADM5_POLICY) &&
goto done;
}
}
if (mask & KADM5_AUX_ATTRIBUTES)
if ((mask & KADM5_PRINCIPAL) &&
goto done;
}
if (mask & KADM5_PRINC_EXPIRE_TIME)
if ((mask & KADM5_LAST_PWD_CHANGE) &&
&(entry->last_pwd_change)))) {
goto done;
}
if (mask & KADM5_PW_EXPIRATION)
if (mask & KADM5_MAX_LIFE)
/* this is a little non-sensical because the function returns two */
/* values that must be checked separately against the mask */
if (ret) {
goto done;
}
if (! (mask & KADM5_MOD_TIME))
if (! (mask & KADM5_MOD_NAME)) {
}
}
if (mask & KADM5_ATTRIBUTES)
if (mask & KADM5_KVNO)
else {
/* XXX I'll be damned if I know how to deal with this one --marc */
}
/*
* The new fields that only exist in version 2 start here
*/
if (mask & KADM5_MAX_RLIFE)
if (mask & KADM5_LAST_SUCCESS)
if (mask & KADM5_LAST_FAILED)
if (mask & KADM5_FAIL_AUTH_COUNT)
if (mask & KADM5_TL_DATA) {
while (tl) {
goto done;
}
}
}
}
if (mask & KADM5_KEY_DATA) {
if(entry->n_key_data) {
goto done;
}
} else
for (i = 0; i < entry->n_key_data; i++)
if (ret)
goto done;
}
}
/*
* If KADM5_API_VERSION_1, we return an allocated structure, and
* we need to convert the new structure back into the format the
* caller is expecting.
*/
goto done;
}
}
done:
return ret;
}
/*
* Function: check_pw_reuse
*
* Purpose: Check if a key appears in a list of keys, in order to
* enforce password history.
*
* Arguments:
*
* context (r) the krb5 context
* hist_keyblock (r) the key that hist_key_data is
* encrypted in
* n_new_key_data (r) length of new_key_data
* new_key_data (r) keys to check against
* pw_hist_data, encrypted in hist_keyblock
* n_pw_hist_data (r) length of pw_hist_data
* pw_hist_data (r) passwords to check new_key_data against
*
* Effects:
* For each new_key in new_key_data:
* decrypt new_key with the master_keyblock
* for each password in pw_hist_data:
* for each hist_key in password:
* decrypt hist_key with hist_keyblock
* compare the new_key and hist_key
*
* Returns krb5 errors, KADM5_PASS_RESUSE if a key in
* new_key_data is the same as a key in pw_hist_data, or 0.
*/
static kadm5_ret_t
{
int x, y, z;
for (x = 0; x < n_new_key_data; x++) {
&(new_key_data[x]),
if (ret)
return(ret);
for (y = 0; y < n_pw_hist_data; y++) {
for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
&pw_hist_data[y].key_data[z],
if (ret)
return(ret);
return(KADM5_PASS_REUSE);
}
}
}
}
return(0);
}
/*
* Function: create_history_entry
*
* Purpose: Creates a password history entry from an array of
* key_data.
*
* Arguments:
*
* context (r) krb5_context to use
* master_keyblcok (r) master key block
* n_key_data (r) number of elements in key_data
* key_data (r) keys to add to the history entry
* hist (w) history entry to fill in
*
* Effects:
*
* hist->key_data is allocated to store n_key_data key_datas. Each
* element of key_data is decrypted with master_keyblock, re-encrypted
* in hist_key, and added to hist->key_data. hist->n_key_data is
* set to n_key_data.
*/
static
{
int i, ret;
return ENOMEM;
for (i = 0; i < n_key_data; i++) {
&key_data[i],
if (ret)
return ret;
if (ret)
return ret;
/* krb5_free_keysalt(context, &salt); */
}
return 0;
}
static
{
int i;
for (i = 0; i < hist->n_key_data; i++)
}
/*
* Function: add_to_history
*
* Purpose: Adds a password to a principal's password history.
*
* Arguments:
*
* context (r) krb5_context to use
* adb (r/w) admin principal entry to add keys to
* pol (r) adb's policy
* pw (r) keys for the password to add to adb's key history
*
* Effects:
*
* add_to_history adds a single password to adb's password history.
* pw contains n_key_data keys in its key_data, in storage should be
* allocated but not freed by the caller (XXX blech!).
*
* This function maintains adb->old_keys as a circular queue. It
* starts empty, and grows each time this function is called until it
* is pol->pw_history_num items long. adb->old_key_len holds the
* number of allocated entries in the array, and must therefore be [0,
* pol->pw_history_num). adb->old_key_next is the index into the
* array where the next element should be written, and must be [0,
* adb->old_key_len).
*/
{
/* A history of 1 means just check the current password */
if (nhist <= 1)
return 0;
/* resize the adb->old_keys array if necessary */
} else {
}
return(ENOMEM);
/*
* To avoid losing old keys, shift forward each entry after
* knext.
*/
}
/*
* The policy must have changed! Shrink the array.
* Can't simply realloc() down, since it might be wrapped.
* To understand the arithmetic below, note that we are
* copying into new positions 0 .. N-1 from old positions
* old_key_next-N .. old_key_next-1, modulo old_key_len,
* where N = pw_history_num - 1 is the length of the
* shortened list. Matt Crawford, FNAL
*/
/*
* M = adb->old_key_len, N = pol->pw_history_num - 1
*
* tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
*/
int j;
tmp = (osa_pw_hist_ent *)
return ENOMEM;
for (i = 0; i < nhist - 1; i++) {
/*
* Add nkeys once before taking remainder to avoid
* negative values.
*/
}
/* Now free the ones we don't keep (the oldest ones) */
for (j = 0; j < histp->n_key_data; j++) {
}
}
}
/*
* If nhist decreased since the last password change, and nkeys+1
* is less than the previous nhist, it is possible for knext to
* index into unallocated space. This condition would not be
* caught by the resizing code above.
*/
/* free the old pw history entry if it contains data */
for (i = 0; i < histp->n_key_data; i++)
/* store the new entry */
/* update the next pointer */
adb->old_key_next = 0;
return(0);
}
#ifdef USE_PASSWORD_SERVER
/* FIXME: don't use global variable for this */
static krb5_boolean
kadm5_use_password_server (void)
{
return use_password_server;
}
void
{
use_password_server = 1;
}
#endif
#ifdef USE_PASSWORD_SERVER
/*
* kadm5_launch_task () runs a program (task_path) to synchronize the
* Apple password server with the Kerberos database. Password server
* programs can receive arguments on the command line (task_argv)
* and a block of data via stdin (data_buffer).
*
* Because a failure to communicate with the tool results in the
* password server falling out of sync with the database,
* kadm5_launch_task() always fails if it can't talk to the tool.
*/
static kadm5_ret_t
const char *data_buffer)
{
kadm5_ret_t ret = 0;
int data_pipe[2];
if (data_buffer != NULL) {
}
if (!ret) {
if (pid == -1) {
} else if (pid == 0) {
/* The child: */
if (data_buffer != NULL) {
_exit (1);
}
} else {
}
} else {
/* The parent: */
int status;
if (data_buffer != NULL) {
/* Write out the buffer to the child */
/* kill the child to make sure waitpid() won't hang later */
}
}
close (data_buffer[0]);
if (!ret) {
/* child read password and exited. Check the return value. */
}
} else {
/* child read password but crashed or was killed */
}
}
}
}
return ret;
}
#endif
{
return
}
char *password)
{
int have_pol = 0;
/* Solaris Kerberos - kadm5_check_min_life checks for null principal. */
if (ret)
return (ret);
hist_added = 0;
return EINVAL;
return KADM5_PROTECT_PRINCIPAL;
return(ret);
/* we are going to need the current keys after the new keys are set */
return(ret);
}
goto done;
have_pol = 1;
}
goto done;
password, 0 /* increment kvno */,
if (ret)
goto done;
if (ret)
goto done;
/* the policy was loaded before */
if (ret)
goto done;
#if 0
/*
* The spec says this check is overridden if the caller has
* modify privilege. The admin server therefore makes this
* check itself (in chpass_principal_wrapper, misc.c). A
* local caller implicitly has all authorization bits.
*/
goto done;
}
#endif
if (ret)
goto done;
&hist_key,
1, &hist);
if (ret)
goto done;
goto done;
}
&hist_key,
if (ret)
goto done;
if (ret)
goto done;
hist_added = 1;
}
if (pol.pw_max_life)
else
kdb.pw_expiration = 0;
} else {
kdb.pw_expiration = 0;
}
#ifdef USE_PASSWORD_SERVER
if (kadm5_use_password_server () &&
char pwbuf[256];
if (!ret) {
}
if (!ret) {
}
if (ret)
goto done;
}
#endif
if (ret)
goto done;
/* key data and attributes changed, let the database provider know */
/* Solaris Kerberos: adding support for key history in LDAP KDB */
if (hist_added == 1)
/* | KADM5_CPW_FUNCTION */;
else
goto done;
done:
&& !ret)
return ret;
}
int *n_keys)
{
/* Solaris Kerberos: */
/*
* Anyone calling this routine is forced to use only DES
* enctypes to be compatible with earlier releases that
* did not support stronger crypto.
*
* S10 (and later) kadmin clients will not use this API,
* so we can assume the request is from an older version.
*/
}
int *n_keys)
{
if (keyblocks)
return EINVAL;
if (hist_princ && /* this will be NULL when initializing the databse */
return KADM5_PROTECT_PRINCIPAL;
return(ret);
&kdb);
if (ret)
goto done;
if (ret)
goto done;
goto done;
have_pol = 1;
if (ret)
goto done;
#if 0
/*
* The spec says this check is overridden if the caller has
* modify privilege. The admin server therefore makes this
* check itself (in chpass_principal_wrapper, misc.c). A
* local caller implicitly has all authorization bits.
*/
goto done;
}
#endif
goto done;
}
&hist_key,
if (ret)
goto done;
}
if (pol.pw_max_life)
else
kdb.pw_expiration = 0;
} else {
kdb.pw_expiration = 0;
}
if (ret)
goto done;
if (keyblocks) {
/* Version 1 clients will expect to see a DES_CRC enctype. */
if (ret)
goto done;
if (ret)
goto done;
} else {
if (ret)
goto done;
}
}
/* key data changed, let the database provider know */
goto done;
done:
if (have_pol)
return ret;
}
#if 0 /* Solaris Kerberos */
/*
* kadm5_setv4key_principal:
*
* Set only ONE key of the principal, removing all others. This key
* must have the DES_CBC_CRC enctype and is entered as having the
* krb4 salttype. This is to enable things like kadmind4 to work.
*/
{
#if 0
int last_pwd;
#endif
return EINVAL;
if (hist_princ && /* this will be NULL when initializing the databse */
return KADM5_PROTECT_PRINCIPAL;
return KADM5_SETV4KEY_INVAL_ENCTYPE;
return(ret);
return ENOMEM;
/* XXX data.magic? */
/* use tmp_key_data as temporary location and reallocate later */
&tmp_key_data);
if (ret) {
goto done;
}
for (k = 0; k < tmp_key_data.key_data_ver; k++) {
if (tmp_key_data.key_data_contents[k]) {
kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
kdb.n_key_data = 0;
goto done;
}
memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
}
}
if (ret)
goto done;
goto done;
have_pol = 1;
#if 0
/*
* The spec says this check is overridden if the caller has
* modify privilege. The admin server therefore makes this
* check itself (in chpass_principal_wrapper, misc.c). A
* local caller implicitly has all authorization bits.
*/
goto done;
goto done;
}
#endif
#if 0
/*
*/
goto done;
}
&hist_key,
goto done;
}
#endif
if (pol.pw_max_life)
else
kdb.pw_expiration = 0;
} else {
kdb.pw_expiration = 0;
}
if (ret)
goto done;
goto done;
done:
for (i = 0; i < tmp_key_data.key_data_ver; i++) {
if (tmp_key_data.key_data_contents[i]) {
}
}
if (have_pol)
return ret;
}
#endif
int n_keys)
{
return
}
int n_keys)
{
int n_old_keys;
#if 0
int last_pwd;
#endif
return EINVAL;
if (hist_princ && /* this will be NULL when initializing the databse */
return KADM5_PROTECT_PRINCIPAL;
for (i = 0; i < n_keys; i++) {
for (j = i+1; j < n_keys; j++) {
&similar)))
return(ret);
if (similar) {
if (n_ks_tuple) {
return KADM5_SETKEY_DUP_ENCTYPES;
} else
return KADM5_SETKEY_DUP_ENCTYPES;
}
}
}
return KADM5_SETKEY3_ETYPE_MISMATCH;
return(ret);
if (keepold) {
} else {
n_old_keys = 0;
old_key_data = NULL;
}
*sizeof(krb5_key_data));
goto done;
}
kdb.n_key_data = 0;
for (i = 0; i < n_keys; i++) {
if (n_ks_tuple) {
goto done;
}
}
&keyblocks[i],
kvno + 1,
&tmp_key_data);
if (ret) {
goto done;
}
for (k = 0; k < tmp_key_data.key_data_ver; k++) {
if (tmp_key_data.key_data_contents[k]) {
int i1;
}
}
goto done;
}
memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
}
}
kdb.n_key_data++;
}
/* copy old key data if necessary */
for (i = 0; i < n_old_keys; i++) {
kdb.n_key_data++;
}
if (old_key_data)
/* assert(kdb.n_key_data == n_keys + n_old_keys) */
goto done;
goto done;
have_pol = 1;
#if 0
/*
* The spec says this check is overridden if the caller has
* modify privilege. The admin server therefore makes this
* check itself (in chpass_principal_wrapper, misc.c). A
* local caller implicitly has all authorization bits.
*/
goto done;
goto done;
}
#endif
#if 0
/*
*/
goto done;
}
&hist_key,
goto done;
}
#endif
if (pol.pw_max_life)
else
kdb.pw_expiration = 0;
} else {
kdb.pw_expiration = 0;
}
goto done;
goto done;
done:
if (have_pol)
return ret;
}
/*
* Allocate an array of n_key_data krb5_keyblocks, fill in each
* element with the results of decrypting the nth key in key_data with
* master_keyblock, and if n_keys is not NULL fill it in with the
* number of keys decrypted.
*/
{
int ret, i;
return ENOMEM;
for (i = 0; i < n_key_data; i++) {
&key_data[i],
if (ret) {
for (; i >= 0; i--) {
}
}
return ret;
}
}
if (n_keys)
*n_keys = n_key_data;
return 0;
}
/*
* Function: kadm5_decrypt_key
*
* Purpose: Retrieves and decrypts a principal key.
*
* Arguments:
*
* server_handle (r) kadm5 handle
* entry (r) principal retrieved with kadm5_get_principal
* ktype (r) enctype to search for, or -1 to ignore
* stype (r) salt type to search for, or -1 to ignore
* kvno (r) kvno to search for, -1 for max, 0 for max
* only if it also matches ktype and stype
* keyblock (w) keyblock to fill in
* keysalt (w) keysalt to fill in, or NULL
* kvnop (w) kvno to fill in, or NULL
*
* Effects: Searches the key_data array of entry, which must have been
* retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
* find a key with a specified enctype, salt type, and kvno in a
* principal entry. If not found, return ENOENT. Otherwise, decrypt
* it with the master key, and return the key in keyblock, the salt
* in salttype, and the key version number in kvno.
*
* If ktype or stype is -1, it is ignored for the search. If kvno is
* -1, ktype and stype are ignored and the key with the max kvno is
* returned. If kvno is 0, only the key with the max kvno is returned
* and only if it matches the ktype and stype; otherwise, ENOENT is
* returned.
*/
{
int ret;
return EINVAL;
/* find_enctype only uses these two fields */
return ret;
return ret;
/*
* Coerce the enctype of the output keyblock in case we got an
* inexact match on the enctype; this behavior will go away when
* the key storage architecture gets redesigned for 1.3.
*/
if (kvnop)
return KADM5_OK;
}
/* Solaris Kerberos */
{
*msg_ret = '\0';
if (ret)
return ret;
if(ret)
return ret;
return ret;
}
*errstr = '\0';
} else {
*ptr = '\0';
}
}
return KADM5_PASS_TOOSOON;
}
if (ret) {
return ret;
}
}
}