krb5: Improve cccol sub naming; add gss_store_cred_into2()
- Formalize the TYPE:collection_name:subsidiary_name naming scheme for ccaches in ccache collections - KEYRING: ccaches are weird because they have one more optional field: the "anchor", so rather than just assume a naming convention everywhere, we add new functions as well - Add krb5_cc_{resolve,default}_sub() that allows one to specify a "subsidiary" ccache name in a collection separately from the collection name - Add krb5_cc_{resolve,default}_for() which take a principal name, unparse it, and use it as the subsidiary ccache name (with colons replaced) - Make kinit use the new interfaces - Add missing DIR ccache iteration functionality - Revamps test_cc - Add krb5_cc_get_collection() and krb5_cc_get_subsidiary() - Bump the ccops SPI version number - Add gss_store_cred_into2() - Make MEMORY:anonymous not linked into the global MEMORY ccache collection, and uses this for delegated cred handles TBD: - Split this up into a krb5 change and gss mech_krb5 change? - Add krb5_cc_init_and_store() utility, per Greg's suggestion?
This commit is contained in:
20
kcm/glue.c
20
kcm/glue.c
@@ -44,15 +44,27 @@ RCSID("$Id$");
|
|||||||
#define KCMCACHE(X) ((kcm_ccache)(X)->data.data)
|
#define KCMCACHE(X) ((kcm_ccache)(X)->data.data)
|
||||||
#define CACHENAME(X) (KCMCACHE(X)->name)
|
#define CACHENAME(X) (KCMCACHE(X)->name)
|
||||||
|
|
||||||
static const char *
|
static krb5_error_code
|
||||||
kcmss_get_name(krb5_context context,
|
kcmss_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **col,
|
||||||
|
const char **sub)
|
||||||
{
|
{
|
||||||
return CACHENAME(id);
|
if (name)
|
||||||
|
*name = CACHENAME(id);
|
||||||
|
if (col)
|
||||||
|
*col = NULL;
|
||||||
|
if (name)
|
||||||
|
*sub = CACHENAME(id);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
kcmss_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
kcmss_resolve(krb5_context context,
|
||||||
|
krb5_ccache *id,
|
||||||
|
const char *res,
|
||||||
|
const char *sub)
|
||||||
{
|
{
|
||||||
return KRB5_FCC_INTERNAL;
|
return KRB5_FCC_INTERNAL;
|
||||||
}
|
}
|
||||||
|
@@ -1316,65 +1316,12 @@ get_princ_kt(krb5_context context,
|
|||||||
free(def_realm);
|
free(def_realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
|
||||||
get_switched_ccache(krb5_context context,
|
|
||||||
const char * type,
|
|
||||||
krb5_principal principal,
|
|
||||||
krb5_ccache *ccache)
|
|
||||||
{
|
|
||||||
krb5_error_code ret;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (strcmp(type, "API") == 0) {
|
|
||||||
/*
|
|
||||||
* Windows stores the default ccache name in the
|
|
||||||
* registry which is shared across multiple logon
|
|
||||||
* sessions for the same user. The API credential
|
|
||||||
* cache provides a unique name space per logon
|
|
||||||
* session. Therefore there is no need to generate
|
|
||||||
* a unique ccache name. Instead use the principal
|
|
||||||
* name. This provides a friendlier user experience.
|
|
||||||
*/
|
|
||||||
char * unparsed_name;
|
|
||||||
char * cred_cache;
|
|
||||||
|
|
||||||
ret = krb5_unparse_name(context, principal,
|
|
||||||
&unparsed_name);
|
|
||||||
if (ret)
|
|
||||||
krb5_err(context, 1, ret,
|
|
||||||
N_("unparsing principal name", ""));
|
|
||||||
|
|
||||||
ret = asprintf(&cred_cache, "API:%s", unparsed_name);
|
|
||||||
krb5_free_unparsed_name(context, unparsed_name);
|
|
||||||
if (ret == -1 || cred_cache == NULL)
|
|
||||||
krb5_err(context, 1, ret,
|
|
||||||
N_("building credential cache name", ""));
|
|
||||||
|
|
||||||
ret = krb5_cc_resolve(context, cred_cache, ccache);
|
|
||||||
free(cred_cache);
|
|
||||||
} else if (strcmp(type, "MSLSA") == 0) {
|
|
||||||
/*
|
|
||||||
* The Windows MSLSA cache when it is writeable
|
|
||||||
* stores tickets for multiple client principals
|
|
||||||
* in a single credential cache.
|
|
||||||
*/
|
|
||||||
ret = krb5_cc_resolve(context, "MSLSA:", ccache);
|
|
||||||
} else {
|
|
||||||
ret = krb5_cc_new_unique(context, type, NULL, ccache);
|
|
||||||
}
|
|
||||||
#else /* !_WIN32 */
|
|
||||||
ret = krb5_cc_new_unique(context, type, NULL, ccache);
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_context context;
|
krb5_context context;
|
||||||
krb5_ccache ccache;
|
krb5_ccache ccache = NULL;
|
||||||
krb5_principal principal = NULL;
|
krb5_principal principal = NULL;
|
||||||
int optidx = 0;
|
int optidx = 0;
|
||||||
krb5_deltat ticket_life = 0;
|
krb5_deltat ticket_life = 0;
|
||||||
@@ -1477,42 +1424,8 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (cred_cache)
|
if (cred_cache)
|
||||||
ret = krb5_cc_resolve(context, cred_cache, &ccache);
|
ret = krb5_cc_resolve(context, cred_cache, &ccache);
|
||||||
else {
|
else
|
||||||
if (argc > 1) {
|
ret = krb5_cc_default_for(context, principal, &ccache);
|
||||||
char s[1024];
|
|
||||||
ret = krb5_cc_new_unique(context, NULL, NULL, &ccache);
|
|
||||||
if (ret)
|
|
||||||
krb5_err(context, 1, ret, "creating cred cache");
|
|
||||||
snprintf(s, sizeof(s), "%s:%s",
|
|
||||||
krb5_cc_get_type(context, ccache),
|
|
||||||
krb5_cc_get_name(context, ccache));
|
|
||||||
setenv("KRB5CCNAME", s, 1);
|
|
||||||
unique_ccache = TRUE;
|
|
||||||
} else {
|
|
||||||
ret = krb5_cc_cache_match(context, principal, &ccache);
|
|
||||||
if (ret) {
|
|
||||||
const char *type;
|
|
||||||
ret = krb5_cc_default(context, &ccache);
|
|
||||||
if (ret)
|
|
||||||
krb5_err(context, 1, ret,
|
|
||||||
N_("resolving credentials cache", ""));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the type support switching, and we do,
|
|
||||||
* then do that instead over overwriting the current
|
|
||||||
* default credential
|
|
||||||
*/
|
|
||||||
type = krb5_cc_get_type(context, ccache);
|
|
||||||
if (krb5_cc_support_switch(context, type)) {
|
|
||||||
krb5_cc_close(context, ccache);
|
|
||||||
ret = get_switched_ccache(context, type, principal,
|
|
||||||
&ccache);
|
|
||||||
if (ret == 0)
|
|
||||||
unique_ccache = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ret)
|
if (ret)
|
||||||
krb5_err(context, 1, ret, N_("resolving credentials cache", ""));
|
krb5_err(context, 1, ret, N_("resolving credentials cache", ""));
|
||||||
|
|
||||||
|
@@ -1187,6 +1187,29 @@ gss_store_cred_into(
|
|||||||
gss_cred_usage_t * /* cred_usage_stored */
|
gss_cred_usage_t * /* cred_usage_stored */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
|
||||||
|
gss_store_cred_into2(
|
||||||
|
OM_uint32 * /* minor_status */,
|
||||||
|
gss_const_cred_id_t /* input_cred_handle */,
|
||||||
|
gss_cred_usage_t /* input_usage */,
|
||||||
|
const gss_OID /* desired_mech */,
|
||||||
|
OM_uint32 /* store_cred_flags */,
|
||||||
|
gss_const_key_value_set_t /* cred_store */,
|
||||||
|
gss_OID_set * /* elements_stored */,
|
||||||
|
gss_cred_usage_t * /* cred_usage_stored */,
|
||||||
|
gss_buffer_set_t * /* env */
|
||||||
|
);
|
||||||
|
|
||||||
|
enum gss_store_cred_flags {
|
||||||
|
GSS_C_STORE_CRED_DEFAULT = 1,
|
||||||
|
GSS_C_STORE_CRED_OVERWRITE = 2,
|
||||||
|
GSS_C_STORE_CRED_SET_PROCESS = 4,
|
||||||
|
};
|
||||||
|
#define GSS_C_STORE_CRED_DEFAULT GSS_C_STORE_CRED_DEFAULT
|
||||||
|
#define GSS_C_STORE_CRED_OVERWRITE GSS_C_STORE_CRED_OVERWRITE
|
||||||
|
#define GSS_C_STORE_CRED_SET_PROCESS GSS_C_STORE_CRED_SET_PROCESS
|
||||||
|
|
||||||
|
|
||||||
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_CALLCONV
|
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_CALLCONV
|
||||||
gss_set_neg_mechs(
|
gss_set_neg_mechs(
|
||||||
OM_uint32 * /* minor_status */,
|
OM_uint32 * /* minor_status */,
|
||||||
|
@@ -474,6 +474,17 @@ _gss_store_cred_into_t(OM_uint32 *minor_status,
|
|||||||
gss_OID_set *elements_stored,
|
gss_OID_set *elements_stored,
|
||||||
gss_cred_usage_t *cred_usage_stored);
|
gss_cred_usage_t *cred_usage_stored);
|
||||||
|
|
||||||
|
typedef OM_uint32 GSSAPI_CALLCONV
|
||||||
|
_gss_store_cred_into2_t(OM_uint32 *minor_status,
|
||||||
|
gss_const_cred_id_t input_cred_handle,
|
||||||
|
gss_cred_usage_t input_usage,
|
||||||
|
gss_OID desired_mech,
|
||||||
|
OM_uint32 store_cred_flags,
|
||||||
|
gss_const_key_value_set_t cred_store,
|
||||||
|
gss_OID_set *elements_stored,
|
||||||
|
gss_cred_usage_t *cred_usage_stored,
|
||||||
|
gss_buffer_set_t *env);
|
||||||
|
|
||||||
typedef OM_uint32 GSSAPI_CALLCONV
|
typedef OM_uint32 GSSAPI_CALLCONV
|
||||||
_gss_set_neg_mechs_t(OM_uint32 *minor_status,
|
_gss_set_neg_mechs_t(OM_uint32 *minor_status,
|
||||||
gss_cred_id_t cred_handle,
|
gss_cred_id_t cred_handle,
|
||||||
@@ -623,6 +634,7 @@ typedef struct gssapi_mech_interface_desc {
|
|||||||
_gss_query_mechanism_info_t *gm_query_mechanism_info;
|
_gss_query_mechanism_info_t *gm_query_mechanism_info;
|
||||||
_gss_query_meta_data_t *gm_query_meta_data;
|
_gss_query_meta_data_t *gm_query_meta_data;
|
||||||
_gss_exchange_meta_data_t *gm_exchange_meta_data;
|
_gss_exchange_meta_data_t *gm_exchange_meta_data;
|
||||||
|
_gss_store_cred_into2_t *gm_store_cred_into2;
|
||||||
struct gss_mech_compat_desc_struct *gm_compat;
|
struct gss_mech_compat_desc_struct *gm_compat;
|
||||||
} gssapi_mech_interface_desc, *gssapi_mech_interface;
|
} gssapi_mech_interface_desc, *gssapi_mech_interface;
|
||||||
|
|
||||||
|
@@ -169,8 +169,7 @@ gsskrb5_accept_delegated_token
|
|||||||
}
|
}
|
||||||
|
|
||||||
*delegated_cred_handle = NULL;
|
*delegated_cred_handle = NULL;
|
||||||
kret = krb5_cc_new_unique (context, krb5_cc_type_memory,
|
kret = krb5_cc_resolve(context, "MEMORY:anonymous", &ccache);
|
||||||
NULL, &ccache);
|
|
||||||
if (kret) {
|
if (kret) {
|
||||||
ctx->flags &= ~GSS_C_DELEG_FLAG;
|
ctx->flags &= ~GSS_C_DELEG_FLAG;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -204,7 +203,7 @@ gsskrb5_accept_delegated_token
|
|||||||
gsskrb5_cred handle;
|
gsskrb5_cred handle;
|
||||||
|
|
||||||
ret = _gsskrb5_krb5_import_cred(minor_status,
|
ret = _gsskrb5_krb5_import_cred(minor_status,
|
||||||
ccache,
|
&ccache,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
delegated_cred_handle);
|
delegated_cred_handle);
|
||||||
@@ -212,10 +211,7 @@ gsskrb5_accept_delegated_token
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
handle = (gsskrb5_cred) *delegated_cred_handle;
|
handle = (gsskrb5_cred) *delegated_cred_handle;
|
||||||
|
|
||||||
handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
|
handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
|
||||||
krb5_cc_close(context, ccache);
|
|
||||||
ccache = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@@ -62,9 +62,18 @@ gss_krb5_copy_ccache(OM_uint32 *minor_status,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WARNING: Takes ownership of `id'. Because MEMORY:anonymous is now not
|
||||||
|
* linked into to the MEMORY ccache namespace, we can't use krb5_cc_resolve()
|
||||||
|
* with the cache's name anymore. We need a krb5_cc_clone() or some such, with
|
||||||
|
* attendant new method for ccops. Or we could create a new MEMORY:anonymous
|
||||||
|
* ccache and copy all the creds from `id' into it. But we know callers of
|
||||||
|
* this function don't need `id' after calling it, so for now we'll just take
|
||||||
|
* ownershipd of it.
|
||||||
|
*/
|
||||||
OM_uint32
|
OM_uint32
|
||||||
_gsskrb5_krb5_import_cred(OM_uint32 *minor_status,
|
_gsskrb5_krb5_import_cred(OM_uint32 *minor_status,
|
||||||
krb5_ccache id,
|
krb5_ccache *id,
|
||||||
krb5_principal keytab_principal,
|
krb5_principal keytab_principal,
|
||||||
krb5_keytab keytab,
|
krb5_keytab keytab,
|
||||||
gss_cred_id_t *cred)
|
gss_cred_id_t *cred)
|
||||||
@@ -88,14 +97,13 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status,
|
|||||||
|
|
||||||
handle->usage = 0;
|
handle->usage = 0;
|
||||||
|
|
||||||
if (id) {
|
if (*id) {
|
||||||
time_t now;
|
time_t now;
|
||||||
OM_uint32 left;
|
OM_uint32 left;
|
||||||
char *str;
|
|
||||||
|
|
||||||
handle->usage |= GSS_C_INITIATE;
|
handle->usage |= GSS_C_INITIATE;
|
||||||
|
|
||||||
kret = krb5_cc_get_principal(context, id,
|
kret = krb5_cc_get_principal(context, *id,
|
||||||
&handle->principal);
|
&handle->principal);
|
||||||
if (kret) {
|
if (kret) {
|
||||||
free(handle);
|
free(handle);
|
||||||
@@ -121,7 +129,7 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status,
|
|||||||
krb5_timeofday(context, &now);
|
krb5_timeofday(context, &now);
|
||||||
ret = __gsskrb5_ccache_lifetime(minor_status,
|
ret = __gsskrb5_ccache_lifetime(minor_status,
|
||||||
context,
|
context,
|
||||||
id,
|
*id,
|
||||||
handle->principal,
|
handle->principal,
|
||||||
&left);
|
&left);
|
||||||
if (ret != GSS_S_COMPLETE) {
|
if (ret != GSS_S_COMPLETE) {
|
||||||
@@ -131,12 +139,8 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status,
|
|||||||
}
|
}
|
||||||
handle->endtime = now + left;
|
handle->endtime = now + left;
|
||||||
|
|
||||||
kret = krb5_cc_get_full_name(context, id, &str);
|
handle->ccache = *id;
|
||||||
if (kret)
|
*id = NULL;
|
||||||
goto out;
|
|
||||||
|
|
||||||
kret = krb5_cc_resolve(context, str, &handle->ccache);
|
|
||||||
free(str);
|
|
||||||
if (kret)
|
if (kret)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@@ -404,6 +404,7 @@ static gssapi_mech_interface_desc krb5_mech = {
|
|||||||
NULL, /* gm_query_mechanism_info */
|
NULL, /* gm_query_mechanism_info */
|
||||||
NULL, /* gm_query_meta_data */
|
NULL, /* gm_query_meta_data */
|
||||||
NULL, /* gm_exchange_meta_data */
|
NULL, /* gm_exchange_meta_data */
|
||||||
|
_gsskrb5_store_cred_into2,
|
||||||
NULL /* gm_compat */
|
NULL /* gm_compat */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -105,7 +105,7 @@ import_cred(OM_uint32 *minor_status,
|
|||||||
free(str);
|
free(str);
|
||||||
str = NULL;
|
str = NULL;
|
||||||
|
|
||||||
major_stat = _gsskrb5_krb5_import_cred(minor_status, id, keytab_principal,
|
major_stat = _gsskrb5_krb5_import_cred(minor_status, &id, keytab_principal,
|
||||||
keytab, cred_handle);
|
keytab, cred_handle);
|
||||||
out:
|
out:
|
||||||
if (id)
|
if (id)
|
||||||
|
@@ -51,64 +51,54 @@ same_princ(krb5_context context, krb5_ccache id1, krb5_ccache id2)
|
|||||||
return same;
|
return same;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static OM_uint32
|
||||||
* Like krb5_cc_cache_match(), but only looking in the default collection.
|
add_env(OM_uint32 *minor,
|
||||||
*
|
gss_buffer_set_t *env,
|
||||||
* We need this to avoid looking for MEMORY ccaches, which risks matching the
|
const char *var,
|
||||||
* same credential that we're storing. We could make sure that MEMORY ccaches
|
const char *val)
|
||||||
* are searched for last in krb5_cc_cache_match(), then ignore any MEMORY
|
|
||||||
* ccaches we find there, but, if we might then store in a ccache that will not
|
|
||||||
* be found later as the default ccache, then it's not worth it.
|
|
||||||
*
|
|
||||||
* XXX In order to remove this, we'll first need to make sure that
|
|
||||||
* krb5_cc_default() searches all collections when KRB5CCNAME is not set,
|
|
||||||
* then we'll need to make sure that krb5_cc_cache_match() searches MEMORY
|
|
||||||
* ccaches last (or else introduce a new ccache type like MEMORY but which
|
|
||||||
* is never searched or searchable), then make sure that the caller below
|
|
||||||
* treat finding a MEMORY the same as not finding a ccache at all.
|
|
||||||
*/
|
|
||||||
static krb5_error_code
|
|
||||||
ccache_match(krb5_context context,
|
|
||||||
krb5_principal princ,
|
|
||||||
const char *cctype,
|
|
||||||
krb5_ccache *id)
|
|
||||||
{
|
{
|
||||||
krb5_cc_cache_cursor cursor = NULL;
|
OM_uint32 major;
|
||||||
krb5_error_code ret;
|
gss_buffer_desc b;
|
||||||
|
char *varval = NULL;
|
||||||
|
|
||||||
*id = NULL;
|
if (asprintf(&varval, "%s=%s", var, val) == -1 || varval == NULL) {
|
||||||
ret = krb5_cc_cache_get_first(context, cctype, &cursor);
|
*minor = ENOMEM;
|
||||||
if (ret)
|
return GSS_S_FAILURE;
|
||||||
return ret;
|
|
||||||
|
|
||||||
while (krb5_cc_cache_next(context, cursor, id) == 0) {
|
|
||||||
krb5_principal p = NULL;
|
|
||||||
|
|
||||||
ret = krb5_cc_get_principal(context, *id, &p);
|
|
||||||
if (ret == 0 &&
|
|
||||||
krb5_principal_compare(context, princ, p)) {
|
|
||||||
krb5_free_principal(context, p);
|
|
||||||
krb5_cc_cache_end_seq_get(context, cursor);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (*id)
|
|
||||||
krb5_cc_close(context, *id);
|
|
||||||
*id = NULL;
|
|
||||||
}
|
}
|
||||||
krb5_cc_cache_end_seq_get(context, cursor);
|
|
||||||
return KRB5_CC_END;
|
b.value = varval;
|
||||||
|
b.length = strlen(varval) + 1;
|
||||||
|
major = gss_add_buffer_set_member(minor, &b, env);
|
||||||
|
free(varval);
|
||||||
|
return major;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OM_uint32
|
||||||
|
set_proc(OM_uint32 *minor, gss_buffer_set_t env)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX On systems with setpag(), call setpag(). On WIN32... create a
|
||||||
|
* session, set the access token, ...?
|
||||||
|
*/
|
||||||
|
#ifndef WIN32
|
||||||
|
for (i = 0; i < env->count; i++)
|
||||||
|
putenv(env->elements[i].value);
|
||||||
|
#endif
|
||||||
|
return GSS_S_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
OM_uint32 GSSAPI_CALLCONV
|
OM_uint32 GSSAPI_CALLCONV
|
||||||
_gsskrb5_store_cred_into(OM_uint32 *minor_status,
|
_gsskrb5_store_cred_into2(OM_uint32 *minor_status,
|
||||||
gss_const_cred_id_t input_cred_handle,
|
gss_const_cred_id_t input_cred_handle,
|
||||||
gss_cred_usage_t cred_usage,
|
gss_cred_usage_t cred_usage,
|
||||||
const gss_OID desired_mech,
|
const gss_OID desired_mech,
|
||||||
OM_uint32 overwrite_cred,
|
OM_uint32 store_cred_flags,
|
||||||
OM_uint32 default_cred,
|
gss_const_key_value_set_t cred_store,
|
||||||
gss_const_key_value_set_t cred_store,
|
gss_OID_set *elements_stored,
|
||||||
gss_OID_set *elements_stored,
|
gss_cred_usage_t *cred_usage_stored,
|
||||||
gss_cred_usage_t *cred_usage_stored)
|
gss_buffer_set_t *envp)
|
||||||
{
|
{
|
||||||
krb5_context context;
|
krb5_context context;
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
@@ -116,8 +106,11 @@ _gsskrb5_store_cred_into(OM_uint32 *minor_status,
|
|||||||
krb5_ccache id = NULL;
|
krb5_ccache id = NULL;
|
||||||
time_t exp_current;
|
time_t exp_current;
|
||||||
time_t exp_new;
|
time_t exp_new;
|
||||||
|
gss_buffer_set_t env = GSS_C_NO_BUFFER_SET;
|
||||||
const char *cs_ccache_name = NULL;
|
const char *cs_ccache_name = NULL;
|
||||||
OM_uint32 major_status;
|
OM_uint32 major_status, junk;
|
||||||
|
OM_uint32 overwrite_cred = store_cred_flags & GSS_C_STORE_CRED_OVERWRITE;
|
||||||
|
OM_uint32 default_cred = store_cred_flags & GSS_C_STORE_CRED_DEFAULT;
|
||||||
|
|
||||||
*minor_status = 0;
|
*minor_status = 0;
|
||||||
|
|
||||||
@@ -168,45 +161,17 @@ _gsskrb5_store_cred_into(OM_uint32 *minor_status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cs_ccache_name) {
|
if (cs_ccache_name) {
|
||||||
/*
|
|
||||||
* Not the default ccache.
|
|
||||||
*
|
|
||||||
* Therefore not a collection type cache.
|
|
||||||
*
|
|
||||||
* Therefore there's no question of switching the primary ccache.
|
|
||||||
*
|
|
||||||
* Therefore we reset default_cred.
|
|
||||||
*
|
|
||||||
* XXX Perhaps we should fail in this case if default_cred is true.
|
|
||||||
*/
|
|
||||||
default_cred = 0;
|
default_cred = 0;
|
||||||
ret = krb5_cc_resolve(context, cs_ccache_name, &id);
|
ret = krb5_cc_resolve(context, cs_ccache_name, &id);
|
||||||
} else {
|
} else {
|
||||||
const char *cctype = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use the default ccache, and if it's a collection, switch it if
|
* Use the default ccache, and if it's a collection, switch it if
|
||||||
* default_cred is true.
|
* default_cred is true.
|
||||||
*/
|
*/
|
||||||
ret = krb5_cc_default(context, &id);
|
ret = krb5_cc_default_for(context, input_cred->principal, &id);
|
||||||
if (ret == 0) {
|
if (ret == 0 &&
|
||||||
cctype = krb5_cc_get_type(context, id);
|
krb5_cc_support_switch(context, krb5_cc_get_type(context, id)))
|
||||||
if (krb5_cc_support_switch(context, cctype)) {
|
overwrite_cred = 1;
|
||||||
/* The default ccache is a collection type */
|
|
||||||
|
|
||||||
krb5_cc_close(context, id);
|
|
||||||
id = NULL;
|
|
||||||
|
|
||||||
/* Find a matching ccache or create a new one */
|
|
||||||
ret = ccache_match(context, input_cred->principal,
|
|
||||||
cctype, &id);
|
|
||||||
if (ret || id == NULL) {
|
|
||||||
/* Since the ccache is new, just store unconditionally */
|
|
||||||
overwrite_cred = 1;
|
|
||||||
ret = krb5_cc_new_unique(context, cctype, NULL, &id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret || id == NULL) {
|
if (ret || id == NULL) {
|
||||||
@@ -215,14 +180,7 @@ _gsskrb5_store_cred_into(OM_uint32 *minor_status,
|
|||||||
return ret == 0 ? GSS_S_NO_CRED : GSS_S_FAILURE;
|
return ret == 0 ? GSS_S_NO_CRED : GSS_S_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (!overwrite_cred && same_princ(context, id, input_cred->ccache)) {
|
||||||
* If the new creds are for a different principal than we had before,
|
|
||||||
* overwrite.
|
|
||||||
*/
|
|
||||||
if (!overwrite_cred && !same_princ(context, id, input_cred->ccache))
|
|
||||||
overwrite_cred = 1;
|
|
||||||
|
|
||||||
if (!overwrite_cred) {
|
|
||||||
/*
|
/*
|
||||||
* If current creds are for the same princ as we already had creds for,
|
* If current creds are for the same princ as we already had creds for,
|
||||||
* and the new creds live longer than the old, overwrite.
|
* and the new creds live longer than the old, overwrite.
|
||||||
@@ -246,9 +204,47 @@ _gsskrb5_store_cred_into(OM_uint32 *minor_status,
|
|||||||
NULL);
|
NULL);
|
||||||
if (ret == 0 && default_cred)
|
if (ret == 0 && default_cred)
|
||||||
krb5_cc_switch(context, id);
|
krb5_cc_switch(context, id);
|
||||||
|
|
||||||
|
if ((store_cred_flags & GSS_C_STORE_CRED_SET_PROCESS) && envp == NULL)
|
||||||
|
envp = &env;
|
||||||
|
if (envp != NULL) {
|
||||||
|
char *fullname = NULL;
|
||||||
|
|
||||||
|
if ((ret = krb5_cc_get_full_name(context, id, &fullname)) == 0) {
|
||||||
|
major_status = add_env(minor_status, envp, "KRB5CCNAME", fullname);
|
||||||
|
free(fullname);
|
||||||
|
if (major_status)
|
||||||
|
ret = *minor_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
(void) krb5_cc_close(context, id);
|
(void) krb5_cc_close(context, id);
|
||||||
|
|
||||||
HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex);
|
HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex);
|
||||||
|
if (ret == 0 && (store_cred_flags & GSS_C_STORE_CRED_SET_PROCESS) &&
|
||||||
|
(major_status = set_proc(minor_status, *envp)) != GSS_S_COMPLETE)
|
||||||
|
ret = *minor_status;
|
||||||
|
(void) gss_release_buffer_set(&junk, &env);
|
||||||
*minor_status = ret;
|
*minor_status = ret;
|
||||||
return ret ? GSS_S_FAILURE : GSS_S_COMPLETE;
|
return ret ? GSS_S_FAILURE : GSS_S_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OM_uint32 GSSAPI_CALLCONV
|
||||||
|
_gsskrb5_store_cred_into(OM_uint32 *minor_status,
|
||||||
|
gss_const_cred_id_t input_cred_handle,
|
||||||
|
gss_cred_usage_t cred_usage,
|
||||||
|
const gss_OID desired_mech,
|
||||||
|
OM_uint32 overwrite_cred,
|
||||||
|
OM_uint32 default_cred,
|
||||||
|
gss_const_key_value_set_t cred_store,
|
||||||
|
gss_OID_set *elements_stored,
|
||||||
|
gss_cred_usage_t *cred_usage_stored)
|
||||||
|
{
|
||||||
|
OM_uint32 store_cred_flags =
|
||||||
|
(overwrite_cred ? GSS_C_STORE_CRED_OVERWRITE : 0) |
|
||||||
|
(default_cred ? GSS_C_STORE_CRED_DEFAULT : 0);
|
||||||
|
|
||||||
|
return _gsskrb5_store_cred_into2(minor_status, input_cred_handle,
|
||||||
|
cred_usage, desired_mech,
|
||||||
|
store_cred_flags, cred_store,
|
||||||
|
elements_stored, cred_usage_stored, NULL);
|
||||||
|
}
|
||||||
|
@@ -96,6 +96,7 @@ EXPORTS
|
|||||||
gss_sign
|
gss_sign
|
||||||
gss_store_cred
|
gss_store_cred
|
||||||
gss_store_cred_into
|
gss_store_cred_into
|
||||||
|
gss_store_cred_into2
|
||||||
gss_test_oid_set_member
|
gss_test_oid_set_member
|
||||||
gss_unseal
|
gss_unseal
|
||||||
gss_unwrap
|
gss_unwrap
|
||||||
|
@@ -38,14 +38,23 @@ store_mech_cred(OM_uint32 *minor_status,
|
|||||||
gssapi_mech_interface m,
|
gssapi_mech_interface m,
|
||||||
const struct _gss_mechanism_cred *mc,
|
const struct _gss_mechanism_cred *mc,
|
||||||
gss_cred_usage_t input_usage,
|
gss_cred_usage_t input_usage,
|
||||||
OM_uint32 overwrite_cred,
|
OM_uint32 store_cred_flags,
|
||||||
OM_uint32 default_cred,
|
|
||||||
gss_const_key_value_set_t cred_store,
|
gss_const_key_value_set_t cred_store,
|
||||||
gss_cred_usage_t *usage_stored)
|
gss_cred_usage_t *usage_stored,
|
||||||
|
gss_buffer_set_t *env)
|
||||||
{
|
{
|
||||||
OM_uint32 major_status;
|
OM_uint32 major_status;
|
||||||
|
OM_uint32 overwrite_cred =
|
||||||
|
!!(store_cred_flags & GSS_C_STORE_CRED_OVERWRITE);
|
||||||
|
OM_uint32 default_cred = !!(store_cred_flags & GSS_C_STORE_CRED_DEFAULT);
|
||||||
|
|
||||||
if (m->gm_store_cred_into)
|
if (m->gm_store_cred_into2)
|
||||||
|
major_status = m->gm_store_cred_into2(minor_status, mc->gmc_cred,
|
||||||
|
input_usage, &m->gm_mech_oid,
|
||||||
|
store_cred_flags, cred_store,
|
||||||
|
NULL, usage_stored,
|
||||||
|
env);
|
||||||
|
else if (m->gm_store_cred_into)
|
||||||
major_status = m->gm_store_cred_into(minor_status, mc->gmc_cred,
|
major_status = m->gm_store_cred_into(minor_status, mc->gmc_cred,
|
||||||
input_usage, &m->gm_mech_oid,
|
input_usage, &m->gm_mech_oid,
|
||||||
overwrite_cred, default_cred,
|
overwrite_cred, default_cred,
|
||||||
@@ -66,25 +75,28 @@ store_mech_cred(OM_uint32 *minor_status,
|
|||||||
* const key/value hashmap-like thing that specifies a credential store in a
|
* const key/value hashmap-like thing that specifies a credential store in a
|
||||||
* mechanism- and implementation-specific way, though Heimdal and MIT agree on
|
* mechanism- and implementation-specific way, though Heimdal and MIT agree on
|
||||||
* at least the following keys for the Kerberos mechanism: ccache, keytab, and
|
* at least the following keys for the Kerberos mechanism: ccache, keytab, and
|
||||||
* client_keytab.
|
* client_keytab. A set of environment variables may be output as well
|
||||||
*/
|
*/
|
||||||
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
|
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
|
||||||
gss_store_cred_into(OM_uint32 *minor_status,
|
gss_store_cred_into2(OM_uint32 *minor_status,
|
||||||
gss_const_cred_id_t input_cred_handle,
|
gss_const_cred_id_t input_cred_handle,
|
||||||
gss_cred_usage_t input_usage,
|
gss_cred_usage_t input_usage,
|
||||||
const gss_OID desired_mech,
|
const gss_OID desired_mech,
|
||||||
OM_uint32 overwrite_cred,
|
OM_uint32 store_cred_flags,
|
||||||
OM_uint32 default_cred,
|
gss_const_key_value_set_t cred_store,
|
||||||
gss_const_key_value_set_t cred_store,
|
gss_OID_set *elements_stored,
|
||||||
gss_OID_set *elements_stored,
|
gss_cred_usage_t *cred_usage_stored,
|
||||||
gss_cred_usage_t *cred_usage_stored)
|
gss_buffer_set_t *env)
|
||||||
{
|
{
|
||||||
struct _gss_cred *cred = (struct _gss_cred *) input_cred_handle;
|
struct _gss_cred *cred = (struct _gss_cred *)input_cred_handle;
|
||||||
struct _gss_mechanism_cred *mc;
|
struct _gss_mechanism_cred *mc;
|
||||||
OM_uint32 major_status;
|
OM_uint32 major_status;
|
||||||
OM_uint32 minor;
|
OM_uint32 minor;
|
||||||
size_t successes;
|
size_t successes;
|
||||||
|
|
||||||
|
if (env != NULL)
|
||||||
|
*env = NULL;
|
||||||
|
|
||||||
if (input_cred_handle == NULL)
|
if (input_cred_handle == NULL)
|
||||||
return GSS_S_CALL_INACCESSIBLE_READ;
|
return GSS_S_CALL_INACCESSIBLE_READ;
|
||||||
|
|
||||||
@@ -117,10 +129,9 @@ gss_store_cred_into(OM_uint32 *minor_status,
|
|||||||
!gss_oid_equal(&m->gm_mech_oid, desired_mech))
|
!gss_oid_equal(&m->gm_mech_oid, desired_mech))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
major_status = store_mech_cred(minor_status, m, mc,
|
major_status = store_mech_cred(minor_status, m, mc, input_usage,
|
||||||
input_usage, overwrite_cred,
|
store_cred_flags, cred_store,
|
||||||
default_cred, cred_store,
|
cred_usage_stored, env);
|
||||||
cred_usage_stored);
|
|
||||||
if (major_status == GSS_S_COMPLETE) {
|
if (major_status == GSS_S_COMPLETE) {
|
||||||
if (elements_stored && desired_mech != GSS_C_NO_OID)
|
if (elements_stored && desired_mech != GSS_C_NO_OID)
|
||||||
gss_add_oid_set_member(&minor, desired_mech, elements_stored);
|
gss_add_oid_set_member(&minor, desired_mech, elements_stored);
|
||||||
@@ -142,3 +153,29 @@ gss_store_cred_into(OM_uint32 *minor_status,
|
|||||||
|
|
||||||
return major_status;
|
return major_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See RFC5588 for gss_store_cred(). This function is a variant that takes a
|
||||||
|
* const key/value hashmap-like thing that specifies a credential store in a
|
||||||
|
* mechanism- and implementation-specific way, though Heimdal and MIT agree on
|
||||||
|
* at least the following keys for the Kerberos mechanism: ccache, keytab, and
|
||||||
|
* client_keytab.
|
||||||
|
*/
|
||||||
|
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
|
||||||
|
gss_store_cred_into(OM_uint32 *minor_status,
|
||||||
|
gss_const_cred_id_t input_cred_handle,
|
||||||
|
gss_cred_usage_t input_usage,
|
||||||
|
const gss_OID desired_mech,
|
||||||
|
OM_uint32 overwrite_cred,
|
||||||
|
OM_uint32 default_cred,
|
||||||
|
gss_const_key_value_set_t cred_store,
|
||||||
|
gss_OID_set *elements_stored,
|
||||||
|
gss_cred_usage_t *cred_usage_stored)
|
||||||
|
{
|
||||||
|
OM_uint32 store_cred_flags =
|
||||||
|
(overwrite_cred ? GSS_C_STORE_CRED_OVERWRITE : 0) |
|
||||||
|
(default_cred ? GSS_C_STORE_CRED_DEFAULT : 0);
|
||||||
|
return gss_store_cred_into2(minor_status, input_cred_handle, input_usage,
|
||||||
|
desired_mech, store_cred_flags, cred_store,
|
||||||
|
elements_stored, cred_usage_stored, NULL);
|
||||||
|
}
|
||||||
|
@@ -130,6 +130,7 @@ static gssapi_mech_interface_desc ntlm_mech = {
|
|||||||
NULL, /* gm_query_mechanism_info */
|
NULL, /* gm_query_mechanism_info */
|
||||||
NULL, /* gm_query_meta_data */
|
NULL, /* gm_query_meta_data */
|
||||||
NULL, /* gm_exchange_meta_data */
|
NULL, /* gm_exchange_meta_data */
|
||||||
|
NULL, /* gm_store_cred_into2 */
|
||||||
NULL, /* gm_compat */
|
NULL, /* gm_compat */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -154,6 +154,7 @@ static gssapi_mech_interface_desc spnego_mech = {
|
|||||||
NULL, /* gm_query_mechanism_info */
|
NULL, /* gm_query_mechanism_info */
|
||||||
NULL, /* gm_query_meta_data */
|
NULL, /* gm_query_meta_data */
|
||||||
NULL, /* gm_exchange_meta_data */
|
NULL, /* gm_exchange_meta_data */
|
||||||
|
NULL, /* gm_store_cred_into2 */
|
||||||
NULL /* gm_compat */
|
NULL /* gm_compat */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -94,12 +94,21 @@ gss_err(int exitval, OM_uint32 major, OM_uint32 minor, gss_OID mech,
|
|||||||
exit(exitval);
|
exit(exitval);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int version_flag = 0;
|
static int version_flag = 0;
|
||||||
static int help_flag = 0;
|
static int help_flag = 0;
|
||||||
|
static int env_flag = 0;
|
||||||
|
static int def_flag = 0;
|
||||||
|
static int overwrite_flag = 0;
|
||||||
|
|
||||||
static struct getargs args[] = {
|
static struct getargs args[] = {
|
||||||
{"version", 0, arg_flag, &version_flag, "print version", NULL },
|
{"version", 0, arg_flag, &version_flag, "print version", NULL },
|
||||||
{"help", 0, arg_flag, &help_flag, NULL, NULL }
|
{"help", 0, arg_flag, &help_flag, NULL, NULL },
|
||||||
|
{"env", 'e', arg_flag, &env_flag,
|
||||||
|
"output env settings", NULL },
|
||||||
|
{"default", 0, arg_flag, &def_flag,
|
||||||
|
"switch credential store default principal", NULL },
|
||||||
|
{"overwrite", 0, arg_flag, &overwrite_flag,
|
||||||
|
"overwrite matching credential", NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -119,6 +128,8 @@ main(int argc, char **argv)
|
|||||||
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
|
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
|
||||||
gss_key_value_element_desc from_elements, to_elements;
|
gss_key_value_element_desc from_elements, to_elements;
|
||||||
gss_key_value_set_desc from, to;
|
gss_key_value_set_desc from, to;
|
||||||
|
gss_buffer_set_t env = GSS_C_NO_BUFFER_SET;
|
||||||
|
OM_uint32 store_flags = 0;
|
||||||
int optidx = 0;
|
int optidx = 0;
|
||||||
|
|
||||||
setprogname(argv[0]);
|
setprogname(argv[0]);
|
||||||
@@ -133,6 +144,11 @@ main(int argc, char **argv)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (def_flag)
|
||||||
|
store_flags |= GSS_C_STORE_CRED_DEFAULT;
|
||||||
|
if (overwrite_flag)
|
||||||
|
store_flags |= GSS_C_STORE_CRED_OVERWRITE;
|
||||||
|
|
||||||
argc -= optidx;
|
argc -= optidx;
|
||||||
argv += optidx;
|
argv += optidx;
|
||||||
|
|
||||||
@@ -159,12 +175,35 @@ main(int argc, char **argv)
|
|||||||
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
|
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
|
||||||
"failed to acquire creds from %s", argv[0]);
|
"failed to acquire creds from %s", argv[0]);
|
||||||
|
|
||||||
major = gss_store_cred_into(&minor, from_cred, GSS_C_INITIATE,
|
major = gss_store_cred_into2(&minor, from_cred, GSS_C_INITIATE,
|
||||||
GSS_KRB5_MECHANISM, 1, 1, &to, NULL, NULL);
|
GSS_KRB5_MECHANISM, store_flags, &to, NULL,
|
||||||
|
NULL, env_flag ? &env : NULL);
|
||||||
if (major != GSS_S_COMPLETE)
|
if (major != GSS_S_COMPLETE)
|
||||||
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
|
gss_err(1, major, minor, GSS_KRB5_MECHANISM,
|
||||||
"failed to store creds into %s", argv[1]);
|
"failed to store creds into %s", argv[1]);
|
||||||
|
|
||||||
|
if (env_flag) {
|
||||||
|
size_t i;
|
||||||
|
int got_krb5ccname = 0;
|
||||||
|
|
||||||
|
if (env == GSS_C_NO_BUFFER_SET)
|
||||||
|
warnx("No environment settings");
|
||||||
|
|
||||||
|
for (i = 0; env != GSS_C_NO_BUFFER_SET && i < env->count; i++) {
|
||||||
|
got_krb5ccname = got_krb5ccname ||
|
||||||
|
(env->elements[i].length > sizeof("KRB5CCNAME=") &&
|
||||||
|
strncmp((const char *)env->elements[i].value, "KRB5CCNAME=",
|
||||||
|
sizeof("KRB5CCNAME=") - 1) == 0);
|
||||||
|
printf("%.*s\n", (int)env->elements[i].length,
|
||||||
|
(const char *)env->elements[i].value);
|
||||||
|
}
|
||||||
|
(void) gss_release_buffer_set(&minor, &env);
|
||||||
|
|
||||||
|
if (!got_krb5ccname)
|
||||||
|
errx(1, "KRB5CCNAME environment variable not set by "
|
||||||
|
"gss_store_cred_into2()");
|
||||||
|
}
|
||||||
|
|
||||||
(void) gss_release_cred(&minor, &from_cred);
|
(void) gss_release_cred(&minor, &from_cred);
|
||||||
(void) gss_release_cred(&minor, &to_cred);
|
(void) gss_release_cred(&minor, &to_cred);
|
||||||
|
|
||||||
|
@@ -90,6 +90,7 @@ HEIMDAL_GSS_2.0 {
|
|||||||
gss_sign;
|
gss_sign;
|
||||||
gss_store_cred;
|
gss_store_cred;
|
||||||
gss_store_cred_into;
|
gss_store_cred_into;
|
||||||
|
gss_store_cred_into2;
|
||||||
gss_test_oid_set_member;
|
gss_test_oid_set_member;
|
||||||
gss_unseal;
|
gss_unseal;
|
||||||
gss_unwrap;
|
gss_unwrap;
|
||||||
|
@@ -49,6 +49,7 @@ static void *cc_handle;
|
|||||||
|
|
||||||
typedef struct krb5_acc {
|
typedef struct krb5_acc {
|
||||||
char *cache_name;
|
char *cache_name;
|
||||||
|
char *cache_subsidiary;
|
||||||
cc_context_t context;
|
cc_context_t context;
|
||||||
cc_ccache_t ccache;
|
cc_ccache_t ccache;
|
||||||
} krb5_acc;
|
} krb5_acc;
|
||||||
@@ -442,41 +443,51 @@ get_cc_name(krb5_acc *a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char* KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
acc_get_name(krb5_context context,
|
acc_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **colname,
|
||||||
|
const char **subsidiary)
|
||||||
{
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
krb5_acc *a = ACACHE(id);
|
krb5_acc *a = ACACHE(id);
|
||||||
int32_t error;
|
int32_t error;
|
||||||
|
|
||||||
if (a->cache_name == NULL) {
|
if (name)
|
||||||
krb5_error_code ret;
|
*name = NULL;
|
||||||
krb5_principal principal;
|
if (colname)
|
||||||
char *name;
|
*colname = NULL;
|
||||||
|
if (subsidiary)
|
||||||
|
*subsidiary = NULL;
|
||||||
|
if (a->cache_subsidiary == NULL) {
|
||||||
|
krb5_principal principal = NULL;
|
||||||
|
|
||||||
ret = _krb5_get_default_principal_local(context, &principal);
|
ret = _krb5_get_default_principal_local(context, &principal);
|
||||||
if (ret)
|
if (ret == 0)
|
||||||
return NULL;
|
ret = krb5_unparse_name(context, principal, &a->cache_subsidiary);
|
||||||
|
|
||||||
ret = krb5_unparse_name(context, principal, &name);
|
|
||||||
krb5_free_principal(context, principal);
|
krb5_free_principal(context, principal);
|
||||||
if (ret)
|
if (ret)
|
||||||
return NULL;
|
return ret;
|
||||||
|
|
||||||
error = (*a->context->func->create_new_ccache)(a->context,
|
|
||||||
cc_credentials_v5,
|
|
||||||
name,
|
|
||||||
&a->ccache);
|
|
||||||
krb5_xfree(name);
|
|
||||||
if (error)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
error = get_cc_name(a);
|
|
||||||
if (error)
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return a->cache_name;
|
if (a->cache_name == NULL) {
|
||||||
|
error = (*a->context->func->create_new_ccache)(a->context,
|
||||||
|
cc_credentials_v5,
|
||||||
|
a->cache_subsidiary,
|
||||||
|
&a->ccache);
|
||||||
|
if (error == ccNoError)
|
||||||
|
error = get_cc_name(a);
|
||||||
|
if (error != ccNoError)
|
||||||
|
ret = translate_cc_error(context, error);
|
||||||
|
}
|
||||||
|
if (name)
|
||||||
|
*name = a->cache_name;
|
||||||
|
if (colname)
|
||||||
|
*colname = "";
|
||||||
|
if (subsidiary)
|
||||||
|
*subsidiary = a->cache_subsidiary;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
@@ -497,6 +508,10 @@ acc_alloc(krb5_context context, krb5_ccache *id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
a = ACACHE(*id);
|
a = ACACHE(*id);
|
||||||
|
a->cache_subsidiary = NULL;
|
||||||
|
a->cache_name = NULL;
|
||||||
|
a->context = NULL;
|
||||||
|
a->ccache = NULL;
|
||||||
|
|
||||||
error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
|
error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -504,17 +519,17 @@ acc_alloc(krb5_context context, krb5_ccache *id)
|
|||||||
return translate_cc_error(context, error);
|
return translate_cc_error(context, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
a->cache_name = NULL;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
acc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
acc_resolve(krb5_context context, krb5_ccache *id, const char *res, const char *sub)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
cc_time_t offset;
|
||||||
cc_int32 error;
|
cc_int32 error;
|
||||||
krb5_acc *a;
|
krb5_acc *a;
|
||||||
|
char *s = NULL;
|
||||||
|
|
||||||
ret = acc_alloc(context, id);
|
ret = acc_alloc(context, id);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -522,49 +537,44 @@ acc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
|||||||
|
|
||||||
a = ACACHE(*id);
|
a = ACACHE(*id);
|
||||||
|
|
||||||
error = (*a->context->func->open_ccache)(a->context, res, &a->ccache);
|
if (sub) {
|
||||||
if (error == ccNoError) {
|
if (asprintf(&s, "%s:%s", res, sub) == -1 || s == NULL ||
|
||||||
cc_time_t offset;
|
(a->cache_subsidiary = strdup(sub)) == NULL) {
|
||||||
error = get_cc_name(a);
|
|
||||||
if (error != ccNoError) {
|
|
||||||
acc_close(context, *id);
|
acc_close(context, *id);
|
||||||
*id = NULL;
|
free(s);
|
||||||
return translate_cc_error(context, error);
|
return krb5_enomem(context);
|
||||||
}
|
}
|
||||||
|
res = s;
|
||||||
error = (*a->ccache->func->get_kdc_time_offset)(a->ccache,
|
/*
|
||||||
cc_credentials_v5,
|
* XXX With a bit of extra refactoring we could use the collection name
|
||||||
&offset);
|
* as the path to the shared object implementing CCAPI... For now we
|
||||||
if (error == 0)
|
* ignore the collection name.
|
||||||
context->kdc_sec_offset = offset;
|
*/
|
||||||
|
|
||||||
} else if (error == ccErrCCacheNotFound) {
|
|
||||||
a->ccache = NULL;
|
|
||||||
a->cache_name = NULL;
|
|
||||||
} else {
|
|
||||||
*id = NULL;
|
|
||||||
return translate_cc_error(context, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error = (*a->context->func->open_ccache)(a->context, res, &a->ccache);
|
||||||
|
if (error == ccNoError)
|
||||||
|
error = get_cc_name(a);
|
||||||
|
if (error != ccNoError) {
|
||||||
|
acc_close(context, *id);
|
||||||
|
*id = NULL;
|
||||||
|
free(s);
|
||||||
|
return translate_cc_error(context, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = (*a->ccache->func->get_kdc_time_offset)(a->ccache,
|
||||||
|
cc_credentials_v5,
|
||||||
|
&offset);
|
||||||
|
if (error == 0)
|
||||||
|
context->kdc_sec_offset = offset;
|
||||||
|
free(s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
acc_gen_new(krb5_context context, krb5_ccache *id)
|
acc_gen_new(krb5_context context, krb5_ccache *id)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
return acc_alloc(context, id);
|
||||||
krb5_acc *a;
|
|
||||||
|
|
||||||
ret = acc_alloc(context, id);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
a = ACACHE(*id);
|
|
||||||
|
|
||||||
a->ccache = NULL;
|
|
||||||
a->cache_name = NULL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
|
256
lib/krb5/cache.c
256
lib/krb5/cache.c
@@ -104,7 +104,7 @@ main (int argc, char **argv)
|
|||||||
* Add a new ccache type with operations `ops', overwriting any
|
* Add a new ccache type with operations `ops', overwriting any
|
||||||
* existing one if `override'.
|
* existing one if `override'.
|
||||||
*
|
*
|
||||||
* @param context a Keberos context
|
* @param context a Kerberos context
|
||||||
* @param ops type of plugin symbol
|
* @param ops type of plugin symbol
|
||||||
* @param override flag to select if the registration is to overide
|
* @param override flag to select if the registration is to overide
|
||||||
* an existing ops with the same name.
|
* an existing ops with the same name.
|
||||||
@@ -180,10 +180,11 @@ _krb5_cc_allocate(krb5_context context,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
allocate_ccache (krb5_context context,
|
allocate_ccache(krb5_context context,
|
||||||
const krb5_cc_ops *ops,
|
const krb5_cc_ops *ops,
|
||||||
const char *residual,
|
const char *residual,
|
||||||
krb5_ccache *id)
|
const char *subsidiary,
|
||||||
|
krb5_ccache *id)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
#ifdef KRB5_USE_PATH_TOKENS
|
#ifdef KRB5_USE_PATH_TOKENS
|
||||||
@@ -210,7 +211,7 @@ allocate_ccache (krb5_context context,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = (*id)->ops->resolve(context, id, residual);
|
ret = (*id)->ops->resolve(context, id, residual, subsidiary);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
free(*id);
|
free(*id);
|
||||||
*id = NULL;
|
*id = NULL;
|
||||||
@@ -247,7 +248,7 @@ is_possible_path_name(const char * name)
|
|||||||
* Find and allocate a ccache in `id' from the specification in `residual'.
|
* Find and allocate a ccache in `id' from the specification in `residual'.
|
||||||
* If the ccache name doesn't contain any colon, interpret it as a file name.
|
* If the ccache name doesn't contain any colon, interpret it as a file name.
|
||||||
*
|
*
|
||||||
* @param context a Keberos context.
|
* @param context a Kerberos context.
|
||||||
* @param name string name of a credential cache.
|
* @param name string name of a credential cache.
|
||||||
* @param id return pointer to a found credential cache.
|
* @param id return pointer to a found credential cache.
|
||||||
*
|
*
|
||||||
@@ -273,12 +274,12 @@ krb5_cc_resolve(krb5_context context,
|
|||||||
if(strncmp(context->cc_ops[i]->prefix, name, prefix_len) == 0
|
if(strncmp(context->cc_ops[i]->prefix, name, prefix_len) == 0
|
||||||
&& name[prefix_len] == ':') {
|
&& name[prefix_len] == ':') {
|
||||||
return allocate_ccache (context, context->cc_ops[i],
|
return allocate_ccache (context, context->cc_ops[i],
|
||||||
name + prefix_len + 1,
|
name + prefix_len + 1, NULL,
|
||||||
id);
|
id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_possible_path_name(name))
|
if (is_possible_path_name(name))
|
||||||
return allocate_ccache (context, &krb5_fcc_ops, name, id);
|
return allocate_ccache (context, &krb5_fcc_ops, name, NULL, id);
|
||||||
else {
|
else {
|
||||||
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
|
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
|
||||||
N_("unknown ccache type %s", "name"), name);
|
N_("unknown ccache type %s", "name"), name);
|
||||||
@@ -286,6 +287,153 @@ krb5_cc_resolve(krb5_context context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_default_cc_type(krb5_context context, int simple)
|
||||||
|
{
|
||||||
|
const char *def_ccname;
|
||||||
|
const char *def_cctype =
|
||||||
|
krb5_config_get_string_default(context, NULL,
|
||||||
|
secure_getenv("KRB5CCTYPE"),
|
||||||
|
"libdefaults", "default_cc_type", NULL);
|
||||||
|
|
||||||
|
if (!simple &&
|
||||||
|
(def_ccname = krb5_cc_default_name(context))) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
|
||||||
|
size_t prefix_len = strlen(context->cc_ops[i]->prefix);
|
||||||
|
|
||||||
|
if (!strncmp(context->cc_ops[i]->prefix, def_ccname, prefix_len) &&
|
||||||
|
def_ccname[prefix_len] == ':')
|
||||||
|
return context->cc_ops[i]->prefix;
|
||||||
|
}
|
||||||
|
if (is_possible_path_name(def_ccname))
|
||||||
|
return "FILE";
|
||||||
|
}
|
||||||
|
return def_cctype ? def_cctype : "DIR";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and allocate a ccache in `id' for the subsidiary cache named by
|
||||||
|
* `subsidiary' in the collection named by `collection'.
|
||||||
|
*
|
||||||
|
* @param context a Kerberos context.
|
||||||
|
* @param cctype string name of a credential cache collection type.
|
||||||
|
* @param collection string name of a credential cache collection.
|
||||||
|
* @param subsidiary string name of a credential cache in a collection.
|
||||||
|
* @param id return pointer to a found credential cache.
|
||||||
|
*
|
||||||
|
* @return Return 0 or an error code. In case of an error, id is set
|
||||||
|
* to NULL, see krb5_get_error_message().
|
||||||
|
*
|
||||||
|
* @ingroup krb5_ccache
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||||
|
krb5_cc_resolve_sub(krb5_context context,
|
||||||
|
const char *cctype,
|
||||||
|
const char *collection,
|
||||||
|
const char *subsidiary,
|
||||||
|
krb5_ccache *id)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
*id = NULL;
|
||||||
|
|
||||||
|
if (!cctype && collection) {
|
||||||
|
/* Get the cctype from the collection, maybe */
|
||||||
|
for (i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
|
||||||
|
size_t plen = strlen(context->cc_ops[i]->prefix);
|
||||||
|
|
||||||
|
if ((strncmp(context->cc_ops[i]->prefix, collection, plen) ||
|
||||||
|
collection[plen] != ':'))
|
||||||
|
continue;
|
||||||
|
cctype = context->cc_ops[i]->prefix;
|
||||||
|
collection += plen + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!cctype) {
|
||||||
|
const char *def_cctype = get_default_cc_type(context, 0);
|
||||||
|
int might_be_path = collection && is_possible_path_name(collection);
|
||||||
|
|
||||||
|
if (def_cctype)
|
||||||
|
cctype = def_cctype;
|
||||||
|
else if (might_be_path && subsidiary)
|
||||||
|
cctype = "DIR"; /* Default to DIR */
|
||||||
|
else if (might_be_path && !subsidiary)
|
||||||
|
cctype = "FILE"; /* Default to FILE */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If either `cctype' is not NULL or `collection' starts with TYPE: */
|
||||||
|
if (cctype || collection) {
|
||||||
|
for (i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
|
||||||
|
size_t plen = strlen(context->cc_ops[i]->prefix);
|
||||||
|
|
||||||
|
if (cctype && strcmp(context->cc_ops[i]->prefix, cctype))
|
||||||
|
continue;
|
||||||
|
if (!cctype &&
|
||||||
|
(strncmp(context->cc_ops[i]->prefix, collection, plen) ||
|
||||||
|
collection[plen] != ':'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return allocate_ccache(context, context->cc_ops[i],
|
||||||
|
cctype ? collection : collection + plen + 1,
|
||||||
|
subsidiary, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
|
||||||
|
N_("unknown ccache type %s", ""),
|
||||||
|
cctype ? cctype : collection);
|
||||||
|
return KRB5_CC_UNKNOWN_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and allocate a ccache in `id' from the specification in `residual', but
|
||||||
|
* specific to the given principal `principal' by using the principal name as
|
||||||
|
* the name of a "subsidiary" credentials cache in the collection named by
|
||||||
|
* `name'. If the ccache name doesn't contain any colon, interpret it as a
|
||||||
|
* file name.
|
||||||
|
*
|
||||||
|
* @param context a Kerberos context.
|
||||||
|
* @param name string name of a credential cache.
|
||||||
|
* @param principal principal name of desired credentials.
|
||||||
|
* @param id return pointer to a found credential cache.
|
||||||
|
*
|
||||||
|
* @return Return 0 or an error code. In case of an error, id is set
|
||||||
|
* to NULL, see krb5_get_error_message().
|
||||||
|
*
|
||||||
|
* @ingroup krb5_ccache
|
||||||
|
*/
|
||||||
|
|
||||||
|
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||||
|
krb5_cc_resolve_for(krb5_context context,
|
||||||
|
const char *cctype,
|
||||||
|
const char *name,
|
||||||
|
krb5_const_principal principal,
|
||||||
|
krb5_ccache *id)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
char *p, *s;
|
||||||
|
|
||||||
|
*id = NULL;
|
||||||
|
|
||||||
|
ret = krb5_unparse_name(context, principal, &p);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
/* Subsidiary components cannot have ':'s in them */
|
||||||
|
for (s = strchr(p, ':'); s; s = strchr(s + 1, ':'))
|
||||||
|
*s = '-';
|
||||||
|
ret = krb5_cc_resolve_sub(context, cctype, name, p, id);
|
||||||
|
free(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new unique ccache of `type` in `id'. If `type' is NULL,
|
* Generates a new unique ccache of `type` in `id'. If `type' is NULL,
|
||||||
* the library chooses the default credential cache type. The supplied
|
* the library chooses the default credential cache type. The supplied
|
||||||
@@ -334,7 +482,42 @@ KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
|
|||||||
krb5_cc_get_name(krb5_context context,
|
krb5_cc_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id)
|
||||||
{
|
{
|
||||||
return id->ops->get_name(context, id);
|
const char *name;
|
||||||
|
|
||||||
|
(void) id->ops->get_name(context, id, &name, NULL, NULL);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the ccache collection associated with `id'
|
||||||
|
*
|
||||||
|
* @ingroup krb5_ccache
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
|
||||||
|
krb5_cc_get_collection(krb5_context context, krb5_ccache id)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
(void) id->ops->get_name(context, id, NULL, &name, NULL);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the subsidiary ccache of `id'
|
||||||
|
*
|
||||||
|
* @ingroup krb5_ccache
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
|
||||||
|
krb5_cc_get_subsidiary(krb5_context context, krb5_ccache id)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
(void) id->ops->get_name(context, id, NULL, NULL, &name);
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -354,7 +537,7 @@ krb5_cc_get_type(krb5_context context,
|
|||||||
/**
|
/**
|
||||||
* Return the complete resolvable name the cache
|
* Return the complete resolvable name the cache
|
||||||
|
|
||||||
* @param context a Keberos context
|
* @param context a Kerberos context
|
||||||
* @param id return pointer to a found credential cache
|
* @param id return pointer to a found credential cache
|
||||||
* @param str the returned name of a credential cache, free with krb5_xfree()
|
* @param str the returned name of a credential cache, free with krb5_xfree()
|
||||||
*
|
*
|
||||||
@@ -620,8 +803,7 @@ krb5_cc_configured_default_name(krb5_context context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Else try a configured default ccache type's default */
|
/* Else try a configured default ccache type's default */
|
||||||
cfg = krb5_config_get_string(context, NULL, "libdefaults",
|
cfg = get_default_cc_type(context, 1);
|
||||||
"default_cc_type", NULL);
|
|
||||||
if (cfg) {
|
if (cfg) {
|
||||||
const krb5_cc_ops *ops;
|
const krb5_cc_ops *ops;
|
||||||
|
|
||||||
@@ -687,18 +869,52 @@ krb5_cc_configured_default_name(krb5_context context)
|
|||||||
* @ingroup krb5_ccache
|
* @ingroup krb5_ccache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||||
krb5_cc_default(krb5_context context,
|
krb5_cc_default(krb5_context context,
|
||||||
krb5_ccache *id)
|
krb5_ccache *id)
|
||||||
{
|
{
|
||||||
const char *p = krb5_cc_default_name(context);
|
const char *p = krb5_cc_default_name(context);
|
||||||
|
|
||||||
|
*id = NULL;
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
return krb5_cc_resolve(context, p, id);
|
return krb5_cc_resolve(context, p, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the named subsidiary cache from the default ccache collection in `id'.
|
||||||
|
*
|
||||||
|
* @return Return an error code or 0, see krb5_get_error_message().
|
||||||
|
*
|
||||||
|
* @ingroup krb5_ccache
|
||||||
|
*/
|
||||||
|
|
||||||
|
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||||
|
krb5_cc_default_sub(krb5_context context,
|
||||||
|
const char *subsidiary,
|
||||||
|
krb5_ccache *id)
|
||||||
|
{
|
||||||
|
return krb5_cc_resolve_sub(context, get_default_cc_type(context, 0), NULL,
|
||||||
|
subsidiary, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the default ccache in `id' that corresponds to the given principal.
|
||||||
|
*
|
||||||
|
* @return Return an error code or 0, see krb5_get_error_message().
|
||||||
|
*
|
||||||
|
* @ingroup krb5_ccache
|
||||||
|
*/
|
||||||
|
|
||||||
|
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||||
|
krb5_cc_default_for(krb5_context context,
|
||||||
|
krb5_const_principal principal,
|
||||||
|
krb5_ccache *id)
|
||||||
|
{
|
||||||
|
return krb5_cc_resolve_for(context, get_default_cc_type(context, 0), NULL,
|
||||||
|
principal, id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new ccache in `id' for `primary_principal'.
|
* Create a new ccache in `id' for `primary_principal'.
|
||||||
*
|
*
|
||||||
@@ -1424,7 +1640,7 @@ krb5_cc_cache_match (krb5_context context,
|
|||||||
* Move the content from one credential cache to another. The
|
* Move the content from one credential cache to another. The
|
||||||
* operation is an atomic switch.
|
* operation is an atomic switch.
|
||||||
*
|
*
|
||||||
* @param context a Keberos context
|
* @param context a Kerberos context
|
||||||
* @param from the credential cache to move the content from
|
* @param from the credential cache to move the content from
|
||||||
* @param to the credential cache to move the content to
|
* @param to the credential cache to move the content to
|
||||||
|
|
||||||
@@ -1515,7 +1731,7 @@ build_conf_principals(krb5_context context, krb5_ccache id,
|
|||||||
* principal (generated part of krb5_cc_set_config()). Returns FALSE
|
* principal (generated part of krb5_cc_set_config()). Returns FALSE
|
||||||
* (zero) if not a configuration principal.
|
* (zero) if not a configuration principal.
|
||||||
*
|
*
|
||||||
* @param context a Keberos context
|
* @param context a Kerberos context
|
||||||
* @param principal principal to check if it a configuration principal
|
* @param principal principal to check if it a configuration principal
|
||||||
*
|
*
|
||||||
* @ingroup krb5_ccache
|
* @ingroup krb5_ccache
|
||||||
@@ -1539,7 +1755,7 @@ krb5_is_config_principal(krb5_context context,
|
|||||||
* Store some configuration for the credential cache in the cache.
|
* Store some configuration for the credential cache in the cache.
|
||||||
* Existing configuration under the same name is over-written.
|
* Existing configuration under the same name is over-written.
|
||||||
*
|
*
|
||||||
* @param context a Keberos context
|
* @param context a Kerberos context
|
||||||
* @param id the credential cache to store the data for
|
* @param id the credential cache to store the data for
|
||||||
* @param principal configuration for a specific principal, if
|
* @param principal configuration for a specific principal, if
|
||||||
* NULL, global for the whole cache.
|
* NULL, global for the whole cache.
|
||||||
@@ -1586,7 +1802,7 @@ out:
|
|||||||
/**
|
/**
|
||||||
* Get some configuration for the credential cache in the cache.
|
* Get some configuration for the credential cache in the cache.
|
||||||
*
|
*
|
||||||
* @param context a Keberos context
|
* @param context a Kerberos context
|
||||||
* @param id the credential cache to store the data for
|
* @param id the credential cache to store the data for
|
||||||
* @param principal configuration for a specific principal, if
|
* @param principal configuration for a specific principal, if
|
||||||
* NULL, global for the whole cache.
|
* NULL, global for the whole cache.
|
||||||
@@ -1637,7 +1853,7 @@ struct krb5_cccol_cursor_data {
|
|||||||
* Get a new cache interation cursor that will interate over all
|
* Get a new cache interation cursor that will interate over all
|
||||||
* credentials caches independent of type.
|
* credentials caches independent of type.
|
||||||
*
|
*
|
||||||
* @param context a Keberos context
|
* @param context a Kerberos context
|
||||||
* @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
|
* @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
|
||||||
*
|
*
|
||||||
* @return Returns 0 or and error code, see krb5_get_error_message().
|
* @return Returns 0 or and error code, see krb5_get_error_message().
|
||||||
@@ -1711,7 +1927,7 @@ krb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor,
|
|||||||
return KRB5_CC_END;
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -37,8 +37,10 @@
|
|||||||
|
|
||||||
typedef struct krb5_dcache{
|
typedef struct krb5_dcache{
|
||||||
krb5_ccache fcache;
|
krb5_ccache fcache;
|
||||||
char *dir;
|
|
||||||
char *name;
|
char *name;
|
||||||
|
char *dir;
|
||||||
|
char *sub;
|
||||||
|
unsigned int default_candidate:1;
|
||||||
} krb5_dcache;
|
} krb5_dcache;
|
||||||
|
|
||||||
#define DCACHE(X) ((krb5_dcache*)(X)->data.data)
|
#define DCACHE(X) ((krb5_dcache*)(X)->data.data)
|
||||||
@@ -46,7 +48,47 @@ typedef struct krb5_dcache{
|
|||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV dcc_close(krb5_context, krb5_ccache);
|
static krb5_error_code KRB5_CALLCONV dcc_close(krb5_context, krb5_ccache);
|
||||||
static krb5_error_code KRB5_CALLCONV dcc_get_default_name(krb5_context, char **);
|
static krb5_error_code KRB5_CALLCONV dcc_get_default_name(krb5_context, char **);
|
||||||
|
static krb5_error_code KRB5_CALLCONV dcc_set_default(krb5_context, krb5_ccache);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make subsidiary filesystem safe by mapping / and : to -. If the subsidiary
|
||||||
|
* is longer than 128 bytes, then truncate.
|
||||||
|
* In all cases, "tkt." is prefixed to be compatible with the DIR requirement
|
||||||
|
* that subsidiary ccache files be named tkt*.
|
||||||
|
*
|
||||||
|
* Thus host/foo.bar.baz@BAR.BAZ -> tkt.host-foo.bar.baz@BAR.BAZ.
|
||||||
|
*
|
||||||
|
* In particular, no filesystem component separators will be emitted, and . and
|
||||||
|
* .. will never be traversed.
|
||||||
|
*/
|
||||||
|
static krb5_error_code
|
||||||
|
fs_encode_subsidiary(krb5_context context,
|
||||||
|
krb5_dcache *dc,
|
||||||
|
const char *subsidiary,
|
||||||
|
char **res)
|
||||||
|
{
|
||||||
|
size_t len = strlen(subsidiary);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
*res = NULL;
|
||||||
|
if (asprintf(res, "tkt.%s", subsidiary) == -1 || *res == NULL)
|
||||||
|
return krb5_enomem(context);
|
||||||
|
for (i = sizeof("tkt.") - 1; i < len; i++) {
|
||||||
|
switch ((*res)[i]) {
|
||||||
|
#ifdef WIN32
|
||||||
|
case '\\': (*res)[0] = '-'; break;
|
||||||
|
#endif
|
||||||
|
case '/': (*res)[0] = '-'; break;
|
||||||
|
case ':': (*res)[0] = '-'; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hopefully this will work on all filesystems */
|
||||||
|
if (len > 128 - sizeof("tkt.") - 1)
|
||||||
|
(*res)[127] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
primary_create(krb5_dcache *dc)
|
primary_create(krb5_dcache *dc)
|
||||||
@@ -63,8 +105,14 @@ primary_create(krb5_dcache *dc)
|
|||||||
static int
|
static int
|
||||||
is_filename_cacheish(const char *name)
|
is_filename_cacheish(const char *name)
|
||||||
{
|
{
|
||||||
return strncmp(name, "tkt", 3) == 0;
|
size_t i;
|
||||||
|
|
||||||
|
if (strncmp(name, "tkt", sizeof("tkt") - 1))
|
||||||
|
return 0;
|
||||||
|
for (i = sizeof("tkt") - 1; name[i]; i++)
|
||||||
|
if (ISPATHSEP(name[i]))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
@@ -77,12 +125,6 @@ set_default_cache(krb5_context context, krb5_dcache *dc, const char *residual)
|
|||||||
int fd = -1;
|
int fd = -1;
|
||||||
int asprintf_ret;
|
int asprintf_ret;
|
||||||
|
|
||||||
if (!is_filename_cacheish(residual)) {
|
|
||||||
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
|
||||||
"name %s is not a cache (doesn't start with tkt)", residual);
|
|
||||||
return KRB5_CC_FORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
asprintf_ret = asprintf(&path, "%s/primary-XXXXXX", dc->dir);
|
asprintf_ret = asprintf(&path, "%s/primary-XXXXXX", dc->dir);
|
||||||
if (asprintf_ret == -1 || path == NULL) {
|
if (asprintf_ret == -1 || path == NULL) {
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
@@ -141,14 +183,18 @@ set_default_cache(krb5_context context, krb5_dcache *dc, const char *residual)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
get_default_cache(krb5_context context, krb5_dcache *dc, char **residual)
|
get_default_cache(krb5_context context, krb5_dcache *dc,
|
||||||
|
const char *subsidiary, char **residual)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
char buf[MAXPATHLEN];
|
char buf[MAXPATHLEN];
|
||||||
char *primary;
|
char *primary = NULL;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
*residual = NULL;
|
*residual = NULL;
|
||||||
|
if (subsidiary)
|
||||||
|
return fs_encode_subsidiary(context, dc, subsidiary, residual);
|
||||||
|
|
||||||
primary = primary_create(dc);
|
primary = primary_create(dc);
|
||||||
if (primary == NULL)
|
if (primary == NULL)
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
@@ -197,12 +243,22 @@ get_default_cache(krb5_context context, krb5_dcache *dc, char **residual)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const char* KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
dcc_get_name(krb5_context context,
|
dcc_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **dir,
|
||||||
|
const char **sub)
|
||||||
{
|
{
|
||||||
krb5_dcache *dc = DCACHE(id);
|
krb5_dcache *dc = DCACHE(id);
|
||||||
return dc->name;
|
|
||||||
|
if (name)
|
||||||
|
*name = dc->name;
|
||||||
|
if (dir)
|
||||||
|
*dir = dc->dir;
|
||||||
|
if (sub)
|
||||||
|
*sub = dc->sub;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -211,6 +267,12 @@ verify_directory(krb5_context context, const char *path)
|
|||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
|
if (!path[0]) {
|
||||||
|
krb5_set_error_message(context, EINVAL,
|
||||||
|
N_("DIR empty directory component", ""));
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (stat(path, &sb) != 0) {
|
if (stat(path, &sb) != 0) {
|
||||||
if (errno == ENOENT) {
|
if (errno == ENOENT) {
|
||||||
/* XXX should use mkdirx_np() */
|
/* XXX should use mkdirx_np() */
|
||||||
@@ -241,118 +303,176 @@ dcc_release(krb5_context context, krb5_dcache *dc)
|
|||||||
{
|
{
|
||||||
if (dc->fcache)
|
if (dc->fcache)
|
||||||
krb5_cc_close(context, dc->fcache);
|
krb5_cc_close(context, dc->fcache);
|
||||||
if (dc->dir)
|
free(dc->sub);
|
||||||
free(dc->dir);
|
free(dc->dir);
|
||||||
if (dc->name)
|
free(dc->name);
|
||||||
free(dc->name);
|
|
||||||
memset(dc, 0, sizeof(*dc));
|
memset(dc, 0, sizeof(*dc));
|
||||||
free(dc);
|
free(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code
|
||||||
dcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
get_default_dir(krb5_context context, char **res)
|
||||||
{
|
{
|
||||||
char *filename = NULL;
|
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_dcache *dc;
|
char *s;
|
||||||
const char *p;
|
|
||||||
int asprintf_ret;
|
|
||||||
|
|
||||||
p = res;
|
if ((ret = dcc_get_default_name(context, &s)))
|
||||||
do {
|
return ret;
|
||||||
p = strstr(p, "..");
|
if (strncmp(s, "DIR:", sizeof("DIR:") - 1)) {
|
||||||
if (p && (p == res || ISPATHSEP(p[-1])) && (ISPATHSEP(p[2]) || p[2] == '\0')) {
|
*res = s;
|
||||||
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
s = NULL;
|
||||||
N_("Path contains a .. component", ""));
|
} else if ((*res = strdup(s + sizeof("DIR:") - 1)) == NULL) {
|
||||||
return KRB5_CC_FORMAT;
|
ret = krb5_enomem(context);
|
||||||
}
|
|
||||||
if (p)
|
|
||||||
p += 3;
|
|
||||||
} while (p);
|
|
||||||
|
|
||||||
dc = calloc(1, sizeof(*dc));
|
|
||||||
if (dc == NULL) {
|
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
|
||||||
N_("malloc: out of memory", ""));
|
|
||||||
return KRB5_CC_NOMEM;
|
|
||||||
}
|
}
|
||||||
|
free(s);
|
||||||
/* check for explicit component */
|
return ret;
|
||||||
if (res[0] == ':') {
|
}
|
||||||
char *q;
|
|
||||||
|
|
||||||
dc->dir = strdup(&res[1]);
|
static krb5_error_code KRB5_CALLCONV
|
||||||
#ifdef _WIN32
|
dcc_resolve(krb5_context context,
|
||||||
q = strrchr(dc->dir, '\\');
|
krb5_ccache *id,
|
||||||
if (q == NULL)
|
const char *res,
|
||||||
#endif
|
const char *sub)
|
||||||
q = strrchr(dc->dir, '/');
|
{
|
||||||
if (q) {
|
krb5_error_code ret;
|
||||||
*q++ = '\0';
|
krb5_dcache *dc = NULL;
|
||||||
} else {
|
char *filename = NULL;
|
||||||
krb5_set_error_message(context, KRB5_CC_FORMAT, N_("Cache not an absolute path: %s", ""), dc->dir);
|
size_t len;
|
||||||
dcc_release(context, dc);
|
int has_pathsep = 0;
|
||||||
return KRB5_CC_FORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_filename_cacheish(q)) {
|
|
||||||
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
|
||||||
N_("Name %s is not a cache (doesn't start with tkt)", ""), q);
|
|
||||||
dcc_release(context, dc);
|
|
||||||
return KRB5_CC_FORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = verify_directory(context, dc->dir);
|
|
||||||
if (ret) {
|
|
||||||
dcc_release(context, dc);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
dc->name = strdup(res);
|
|
||||||
if (dc->name == NULL) {
|
|
||||||
dcc_release(context, dc);
|
|
||||||
return krb5_enomem(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (sub) {
|
||||||
|
/*
|
||||||
|
* Here `res' has the directory name (or, if NULL, refers to the
|
||||||
|
* default DIR cccol), and `sub' has the "subsidiary" name, to which
|
||||||
|
* we'll prefix "tkt." (though we will insist only on "tkt" later).
|
||||||
|
*/
|
||||||
|
if ((dc = calloc(1, sizeof(*dc))) == NULL ||
|
||||||
|
asprintf(&dc->sub, "tkt.%s", sub) == -1 || dc->sub == NULL) {
|
||||||
|
free(dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
if (res && res[0] && (dc->dir = strdup(res)) == NULL) {
|
||||||
|
free(dc->sub);
|
||||||
|
free(dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
} else if ((!res || !res[0]) && (ret = get_default_dir(context, &dc->dir))) {
|
||||||
|
free(dc->sub);
|
||||||
|
free(dc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
char *residual;
|
const char *p;
|
||||||
size_t len;
|
int is_drive_letter_colon = 0;
|
||||||
|
|
||||||
dc->dir = strdup(res);
|
/*
|
||||||
if (dc->dir == NULL) {
|
* Here `res' has whatever string followed "DIR:", and we need to parse
|
||||||
dcc_release(context, dc);
|
* it into `dc->dir' and `dc->sub'.
|
||||||
return krb5_enomem(context);
|
*
|
||||||
}
|
* Conventions we support for DIR cache naming:
|
||||||
|
*
|
||||||
|
* - DIR:path:NAME ---> FILE:path/tktNAME
|
||||||
|
* - DIR::path/tktNAME ---> FILE:path/tktNAME
|
||||||
|
* - DIR::NAME ---> FILE:${default_DIR_cccol_path}/tktNAME
|
||||||
|
* \-> FILE:/tmp/krb5cc_${uid}_dir/tktNAME
|
||||||
|
* - DIR:path ---> FILE:path/$(cat primary) or FILE:path/tkt
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
len = strlen(dc->dir);
|
if (*res == '\0' || (res[0] == ':' && res[1] == '\0')) {
|
||||||
|
/* XXX Why not? */
|
||||||
|
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
||||||
|
N_("\"DIR:\" is not a valid ccache name", ""));
|
||||||
|
return KRB5_CC_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
if (ISPATHSEP(dc->dir[len - 1]))
|
#ifdef WIN32
|
||||||
dc->dir[len - 1] = '\0';
|
has_pathsep = strchr(res, '\\') != NULL;
|
||||||
|
#endif
|
||||||
|
has_pathsep |= strchr(res, '/') != NULL;
|
||||||
|
|
||||||
ret = verify_directory(context, dc->dir);
|
if ((dc = calloc(1, sizeof(*dc))) == NULL)
|
||||||
if (ret) {
|
return krb5_enomem(context);
|
||||||
dcc_release(context, dc);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = get_default_cache(context, dc, &residual);
|
p = strrchr(res, ':');
|
||||||
if (ret) {
|
#ifdef WIN32
|
||||||
dcc_release(context, dc);
|
is_drive_letter_colon =
|
||||||
return ret;
|
p && ((res[0] == ':' && res[1] != ':' && p - res == 2) ||
|
||||||
}
|
(res[0] != ':' && p - res == 1));
|
||||||
asprintf_ret = asprintf(&dc->name, ":%s/%s", dc->dir, residual);
|
#endif
|
||||||
free(residual);
|
|
||||||
if (asprintf_ret == -1 || dc->name == NULL) {
|
if (res[0] != ':' && p && !is_drive_letter_colon) {
|
||||||
dc->name = NULL;
|
/* DIR:path:NAME */
|
||||||
dcc_release(context, dc);
|
if ((dc->dir = strndup(res, (p - res))) == NULL ||
|
||||||
return krb5_enomem(context);
|
asprintf(&dc->sub, "tkt.%s", p + 1) < 0 || dc->sub == NULL) {
|
||||||
}
|
dcc_release(context, dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
} else if (res[0] == ':' && has_pathsep) {
|
||||||
|
char *q;
|
||||||
|
|
||||||
|
/* DIR::path/tktNAME (the "tkt" must be there; we'll check) */
|
||||||
|
if ((dc->dir = strdup(&res[1])) == NULL) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
q = strrchr(dc->dir, '\\');
|
||||||
|
if (q == NULL || ((p = strrchr(dc->dir, '/')) && q < p))
|
||||||
|
#endif
|
||||||
|
q = strrchr(dc->dir, '/');
|
||||||
|
*q++ = '\0';
|
||||||
|
if ((dc->sub = strdup(q)) == NULL) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
} else if (res[0] == ':') {
|
||||||
|
/* DIR::NAME -- no path component separators in NAME */
|
||||||
|
if ((ret = get_default_dir(context, &dc->dir))) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (asprintf(&dc->sub, "tkt.%s", res + 1) < 0 || dc->sub == NULL) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* DIR:path */
|
||||||
|
if ((dc->dir = strdup(res)) == NULL) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = get_default_cache(context, dc, NULL, &dc->sub))) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asprintf_ret = asprintf(&filename, "FILE%s", dc->name);
|
/* Strip off extra slashes on the end */
|
||||||
if (asprintf_ret == -1 || filename == NULL) {
|
for (len = strlen(dc->dir);
|
||||||
dcc_release(context, dc);
|
len && ISPATHSEP(dc->dir[len - 1]);
|
||||||
return krb5_enomem(context);
|
len -= len ? 1 : 0)
|
||||||
|
dc->dir[len - 1] = '\0';
|
||||||
|
|
||||||
|
/* If we got here then `dc->dir' and `dc->sub' must both be set */
|
||||||
|
|
||||||
|
if ((ret = verify_directory(context, dc->dir))) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!is_filename_cacheish(dc->sub)) {
|
||||||
|
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
||||||
|
N_("Name %s is not a cache "
|
||||||
|
"(doesn't start with tkt)", ""), dc->sub);
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return KRB5_CC_FORMAT;
|
||||||
|
}
|
||||||
|
if (asprintf(&dc->name, ":%s/%s", dc->dir, dc->sub) == -1 ||
|
||||||
|
dc->name == NULL ||
|
||||||
|
asprintf(&filename, "FILE%s", dc->name) == -1 || filename == NULL) {
|
||||||
|
dcc_release(context, dc);
|
||||||
|
return krb5_enomem(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = krb5_cc_resolve(context, filename, &dc->fcache);
|
ret = krb5_cc_resolve(context, filename, &dc->fcache);
|
||||||
@@ -362,86 +482,36 @@ dcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dc->default_candidate = 1;
|
||||||
(*id)->data.data = dc;
|
(*id)->data.data = dc;
|
||||||
(*id)->data.length = sizeof(*dc);
|
(*id)->data.length = sizeof(*dc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
|
||||||
copy_default_dcc_cache(krb5_context context)
|
|
||||||
{
|
|
||||||
const char *defname;
|
|
||||||
krb5_error_code ret;
|
|
||||||
char *name = NULL;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = strlen(krb5_dcc_ops.prefix);
|
|
||||||
|
|
||||||
defname = krb5_cc_default_name(context);
|
|
||||||
if (defname == NULL ||
|
|
||||||
strncmp(defname, krb5_dcc_ops.prefix, len) != 0 ||
|
|
||||||
defname[len] != ':')
|
|
||||||
{
|
|
||||||
ret = dcc_get_default_name(context, &name);
|
|
||||||
if (ret)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return name;
|
|
||||||
} else {
|
|
||||||
return strdup(&defname[len + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
dcc_gen_new(krb5_context context, krb5_ccache *id)
|
dcc_gen_new(krb5_context context, krb5_ccache *id)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
char *def_dir = NULL;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
krb5_dcache *dc;
|
int fd = -1;
|
||||||
int fd;
|
|
||||||
size_t len;
|
|
||||||
int asprintf_ret;
|
|
||||||
|
|
||||||
name = copy_default_dcc_cache(context);
|
ret = get_default_dir(context, &def_dir);
|
||||||
if (name == NULL) {
|
if (ret == 0)
|
||||||
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
ret = verify_directory(context, def_dir);
|
||||||
N_("Can't generate DIR caches unless its the default type", ""));
|
if (ret == 0 &&
|
||||||
return KRB5_CC_FORMAT;
|
(asprintf(&name, "DIR::%s/tktXXXXXX", def_dir) == -1 || name == NULL))
|
||||||
}
|
ret = krb5_enomem(context);
|
||||||
|
if (ret == 0 && (fd = mkstemp(name + sizeof("DIR::") - 1)) == -1)
|
||||||
|
ret = errno;
|
||||||
|
if (ret == 0)
|
||||||
|
ret = dcc_resolve(context, id, name + sizeof("DIR:") - 1, NULL);
|
||||||
|
|
||||||
len = strlen(krb5_dcc_ops.prefix);
|
free(def_dir);
|
||||||
if (strncmp(name, krb5_dcc_ops.prefix, len) == 0 && name[len] == ':')
|
|
||||||
++len;
|
|
||||||
else
|
|
||||||
len = 0;
|
|
||||||
|
|
||||||
ret = dcc_resolve(context, id, name + len);
|
|
||||||
free(name);
|
free(name);
|
||||||
name = NULL;
|
if (fd != -1)
|
||||||
if (ret)
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
dc = DCACHE((*id));
|
|
||||||
|
|
||||||
asprintf_ret = asprintf(&name, ":%s/tktXXXXXX", dc->dir);
|
|
||||||
if (asprintf_ret == -1 || name == NULL) {
|
|
||||||
dcc_close(context, *id);
|
|
||||||
return krb5_enomem(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = mkstemp(&name[1]);
|
|
||||||
if (fd < 0) {
|
|
||||||
dcc_close(context, *id);
|
|
||||||
return krb5_enomem(context);
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
free(dc->name);
|
|
||||||
dc->name = name;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
@@ -457,6 +527,25 @@ static krb5_error_code KRB5_CALLCONV
|
|||||||
dcc_close(krb5_context context,
|
dcc_close(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id)
|
||||||
{
|
{
|
||||||
|
krb5_dcache *dc = DCACHE(id);
|
||||||
|
krb5_principal p = NULL;
|
||||||
|
struct stat st;
|
||||||
|
char *primary = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there's no default cache, but we're closing one, and the one we're
|
||||||
|
* closing has been initialized, then make it the default. This makes the
|
||||||
|
* first cache created the default.
|
||||||
|
*
|
||||||
|
* FIXME We should check if `D2FCACHE(dc)' has live credentials.
|
||||||
|
*/
|
||||||
|
if (dc->default_candidate && D2FCACHE(dc) &&
|
||||||
|
krb5_cc_get_principal(context, D2FCACHE(dc), &p) == 0 &&
|
||||||
|
(primary = primary_create(dc)) &&
|
||||||
|
(stat(primary, &st) == -1 || !S_ISREG(st.st_mode) || st.st_size == 0))
|
||||||
|
dcc_set_default(context, id);
|
||||||
|
krb5_free_principal(context, p);
|
||||||
|
free(primary);
|
||||||
dcc_release(context, DCACHE(id));
|
dcc_release(context, DCACHE(id));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -545,39 +634,61 @@ dcc_get_version(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct dcache_iter {
|
struct dcache_iter {
|
||||||
int first;
|
char *primary;
|
||||||
krb5_dcache *dc;
|
krb5_dcache *dc;
|
||||||
|
DIR *d;
|
||||||
|
unsigned int first:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
dcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
|
dcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
|
||||||
{
|
{
|
||||||
struct dcache_iter *iter;
|
struct dcache_iter *iter = NULL;
|
||||||
krb5_error_code ret;
|
const char *name = krb5_cc_default_name(context);
|
||||||
char *name;
|
size_t len;
|
||||||
|
char *p;
|
||||||
|
|
||||||
*cursor = NULL;
|
*cursor = NULL;
|
||||||
iter = calloc(1, sizeof(*iter));
|
|
||||||
if (iter == NULL)
|
|
||||||
return krb5_enomem(context);
|
|
||||||
iter->first = 1;
|
|
||||||
|
|
||||||
name = copy_default_dcc_cache(context);
|
if (strncmp(name, "DIR:", sizeof("DIR:") - 1) != 0) {
|
||||||
if (name == NULL) {
|
|
||||||
free(iter);
|
|
||||||
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
||||||
N_("Can't generate DIR caches unless its the default type", ""));
|
N_("Can't list DIR caches unless its the default type", ""));
|
||||||
return KRB5_CC_FORMAT;
|
return KRB5_CC_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dcc_resolve(context, NULL, name);
|
if ((iter = calloc(1, sizeof(*iter))) == NULL ||
|
||||||
free(name);
|
(iter->dc = calloc(1, sizeof(iter->dc[0]))) == NULL ||
|
||||||
if (ret) {
|
(iter->dc->dir = strdup(name + sizeof("DIR:") - 1)) == NULL) {
|
||||||
|
if (iter)
|
||||||
|
free(iter->dc);
|
||||||
free(iter);
|
free(iter);
|
||||||
return ret;
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
iter->first = 1;
|
||||||
|
p = strrchr(iter->dc->dir, ':');
|
||||||
|
#ifdef WIN32
|
||||||
|
if (p == iter->dc->dir + 1)
|
||||||
|
p = NULL;
|
||||||
|
#endif
|
||||||
|
if (p)
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
/* Strip off extra slashes on the end */
|
||||||
|
for (len = strlen(iter->dc->dir);
|
||||||
|
len && ISPATHSEP(iter->dc->dir[len - 1]);
|
||||||
|
len -= len ? 1 : 0) {
|
||||||
|
iter->dc->dir[len - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX We need to opendir() here */
|
if ((iter->d = opendir(iter->dc->dir)) == NULL) {
|
||||||
|
free(iter->dc->dir);
|
||||||
|
free(iter->dc);
|
||||||
|
free(iter);
|
||||||
|
krb5_set_error_message(context, KRB5_CC_FORMAT,
|
||||||
|
N_("Can't open DIR %s: %s", ""),
|
||||||
|
iter->dc->dir, strerror(errno));
|
||||||
|
return KRB5_CC_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
*cursor = iter;
|
*cursor = iter;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -587,18 +698,49 @@ static krb5_error_code KRB5_CALLCONV
|
|||||||
dcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
|
dcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
|
||||||
{
|
{
|
||||||
struct dcache_iter *iter = cursor;
|
struct dcache_iter *iter = cursor;
|
||||||
|
krb5_error_code ret;
|
||||||
|
struct stat st;
|
||||||
|
struct dirent *dentry;
|
||||||
|
char *p = NULL;
|
||||||
|
|
||||||
|
*id = NULL;
|
||||||
if (iter == NULL)
|
if (iter == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
if (!iter->first) {
|
/* Emit primary subsidiary first */
|
||||||
krb5_clear_error_message(context);
|
if (iter->first &&
|
||||||
return KRB5_CC_END;
|
(ret = get_default_cache(context, iter->dc, NULL, &iter->primary)) == 0 &&
|
||||||
|
is_filename_cacheish(iter->primary)) {
|
||||||
|
iter->first = 0;
|
||||||
|
ret = KRB5_CC_END;
|
||||||
|
if (asprintf(&p, "FILE:%s/%s", iter->dc->dir, iter->primary) > -1 && p != NULL &&
|
||||||
|
stat(p + sizeof("FILE:") - 1, &st) == 0 && S_ISREG(st.st_mode))
|
||||||
|
ret = krb5_cc_resolve(context, p, id);
|
||||||
|
if (p == NULL)
|
||||||
|
return krb5_enomem(context);
|
||||||
|
free(p);
|
||||||
|
if (ret == 0)
|
||||||
|
return ret;
|
||||||
|
p = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX We need to readdir() here */
|
|
||||||
iter->first = 0;
|
iter->first = 0;
|
||||||
|
for (dentry = readdir(iter->d); dentry; dentry = readdir(iter->d)) {
|
||||||
|
if (!is_filename_cacheish(dentry->d_name) ||
|
||||||
|
(iter->primary && strcmp(dentry->d_name, iter->primary) == 0))
|
||||||
|
continue;
|
||||||
|
p = NULL;
|
||||||
|
ret = KRB5_CC_END;
|
||||||
|
if (asprintf(&p, "FILE:%s/%s", iter->dc->dir, dentry->d_name) > -1 &&
|
||||||
|
p != NULL &&
|
||||||
|
stat(p + sizeof("FILE:") - 1, &st) == 0 && S_ISREG(st.st_mode))
|
||||||
|
ret = krb5_cc_resolve(context, p, id);
|
||||||
|
free(p);
|
||||||
|
if (p == NULL)
|
||||||
|
return krb5_enomem(context);
|
||||||
|
if (ret == 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return KRB5_CC_END;
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,9 +752,10 @@ dcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
|
|||||||
if (iter == NULL)
|
if (iter == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
/* XXX We need to closedir() here */
|
(void) closedir(iter->d);
|
||||||
if (iter->dc)
|
free(iter->dc->dir);
|
||||||
dcc_release(context, iter->dc);
|
free(iter->dc);
|
||||||
|
free(iter->primary);
|
||||||
free(iter);
|
free(iter);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -622,14 +765,22 @@ dcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
|
|||||||
{
|
{
|
||||||
krb5_dcache *dcfrom = DCACHE(from);
|
krb5_dcache *dcfrom = DCACHE(from);
|
||||||
krb5_dcache *dcto = DCACHE(to);
|
krb5_dcache *dcto = DCACHE(to);
|
||||||
|
|
||||||
|
dcfrom->default_candidate = 0;
|
||||||
|
dcto->default_candidate = 1;
|
||||||
return krb5_cc_move(context, D2FCACHE(dcfrom), D2FCACHE(dcto));
|
return krb5_cc_move(context, D2FCACHE(dcfrom), D2FCACHE(dcto));
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
dcc_get_default_name(krb5_context context, char **str)
|
dcc_get_default_name(krb5_context context, char **str)
|
||||||
{
|
{
|
||||||
return _krb5_expand_default_cc_name(context,
|
const char *def_cc_colname =
|
||||||
KRB5_DEFAULT_CCNAME_DIR,
|
krb5_config_get_string_default(context, NULL, KRB5_DEFAULT_CCNAME_DIR,
|
||||||
|
"libdefaults", "default_cc_collection",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* What if def_cc_colname does not start with DIR:? We tolerate it. */
|
||||||
|
return _krb5_expand_default_cc_name(context, def_cc_colname,
|
||||||
str);
|
str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,13 +788,10 @@ static krb5_error_code KRB5_CALLCONV
|
|||||||
dcc_set_default(krb5_context context, krb5_ccache id)
|
dcc_set_default(krb5_context context, krb5_ccache id)
|
||||||
{
|
{
|
||||||
krb5_dcache *dc = DCACHE(id);
|
krb5_dcache *dc = DCACHE(id);
|
||||||
const char *name;
|
|
||||||
|
|
||||||
name = krb5_cc_get_name(context, D2FCACHE(dc));
|
if (dc->sub == NULL)
|
||||||
if (name == NULL)
|
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
return set_default_cache(context, dc, dc->sub);
|
||||||
return set_default_cache(context, dc, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
|
@@ -62,14 +62,23 @@ struct fcc_cursor {
|
|||||||
|
|
||||||
#define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
|
#define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
|
||||||
|
|
||||||
static const char* KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
fcc_get_name(krb5_context context,
|
fcc_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **colname,
|
||||||
|
const char **sub)
|
||||||
{
|
{
|
||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return NULL;
|
return KRB5_CC_NOTFOUND;
|
||||||
|
|
||||||
return FILENAME(id);
|
if (name)
|
||||||
|
*name = FILENAME(id);
|
||||||
|
if (colname)
|
||||||
|
*colname = FILENAME(id);
|
||||||
|
if (sub)
|
||||||
|
*sub = NULL;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
KRB5_LIB_FUNCTION int KRB5_LIB_CALL
|
KRB5_LIB_FUNCTION int KRB5_LIB_CALL
|
||||||
@@ -178,15 +187,32 @@ static krb5_error_code KRB5_CALLCONV
|
|||||||
fcc_lock(krb5_context context, krb5_ccache id,
|
fcc_lock(krb5_context context, krb5_ccache id,
|
||||||
int fd, krb5_boolean exclusive)
|
int fd, krb5_boolean exclusive)
|
||||||
{
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
if (exclusive == FALSE)
|
if (exclusive == FALSE)
|
||||||
return 0;
|
return 0;
|
||||||
return _krb5_xlock(context, fd, exclusive, fcc_get_name(context, id));
|
ret = fcc_get_name(context, id, &name, NULL, NULL);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = _krb5_xlock(context, fd, exclusive, name);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
fcc_resolve(krb5_context context,
|
||||||
|
krb5_ccache *id,
|
||||||
|
const char *res,
|
||||||
|
const char *sub)
|
||||||
{
|
{
|
||||||
krb5_fcache *f;
|
krb5_fcache *f;
|
||||||
|
|
||||||
|
if (sub && *sub) {
|
||||||
|
krb5_set_error_message(context, KRB5_CC_NOSUPP,
|
||||||
|
N_("FILE ccache type is not a collection "
|
||||||
|
"type", ""));
|
||||||
|
return KRB5_CC_NOSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
f = calloc(1, sizeof(*f));
|
f = calloc(1, sizeof(*f));
|
||||||
if(f == NULL) {
|
if(f == NULL) {
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
||||||
@@ -204,6 +230,7 @@ fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
|||||||
f->version = 0;
|
f->version = 0;
|
||||||
(*id)->data.data = f;
|
(*id)->data.data = f;
|
||||||
(*id)->data.length = sizeof(*f);
|
(*id)->data.length = sizeof(*f);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,11 +674,8 @@ fcc_destroy(krb5_context context,
|
|||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
if (TMPFILENAME(id)) {
|
if (TMPFILENAME(id))
|
||||||
(void) _krb5_erase_file(context, TMPFILENAME(id));
|
(void) _krb5_erase_file(context, TMPFILENAME(id));
|
||||||
free(TMPFILENAME(id));
|
|
||||||
TMPFILENAME(id) = NULL;
|
|
||||||
}
|
|
||||||
return _krb5_erase_file(context, FILENAME(id));
|
return _krb5_erase_file(context, FILENAME(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -136,7 +136,9 @@ krb5_kcm_storage_request(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
kcm_alloc(krb5_context context, const char *name, krb5_ccache *id)
|
kcm_alloc(krb5_context context,
|
||||||
|
const char *name,
|
||||||
|
krb5_ccache *id)
|
||||||
{
|
{
|
||||||
krb5_kcmcache *k;
|
krb5_kcmcache *k;
|
||||||
|
|
||||||
@@ -229,17 +231,42 @@ kcm_free(krb5_context context, krb5_ccache *id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static krb5_error_code KRB5_CALLCONV
|
||||||
kcm_get_name(krb5_context context,
|
kcm_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **col,
|
||||||
|
const char **sub)
|
||||||
{
|
{
|
||||||
return CACHENAME(id);
|
/*
|
||||||
|
* TODO:
|
||||||
|
*
|
||||||
|
* - name should be <IPC-name>:<cache-name>
|
||||||
|
* - col should be <IPC-name>
|
||||||
|
* - sub should be <cache-name>
|
||||||
|
*/
|
||||||
|
if (name)
|
||||||
|
*name = CACHENAME(id);
|
||||||
|
if (col)
|
||||||
|
*col = NULL;
|
||||||
|
if (sub)
|
||||||
|
*sub = CACHENAME(id);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
kcm_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
kcm_resolve(krb5_context context,
|
||||||
|
krb5_ccache *id,
|
||||||
|
const char *res,
|
||||||
|
const char *sub)
|
||||||
{
|
{
|
||||||
return kcm_alloc(context, res, id);
|
/*
|
||||||
|
* For now, for KCM the `res' is the `sub'.
|
||||||
|
*
|
||||||
|
* TODO: We should use `res' as the IPC name instead of the one currently
|
||||||
|
* hard-coded in `kcm_ipc_name'.
|
||||||
|
*/
|
||||||
|
return kcm_alloc(context, sub && *sub ? sub : res, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -491,13 +491,16 @@ typedef struct krb5_creds {
|
|||||||
|
|
||||||
typedef struct krb5_cc_cache_cursor_data *krb5_cc_cache_cursor;
|
typedef struct krb5_cc_cache_cursor_data *krb5_cc_cache_cursor;
|
||||||
|
|
||||||
#define KRB5_CC_OPS_VERSION 3
|
#define KRB5_CC_OPS_VERSION 4
|
||||||
|
|
||||||
typedef struct krb5_cc_ops {
|
typedef struct krb5_cc_ops {
|
||||||
int version;
|
int version;
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
const char* (KRB5_CALLCONV * get_name)(krb5_context, krb5_ccache);
|
krb5_error_code (KRB5_CALLCONV * get_name)(krb5_context, krb5_ccache,
|
||||||
krb5_error_code (KRB5_CALLCONV * resolve)(krb5_context, krb5_ccache *, const char *);
|
const char **, const char **,
|
||||||
|
const char **);
|
||||||
|
krb5_error_code (KRB5_CALLCONV * resolve)(krb5_context, krb5_ccache *, const char *,
|
||||||
|
const char *);
|
||||||
krb5_error_code (KRB5_CALLCONV * gen_new)(krb5_context, krb5_ccache *);
|
krb5_error_code (KRB5_CALLCONV * gen_new)(krb5_context, krb5_ccache *);
|
||||||
krb5_error_code (KRB5_CALLCONV * init)(krb5_context, krb5_ccache, krb5_principal);
|
krb5_error_code (KRB5_CALLCONV * init)(krb5_context, krb5_ccache, krb5_principal);
|
||||||
krb5_error_code (KRB5_CALLCONV * destroy)(krb5_context, krb5_ccache);
|
krb5_error_code (KRB5_CALLCONV * destroy)(krb5_context, krb5_ccache);
|
||||||
|
@@ -207,6 +207,8 @@ typedef union _krb5_krcache_and_princ_id {
|
|||||||
*/
|
*/
|
||||||
typedef struct _krb5_krcache {
|
typedef struct _krb5_krcache {
|
||||||
char *krc_name; /* Name for this credentials cache */
|
char *krc_name; /* Name for this credentials cache */
|
||||||
|
char *krc_collection;
|
||||||
|
char *krc_subsidiary;
|
||||||
krb5_timestamp krc_changetime; /* update time, does not decrease (mutable) */
|
krb5_timestamp krc_changetime; /* update time, does not decrease (mutable) */
|
||||||
krb5_krcache_and_princ_id krc_id; /* cache and principal IDs (mutable) */
|
krb5_krcache_and_princ_id krc_id; /* cache and principal IDs (mutable) */
|
||||||
#define krc_cache_and_principal_id krc_id.krcu_cache_and_princ_id
|
#define krc_cache_and_principal_id krc_id.krcu_cache_and_princ_id
|
||||||
@@ -384,8 +386,6 @@ parse_residual(krb5_context context,
|
|||||||
collection_name = strdup(residual);
|
collection_name = strdup(residual);
|
||||||
if (collection_name == NULL)
|
if (collection_name == NULL)
|
||||||
goto nomem;
|
goto nomem;
|
||||||
|
|
||||||
subsidiary_name = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
collection_name = strndup(residual, sep - residual);
|
collection_name = strndup(residual, sep - residual);
|
||||||
if (collection_name == NULL)
|
if (collection_name == NULL)
|
||||||
@@ -918,14 +918,18 @@ initialize_internal(krb5_context context,
|
|||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
krcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
|
krcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
|
||||||
{
|
{
|
||||||
|
krb5_krcache *data = KRCACHE(id);
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
if (data == NULL)
|
||||||
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
if (princ == NULL)
|
if (princ == NULL)
|
||||||
return KRB5_CC_BADNAME;
|
return KRB5_CC_BADNAME;
|
||||||
|
|
||||||
ret = initialize_internal(context, id, princ);
|
ret = initialize_internal(context, id, princ);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
update_change_time(context, 0, KRCACHE(id));
|
update_change_time(context, 0, data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -939,6 +943,8 @@ krcc_close(krb5_context context, krb5_ccache id)
|
|||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
|
free(data->krc_subsidiary);
|
||||||
|
free(data->krc_collection);
|
||||||
free(data->krc_name);
|
free(data->krc_name);
|
||||||
krb5_data_free(&id->data);
|
krb5_data_free(&id->data);
|
||||||
|
|
||||||
@@ -1048,16 +1054,26 @@ make_cache(krb5_context context,
|
|||||||
|
|
||||||
/* Create a keyring ccache handle for the given residual string. */
|
/* Create a keyring ccache handle for the given residual string. */
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual)
|
krcc_resolve(krb5_context context,
|
||||||
|
krb5_ccache *id,
|
||||||
|
const char *residual,
|
||||||
|
const char *sub)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
key_serial_t collection_id, cache_id;
|
key_serial_t collection_id, cache_id;
|
||||||
char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL;
|
char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL;
|
||||||
|
|
||||||
ret = parse_residual(context, residual, &anchor_name, &collection_name,
|
ret = parse_residual(context, residual, &anchor_name, &collection_name,
|
||||||
&subsidiary_name);
|
&subsidiary_name);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
if (sub) {
|
||||||
|
free(subsidiary_name);
|
||||||
|
if ((subsidiary_name = strdup(sub)) == NULL) {
|
||||||
|
ret = krb5_enomem(context);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = get_collection(context, anchor_name, collection_name, &collection_id);
|
ret = get_collection(context, anchor_name, collection_name, &collection_id);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -1243,8 +1259,16 @@ alloc_cache(krb5_context context,
|
|||||||
|
|
||||||
ret = make_subsidiary_residual(context, anchor_name, collection_name,
|
ret = make_subsidiary_residual(context, anchor_name, collection_name,
|
||||||
subsidiary_name, &data->krc_name);
|
subsidiary_name, &data->krc_name);
|
||||||
if (ret) {
|
if (ret ||
|
||||||
|
(data->krc_collection = strdup(collection_name)) == NULL ||
|
||||||
|
(data->krc_subsidiary = strdup(subsidiary_name)) == NULL) {
|
||||||
|
if (data) {
|
||||||
|
free(data->krc_collection);
|
||||||
|
free(data->krc_name);
|
||||||
|
}
|
||||||
free(data);
|
free(data);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = krb5_enomem(context);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,10 +1345,25 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return an alias to the residual string of the cache. */
|
/* Return an alias to the residual string of the cache. */
|
||||||
static const char *KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
krcc_get_name(krb5_context context, krb5_ccache id)
|
krcc_get_name(krb5_context context,
|
||||||
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **collection_name,
|
||||||
|
const char **subsidiary_name)
|
||||||
{
|
{
|
||||||
return KRCACHE(id)->krc_name;
|
krb5_krcache *data = KRCACHE(id);
|
||||||
|
|
||||||
|
if (data == NULL)
|
||||||
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
*name = data->krc_name;
|
||||||
|
if (collection_name)
|
||||||
|
*collection_name = data->krc_collection;
|
||||||
|
if (subsidiary_name)
|
||||||
|
*subsidiary_name = data->krc_subsidiary;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve a copy of the default principal, if the cache is initialized. */
|
/* Retrieve a copy of the default principal, if the cache is initialized. */
|
||||||
@@ -1641,6 +1680,9 @@ krcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat offset)
|
|||||||
key_serial_t cache_id;
|
key_serial_t cache_id;
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
if (data == NULL)
|
||||||
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
heim_base_exchange_32(&cache_id, data->krc_cache_id);
|
heim_base_exchange_32(&cache_id, data->krc_cache_id);
|
||||||
|
|
||||||
ret = save_time_offsets(context, cache_id, (int32_t)offset, 0);
|
ret = save_time_offsets(context, cache_id, (int32_t)offset, 0);
|
||||||
|
@@ -87,6 +87,8 @@ EXPORTS
|
|||||||
krb5_cc_copy_creds ;!
|
krb5_cc_copy_creds ;!
|
||||||
krb5_cc_copy_match_f
|
krb5_cc_copy_match_f
|
||||||
krb5_cc_default
|
krb5_cc_default
|
||||||
|
krb5_cc_default_sub
|
||||||
|
krb5_cc_default_for
|
||||||
krb5_cc_default_name
|
krb5_cc_default_name
|
||||||
krb5_cc_destroy
|
krb5_cc_destroy
|
||||||
krb5_cc_end_seq_get
|
krb5_cc_end_seq_get
|
||||||
@@ -111,6 +113,8 @@ EXPORTS
|
|||||||
krb5_cc_register
|
krb5_cc_register
|
||||||
krb5_cc_remove_cred
|
krb5_cc_remove_cred
|
||||||
krb5_cc_resolve
|
krb5_cc_resolve
|
||||||
|
krb5_cc_resolve_sub
|
||||||
|
krb5_cc_resolve_for
|
||||||
krb5_cc_retrieve_cred
|
krb5_cc_retrieve_cred
|
||||||
krb5_cc_set_config
|
krb5_cc_set_config
|
||||||
krb5_cc_set_default_name
|
krb5_cc_set_default_name
|
||||||
|
@@ -38,7 +38,8 @@
|
|||||||
typedef struct krb5_mcache {
|
typedef struct krb5_mcache {
|
||||||
char *name;
|
char *name;
|
||||||
unsigned int refcnt;
|
unsigned int refcnt;
|
||||||
int dead;
|
unsigned int anonymous:1;
|
||||||
|
unsigned int dead:1;
|
||||||
krb5_principal primary_principal;
|
krb5_principal primary_principal;
|
||||||
struct link {
|
struct link {
|
||||||
krb5_creds cred;
|
krb5_creds cred;
|
||||||
@@ -57,42 +58,89 @@ static struct krb5_mcache *mcc_head;
|
|||||||
|
|
||||||
#define MISDEAD(X) ((X)->dead)
|
#define MISDEAD(X) ((X)->dead)
|
||||||
|
|
||||||
static const char* KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
mcc_get_name(krb5_context context,
|
mcc_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **col,
|
||||||
|
const char **sub)
|
||||||
{
|
{
|
||||||
return MCACHE(id)->name;
|
if (name)
|
||||||
|
*name = MCACHE(id)->name;
|
||||||
|
if (col)
|
||||||
|
*col = NULL;
|
||||||
|
if (sub)
|
||||||
|
*sub = MCACHE(id)->name;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_mcache * KRB5_CALLCONV
|
static krb5_error_code
|
||||||
mcc_alloc(const char *name)
|
mcc_alloc(krb5_context context, const char *name, krb5_mcache **out)
|
||||||
{
|
{
|
||||||
krb5_mcache *m, *m_c;
|
krb5_mcache *m, *m_c;
|
||||||
|
size_t counter = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
*out = NULL;
|
||||||
ALLOC(m, 1);
|
ALLOC(m, 1);
|
||||||
if(m == NULL)
|
if(m == NULL)
|
||||||
return NULL;
|
return krb5_enomem(context);
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (counter > 3) {
|
||||||
|
free(m->name);
|
||||||
|
free(m);
|
||||||
|
return EAGAIN; /* XXX */
|
||||||
|
}
|
||||||
if(name == NULL)
|
if(name == NULL)
|
||||||
ret = asprintf(&m->name, "%p", m);
|
ret = asprintf(&m->name, "u%p-%llu", m, (unsigned long long)counter);
|
||||||
else
|
else
|
||||||
m->name = strdup(name);
|
m->name = strdup(name);
|
||||||
if(ret < 0 || m->name == NULL) {
|
if(ret < 0 || m->name == NULL) {
|
||||||
free(m);
|
free(m);
|
||||||
return NULL;
|
return krb5_enomem(context);
|
||||||
}
|
}
|
||||||
|
if (strcmp(m->name, "anonymous") == 0) {
|
||||||
|
m->anonymous = 1;
|
||||||
|
m->dead = 0;
|
||||||
|
m->refcnt = 1;
|
||||||
|
m->primary_principal = NULL;
|
||||||
|
m->creds = NULL;
|
||||||
|
m->mtime = time(NULL);
|
||||||
|
m->kdc_offset = 0;
|
||||||
|
m->next = NULL;
|
||||||
|
*out = m;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* check for dups first */
|
/* check for dups first */
|
||||||
HEIMDAL_MUTEX_lock(&mcc_mutex);
|
HEIMDAL_MUTEX_lock(&mcc_mutex);
|
||||||
for (m_c = mcc_head; m_c != NULL; m_c = m_c->next)
|
for (m_c = mcc_head; m_c != NULL; m_c = m_c->next)
|
||||||
if (strcmp(m->name, m_c->name) == 0)
|
if (strcmp(m->name, m_c->name) == 0)
|
||||||
break;
|
break;
|
||||||
if (m_c) {
|
if (m_c) {
|
||||||
free(m->name);
|
free(m->name);
|
||||||
free(m);
|
free(m);
|
||||||
HEIMDAL_MUTEX_unlock(&mcc_mutex);
|
if (name) {
|
||||||
return NULL;
|
/* We raced with another thread to create this cache */
|
||||||
|
m = m_c;
|
||||||
|
HEIMDAL_MUTEX_lock(&(m->mutex));
|
||||||
|
m->refcnt++;
|
||||||
|
HEIMDAL_MUTEX_unlock(&(m->mutex));
|
||||||
|
} else {
|
||||||
|
/* How likely are we to conflict on new_unique anyways?? */
|
||||||
|
counter++;
|
||||||
|
free(m->name);
|
||||||
|
m->name = NULL;
|
||||||
|
HEIMDAL_MUTEX_unlock(&mcc_mutex);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
HEIMDAL_MUTEX_unlock(&mcc_mutex);
|
||||||
|
*out = m;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m->anonymous = 0;
|
||||||
m->dead = 0;
|
m->dead = 0;
|
||||||
m->refcnt = 1;
|
m->refcnt = 1;
|
||||||
m->primary_principal = NULL;
|
m->primary_principal = NULL;
|
||||||
@@ -103,35 +151,21 @@ mcc_alloc(const char *name)
|
|||||||
HEIMDAL_MUTEX_init(&(m->mutex));
|
HEIMDAL_MUTEX_init(&(m->mutex));
|
||||||
mcc_head = m;
|
mcc_head = m;
|
||||||
HEIMDAL_MUTEX_unlock(&mcc_mutex);
|
HEIMDAL_MUTEX_unlock(&mcc_mutex);
|
||||||
return m;
|
*out = m;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
mcc_resolve(krb5_context context,
|
||||||
|
krb5_ccache *id,
|
||||||
|
const char *res,
|
||||||
|
const char *sub)
|
||||||
{
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
krb5_mcache *m;
|
krb5_mcache *m;
|
||||||
|
|
||||||
HEIMDAL_MUTEX_lock(&mcc_mutex);
|
if ((ret = mcc_alloc(context, sub && *sub ? sub : res, &m)))
|
||||||
for (m = mcc_head; m != NULL; m = m->next)
|
return ret;
|
||||||
if (strcmp(m->name, res) == 0)
|
|
||||||
break;
|
|
||||||
HEIMDAL_MUTEX_unlock(&mcc_mutex);
|
|
||||||
|
|
||||||
if (m != NULL) {
|
|
||||||
HEIMDAL_MUTEX_lock(&(m->mutex));
|
|
||||||
m->refcnt++;
|
|
||||||
HEIMDAL_MUTEX_unlock(&(m->mutex));
|
|
||||||
(*id)->data.data = m;
|
|
||||||
(*id)->data.length = sizeof(*m);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m = mcc_alloc(res);
|
|
||||||
if (m == NULL) {
|
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
|
||||||
N_("malloc: out of memory", ""));
|
|
||||||
return KRB5_CC_NOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*id)->data.data = m;
|
(*id)->data.data = m;
|
||||||
(*id)->data.length = sizeof(*m);
|
(*id)->data.length = sizeof(*m);
|
||||||
@@ -143,15 +177,11 @@ mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
|||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
mcc_gen_new(krb5_context context, krb5_ccache *id)
|
mcc_gen_new(krb5_context context, krb5_ccache *id)
|
||||||
{
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
krb5_mcache *m;
|
krb5_mcache *m;
|
||||||
|
|
||||||
m = mcc_alloc(NULL);
|
if ((ret = mcc_alloc(context, NULL, &m)))
|
||||||
|
return ret;
|
||||||
if (m == NULL) {
|
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
|
||||||
N_("malloc: out of memory", ""));
|
|
||||||
return KRB5_CC_NOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*id)->data.data = m;
|
(*id)->data.data = m;
|
||||||
(*id)->data.length = sizeof(*m);
|
(*id)->data.length = sizeof(*m);
|
||||||
@@ -221,7 +251,7 @@ mcc_close_internal(krb5_mcache *m)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (MISDEAD(m)) {
|
if (MISDEAD(m)) {
|
||||||
free (m->name);
|
free(m->name);
|
||||||
HEIMDAL_MUTEX_unlock(&(m->mutex));
|
HEIMDAL_MUTEX_unlock(&(m->mutex));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -248,6 +278,18 @@ mcc_destroy(krb5_context context,
|
|||||||
{
|
{
|
||||||
krb5_mcache **n, *m = MCACHE(id);
|
krb5_mcache **n, *m = MCACHE(id);
|
||||||
|
|
||||||
|
if (m->anonymous) {
|
||||||
|
HEIMDAL_MUTEX_lock(&(m->mutex));
|
||||||
|
if (m->refcnt == 0) {
|
||||||
|
HEIMDAL_MUTEX_unlock(&(m->mutex));
|
||||||
|
krb5_abortx(context, "mcc_destroy: refcnt already 0");
|
||||||
|
}
|
||||||
|
if (!MISDEAD(m))
|
||||||
|
mcc_destroy_internal(context, m);
|
||||||
|
HEIMDAL_MUTEX_unlock(&(m->mutex));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
HEIMDAL_MUTEX_lock(&mcc_mutex);
|
HEIMDAL_MUTEX_lock(&mcc_mutex);
|
||||||
HEIMDAL_MUTEX_lock(&(m->mutex));
|
HEIMDAL_MUTEX_lock(&(m->mutex));
|
||||||
if (m->refcnt == 0)
|
if (m->refcnt == 0)
|
||||||
@@ -290,12 +332,8 @@ mcc_store_cred(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
l = malloc (sizeof(*l));
|
l = malloc (sizeof(*l));
|
||||||
if (l == NULL) {
|
if (l == NULL)
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
return krb5_enomem(context);
|
||||||
N_("malloc: out of memory", ""));
|
|
||||||
HEIMDAL_MUTEX_unlock(&(m->mutex));
|
|
||||||
return KRB5_CC_NOMEM;
|
|
||||||
}
|
|
||||||
l->next = m->creds;
|
l->next = m->creds;
|
||||||
m->creds = l;
|
m->creds = l;
|
||||||
memset (&l->cred, 0, sizeof(l->cred));
|
memset (&l->cred, 0, sizeof(l->cred));
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
typedef struct krb5_scache {
|
typedef struct krb5_scache {
|
||||||
char *name;
|
char *name;
|
||||||
char *file;
|
char *file;
|
||||||
|
char *sub;
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
|
|
||||||
sqlite_uint64 cid;
|
sqlite_uint64 cid;
|
||||||
@@ -66,7 +67,7 @@ typedef struct krb5_scache {
|
|||||||
#else
|
#else
|
||||||
#define KRB5_SCACHE_DB "/tmp/krb5scc_%{uid}"
|
#define KRB5_SCACHE_DB "/tmp/krb5scc_%{uid}"
|
||||||
#endif
|
#endif
|
||||||
#define KRB5_SCACHE_NAME "SCC:" SCACHE_DEF_NAME ":" KRB5_SCACHE_DB
|
#define KRB5_SCACHE_NAME "SCC:" KRB5_SCACHE_DB ":" SCACHE_DEF_NAME
|
||||||
|
|
||||||
#define SCACHE_INVALID_CID ((sqlite_uint64)-1)
|
#define SCACHE_INVALID_CID ((sqlite_uint64)-1)
|
||||||
|
|
||||||
@@ -103,7 +104,8 @@ typedef struct krb5_scache {
|
|||||||
#define SQL_UCACHE_PRINCIPAL "UPDATE caches SET principal=? WHERE OID=?"
|
#define SQL_UCACHE_PRINCIPAL "UPDATE caches SET principal=? WHERE OID=?"
|
||||||
#define SQL_DCACHE "DELETE FROM caches WHERE OID=?"
|
#define SQL_DCACHE "DELETE FROM caches WHERE OID=?"
|
||||||
#define SQL_SCACHE "SELECT principal,name FROM caches WHERE OID=?"
|
#define SQL_SCACHE "SELECT principal,name FROM caches WHERE OID=?"
|
||||||
#define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=?"
|
#define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=? OR " \
|
||||||
|
"(PRINCIPAL IS NOT NULL AND PRINCIPAL=?)"
|
||||||
|
|
||||||
#define SQL_CCREDS "" \
|
#define SQL_CCREDS "" \
|
||||||
"CREATE TABLE credentials (" \
|
"CREATE TABLE credentials (" \
|
||||||
@@ -153,8 +155,12 @@ free_krb5(void *str)
|
|||||||
static void
|
static void
|
||||||
scc_free(krb5_scache *s)
|
scc_free(krb5_scache *s)
|
||||||
{
|
{
|
||||||
|
if (!s)
|
||||||
|
return;
|
||||||
if (s->file)
|
if (s->file)
|
||||||
free(s->file);
|
free(s->file);
|
||||||
|
if (s->sub)
|
||||||
|
free(s->sub);
|
||||||
if (s->name)
|
if (s->name)
|
||||||
free(s->name);
|
free(s->name);
|
||||||
|
|
||||||
@@ -225,22 +231,53 @@ exec_stmt(krb5_context context, sqlite3 *db, const char *str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
default_db(krb5_context context, sqlite3 **db)
|
default_db(krb5_context context, const char *name, sqlite3 **db, char **file)
|
||||||
{
|
{
|
||||||
char *name;
|
char *s = NULL;
|
||||||
|
char *f = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &name);
|
if (file)
|
||||||
if (ret)
|
*file = NULL;
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sqlite3_open_v2(name, db, SQLITE_OPEN_READWRITE, NULL);
|
if (name == NULL) {
|
||||||
free(name);
|
if ((name = krb5_cc_default_name(context))) {
|
||||||
|
if (strncmp(name, "SCC:", sizeof("SCC:") - 1) == 0)
|
||||||
|
name += sizeof("SCC:") - 1;
|
||||||
|
}
|
||||||
|
if (name == NULL) {
|
||||||
|
ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
name = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(name, "SCC:", sizeof("SCC:") - 1) == 0)
|
||||||
|
name += sizeof("SCC:") - 1;
|
||||||
|
|
||||||
|
if ((f = strdup(name)) == NULL) {
|
||||||
|
free(s);
|
||||||
|
return krb5_enomem(context);
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
|
||||||
|
if ((s = strrchr(f, ':')))
|
||||||
|
*s = '\0';
|
||||||
|
|
||||||
|
ret = sqlite3_open_v2(f, db, SQLITE_OPEN_READWRITE, NULL);
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
|
sqlite3_close_v2(*db);
|
||||||
krb5_clear_error_message(context);
|
krb5_clear_error_message(context);
|
||||||
|
free(f);
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
*file = f;
|
||||||
|
else
|
||||||
|
free(f);
|
||||||
|
|
||||||
#ifdef TRACEME
|
#ifdef TRACEME
|
||||||
sqlite3_trace(*db, trace, NULL);
|
sqlite3_trace(*db, trace, NULL);
|
||||||
#endif
|
#endif
|
||||||
@@ -249,14 +286,14 @@ default_db(krb5_context context, sqlite3 **db)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
get_def_name(krb5_context context, char **str)
|
get_def_name(krb5_context context, char *filein, char **str, char **file)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
const char *name;
|
const char *name;
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
|
|
||||||
ret = default_db(context, &db);
|
ret = default_db(context, filein, &db, file);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -294,10 +331,15 @@ out:
|
|||||||
|
|
||||||
|
|
||||||
static krb5_scache * KRB5_CALLCONV
|
static krb5_scache * KRB5_CALLCONV
|
||||||
scc_alloc(krb5_context context, const char *name)
|
scc_alloc(krb5_context context,
|
||||||
|
const char *name,
|
||||||
|
const char *sub,
|
||||||
|
int new_unique)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret = 0;
|
||||||
krb5_scache *s;
|
krb5_scache *s;
|
||||||
|
char *freeme = NULL;
|
||||||
|
char *subsidiary;
|
||||||
|
|
||||||
ALLOC(s, 1);
|
ALLOC(s, 1);
|
||||||
if(s == NULL)
|
if(s == NULL)
|
||||||
@@ -305,41 +347,87 @@ scc_alloc(krb5_context context, const char *name)
|
|||||||
|
|
||||||
s->cid = SCACHE_INVALID_CID;
|
s->cid = SCACHE_INVALID_CID;
|
||||||
|
|
||||||
if (name) {
|
if (name && *name && sub && *sub) {
|
||||||
char *file;
|
if ((s->sub = strdup(sub)) == NULL ||
|
||||||
|
(s->file = strdup(name)) == NULL) {
|
||||||
if (*name == '\0') {
|
free(s->file);
|
||||||
ret = get_def_name(context, &s->name);
|
free(s);
|
||||||
if (ret)
|
(void) krb5_enomem(context);
|
||||||
s->name = strdup(SCACHE_DEF_NAME);
|
return NULL;
|
||||||
} else
|
}
|
||||||
s->name = strdup(name);
|
|
||||||
|
|
||||||
file = strrchr(s->name, ':');
|
|
||||||
if (file) {
|
|
||||||
*file++ = '\0';
|
|
||||||
s->file = strdup(file);
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
_krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file);
|
s->sub = NULL;
|
||||||
ret = asprintf(&s->name, "unique-%p", s);
|
s->file = NULL;
|
||||||
|
s->name = NULL;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
name = krb5_cc_default_name(context);
|
||||||
|
if (name == NULL) {
|
||||||
|
ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB,
|
||||||
|
&freeme);
|
||||||
|
if (ret) {
|
||||||
|
free(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
name = freeme;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(name, "SCC:", sizeof("SCC:") - 1) == 0)
|
||||||
|
name += sizeof("SCC:") - 1;
|
||||||
|
|
||||||
|
if ((s->file = strdup(name)) == NULL) {
|
||||||
|
(void) krb5_enomem(context);
|
||||||
|
scc_free(s);
|
||||||
|
free(freeme);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((subsidiary = strrchr(s->file, ':'))) {
|
||||||
|
#ifdef WIN32
|
||||||
|
if (subsidiary == &s->file + 1)
|
||||||
|
subsidiary = NULL;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
*(subsidiary++) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_unique) {
|
||||||
|
ret = asprintf(&s->sub, "unique-%p", s) < 0 || s->sub == NULL ?
|
||||||
|
krb5_enomem(context) : 0;
|
||||||
|
} else if (subsidiary == NULL || *subsidiary == '\0') {
|
||||||
|
ret = get_def_name(context, s->file, &s->sub, NULL);
|
||||||
|
if (ret) {
|
||||||
|
if ((s->sub = strdup(SCACHE_DEF_NAME)) == NULL)
|
||||||
|
ret = krb5_enomem(context);
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
} else if ((s->sub = strdup(subsidiary)) == NULL) {
|
||||||
|
ret = krb5_enomem(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ret < 0 || s->file == NULL || s->name == NULL) {
|
|
||||||
|
if (ret == 0 && s->file && s->sub &&
|
||||||
|
(asprintf(&s->name, "%s:%s", s->file, s->sub) < 0 || s->name == NULL))
|
||||||
|
ret = krb5_enomem(context);
|
||||||
|
if (ret || s->file == NULL || s->sub == NULL || s->name == NULL) {
|
||||||
scc_free(s);
|
scc_free(s);
|
||||||
|
free(freeme);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
open_database(krb5_context context, krb5_scache *s, int flags)
|
open_database(krb5_context context, krb5_scache *s, int flags)
|
||||||
{
|
{
|
||||||
|
struct stat st;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
||||||
|
if (!(flags & SQLITE_OPEN_CREATE) && stat(s->file, &st) == 0 &&
|
||||||
|
st.st_size == 0)
|
||||||
|
return ENOENT;
|
||||||
ret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL);
|
ret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (s->db) {
|
if (s->db) {
|
||||||
@@ -361,7 +449,7 @@ create_cache(krb5_context context, krb5_scache *s)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sqlite3_bind_text(s->icache, 1, s->name, -1, NULL);
|
sqlite3_bind_text(s->icache, 1, s->sub, -1, NULL);
|
||||||
do {
|
do {
|
||||||
ret = sqlite3_step(s->icache);
|
ret = sqlite3_step(s->icache);
|
||||||
} while (ret == SQLITE_ROW);
|
} while (ret == SQLITE_ROW);
|
||||||
@@ -477,20 +565,32 @@ bind_principal(krb5_context context,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const char* KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
scc_get_name(krb5_context context,
|
scc_get_name(krb5_context context,
|
||||||
krb5_ccache id)
|
krb5_ccache id,
|
||||||
|
const char **name,
|
||||||
|
const char **file,
|
||||||
|
const char **sub)
|
||||||
{
|
{
|
||||||
return SCACHE(id)->name;
|
if (name)
|
||||||
|
*name = SCACHE(id)->name;
|
||||||
|
if (file)
|
||||||
|
*file = SCACHE(id)->file;
|
||||||
|
if (sub)
|
||||||
|
*sub = SCACHE(id)->sub;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
scc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
scc_resolve(krb5_context context,
|
||||||
|
krb5_ccache *id,
|
||||||
|
const char *res,
|
||||||
|
const char *sub)
|
||||||
{
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
krb5_scache *s;
|
krb5_scache *s;
|
||||||
int ret;
|
|
||||||
|
|
||||||
s = scc_alloc(context, res);
|
s = scc_alloc(context, res, sub, 0);
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
||||||
N_("malloc: out of memory", ""));
|
N_("malloc: out of memory", ""));
|
||||||
@@ -503,12 +603,12 @@ scc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sqlite3_bind_text(s->scache_name, 1, s->name, -1, NULL);
|
ret = sqlite3_bind_text(s->scache_name, 1, s->sub, -1, NULL);
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
krb5_set_error_message(context, ENOMEM,
|
krb5_set_error_message(context, ENOMEM,
|
||||||
"bind name: %s", sqlite3_errmsg(s->db));
|
"bind principal: %s", sqlite3_errmsg(s->db));
|
||||||
scc_free(s);
|
scc_free(s);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sqlite3_step(s->scache_name) == SQLITE_ROW) {
|
if (sqlite3_step(s->scache_name) == SQLITE_ROW) {
|
||||||
@@ -540,7 +640,7 @@ scc_gen_new(krb5_context context, krb5_ccache *id)
|
|||||||
{
|
{
|
||||||
krb5_scache *s;
|
krb5_scache *s;
|
||||||
|
|
||||||
s = scc_alloc(context, NULL);
|
s = scc_alloc(context, NULL, NULL, 1);
|
||||||
|
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
||||||
@@ -557,7 +657,7 @@ scc_gen_new(krb5_context context, krb5_ccache *id)
|
|||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
scc_initialize(krb5_context context,
|
scc_initialize(krb5_context context,
|
||||||
krb5_ccache id,
|
krb5_ccache id,
|
||||||
krb5_principal primary_principal)
|
krb5_principal principal)
|
||||||
{
|
{
|
||||||
krb5_scache *s = SCACHE(id);
|
krb5_scache *s = SCACHE(id);
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
@@ -589,7 +689,7 @@ scc_initialize(krb5_context context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bind_principal(context, s->db, s->ucachep, 1, primary_principal);
|
ret = bind_principal(context, s->db, s->ucachep, 1, principal);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto rollback;
|
goto rollback;
|
||||||
sqlite3_bind_int(s->ucachep, 2, s->cid);
|
sqlite3_bind_int(s->ucachep, 2, s->cid);
|
||||||
@@ -827,8 +927,8 @@ scc_get_principal(krb5_context context,
|
|||||||
if (sqlite3_step(s->scache) != SQLITE_ROW) {
|
if (sqlite3_step(s->scache) != SQLITE_ROW) {
|
||||||
sqlite3_reset(s->scache);
|
sqlite3_reset(s->scache);
|
||||||
krb5_set_error_message(context, KRB5_CC_END,
|
krb5_set_error_message(context, KRB5_CC_END,
|
||||||
N_("No principal for cache SCC:%s:%s", ""),
|
N_("No principal for cache SCC:%s", ""),
|
||||||
s->name, s->file);
|
s->name);
|
||||||
return KRB5_CC_END;
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -836,8 +936,8 @@ scc_get_principal(krb5_context context,
|
|||||||
sqlite3_reset(s->scache);
|
sqlite3_reset(s->scache);
|
||||||
krb5_set_error_message(context, KRB5_CC_END,
|
krb5_set_error_message(context, KRB5_CC_END,
|
||||||
N_("Principal data of wrong type "
|
N_("Principal data of wrong type "
|
||||||
"for SCC:%s:%s", ""),
|
"for SCC:%s", ""),
|
||||||
s->name, s->file);
|
s->name);
|
||||||
return KRB5_CC_END;
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,8 +945,8 @@ scc_get_principal(krb5_context context,
|
|||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
sqlite3_reset(s->scache);
|
sqlite3_reset(s->scache);
|
||||||
krb5_set_error_message(context, KRB5_CC_END,
|
krb5_set_error_message(context, KRB5_CC_END,
|
||||||
N_("Principal not set for SCC:%s:%s", ""),
|
N_("Principal not set for SCC:%s", ""),
|
||||||
s->name, s->file);
|
s->name);
|
||||||
return KRB5_CC_END;
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1001,8 +1101,8 @@ next:
|
|||||||
|
|
||||||
if (sqlite3_column_type(ctx->credstmt, 0) != SQLITE_BLOB) {
|
if (sqlite3_column_type(ctx->credstmt, 0) != SQLITE_BLOB) {
|
||||||
krb5_set_error_message(context, KRB5_CC_END,
|
krb5_set_error_message(context, KRB5_CC_END,
|
||||||
N_("credential of wrong type for SCC:%s:%s", ""),
|
N_("credential of wrong type for SCC:%s", ""),
|
||||||
s->name, s->file);
|
s->name);
|
||||||
sqlite3_reset(ctx->credstmt);
|
sqlite3_reset(ctx->credstmt);
|
||||||
return KRB5_CC_END;
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
@@ -1079,8 +1179,8 @@ scc_remove_cred(krb5_context context,
|
|||||||
ret = KRB5_CC_END;
|
ret = KRB5_CC_END;
|
||||||
krb5_set_error_message(context, ret,
|
krb5_set_error_message(context, ret,
|
||||||
N_("Credential of wrong type "
|
N_("Credential of wrong type "
|
||||||
"for SCC:%s:%s", ""),
|
"for SCC:%s", ""),
|
||||||
s->name, s->file);
|
s->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1134,6 +1234,7 @@ scc_set_flags(krb5_context context,
|
|||||||
|
|
||||||
struct cache_iter {
|
struct cache_iter {
|
||||||
char *drop;
|
char *drop;
|
||||||
|
char *file;
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
};
|
};
|
||||||
@@ -1151,8 +1252,8 @@ scc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
|
|||||||
if (ctx == NULL)
|
if (ctx == NULL)
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
|
|
||||||
ret = default_db(context, &ctx->db);
|
ret = default_db(context, NULL, &ctx->db, &ctx->file);
|
||||||
if (ctx->db == NULL) {
|
if (ret) {
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1160,48 +1261,48 @@ scc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
|
|||||||
ret = asprintf(&name, "cacheIteration%pPid%d",
|
ret = asprintf(&name, "cacheIteration%pPid%d",
|
||||||
ctx, (int)getpid());
|
ctx, (int)getpid());
|
||||||
if (ret < 0 || name == NULL) {
|
if (ret < 0 || name == NULL) {
|
||||||
sqlite3_close(ctx->db);
|
sqlite3_close(ctx->db);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = asprintf(&ctx->drop, "DROP TABLE %s", name);
|
ret = asprintf(&ctx->drop, "DROP TABLE %s", name);
|
||||||
if (ret < 0 || ctx->drop == NULL) {
|
if (ret < 0 || ctx->drop == NULL) {
|
||||||
sqlite3_close(ctx->db);
|
sqlite3_close(ctx->db);
|
||||||
free(name);
|
free(name);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = asprintf(&str, "CREATE TEMPORARY TABLE %s AS SELECT name FROM caches",
|
ret = asprintf(&str, "CREATE TEMPORARY TABLE %s AS SELECT name FROM caches",
|
||||||
name);
|
name);
|
||||||
if (ret < 0 || str == NULL) {
|
if (ret < 0 || str == NULL) {
|
||||||
sqlite3_close(ctx->db);
|
sqlite3_close(ctx->db);
|
||||||
free(name);
|
free(name);
|
||||||
free(ctx->drop);
|
free(ctx->drop);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = exec_stmt(context, ctx->db, str, KRB5_CC_IO);
|
ret = exec_stmt(context, ctx->db, str, KRB5_CC_IO);
|
||||||
free(str);
|
free(str);
|
||||||
str = NULL;
|
str = NULL;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
sqlite3_close(ctx->db);
|
sqlite3_close(ctx->db);
|
||||||
free(name);
|
free(name);
|
||||||
free(ctx->drop);
|
free(ctx->drop);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = asprintf(&str, "SELECT name FROM %s", name);
|
ret = asprintf(&str, "SELECT name FROM %s", name);
|
||||||
if (ret < 0 || str == NULL) {
|
if (ret < 0 || str == NULL) {
|
||||||
exec_stmt(context, ctx->db, ctx->drop, 0);
|
exec_stmt(context, ctx->db, ctx->drop, 0);
|
||||||
sqlite3_close(ctx->db);
|
sqlite3_close(ctx->db);
|
||||||
free(name);
|
free(name);
|
||||||
free(ctx->drop);
|
free(ctx->drop);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return krb5_enomem(context);
|
return krb5_enomem(context);
|
||||||
}
|
}
|
||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
@@ -1249,10 +1350,13 @@ again:
|
|||||||
goto again;
|
goto again;
|
||||||
|
|
||||||
ret = _krb5_cc_allocate(context, &krb5_scc_ops, id);
|
ret = _krb5_cc_allocate(context, &krb5_scc_ops, id);
|
||||||
if (ret)
|
if (ret == 0)
|
||||||
return ret;
|
ret = scc_resolve(context, id, ctx->file, name);
|
||||||
|
if (ret) {
|
||||||
return scc_resolve(context, id, name);
|
free(*id);
|
||||||
|
*id = NULL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
@@ -1263,6 +1367,7 @@ scc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
|
|||||||
exec_stmt(context, ctx->db, ctx->drop, 0);
|
exec_stmt(context, ctx->db, ctx->drop, 0);
|
||||||
sqlite3_finalize(ctx->stmt);
|
sqlite3_finalize(ctx->stmt);
|
||||||
sqlite3_close(ctx->db);
|
sqlite3_close(ctx->db);
|
||||||
|
free(ctx->file);
|
||||||
free(ctx->drop);
|
free(ctx->drop);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1304,7 +1409,7 @@ scc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_bind_text(sfrom->ucachen, 1, sto->name, -1, NULL);
|
sqlite3_bind_text(sfrom->ucachen, 1, sto->sub, -1, NULL);
|
||||||
sqlite3_bind_int(sfrom->ucachen, 2, sfrom->cid);
|
sqlite3_bind_int(sfrom->ucachen, 2, sfrom->cid);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -1334,20 +1439,8 @@ rollback:
|
|||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
scc_get_default_name(krb5_context context, char **str)
|
scc_get_default_name(krb5_context context, char **str)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
*str = NULL;
|
*str = NULL;
|
||||||
|
return _krb5_expand_default_cc_name(context, KRB5_SCACHE_NAME, str);
|
||||||
ret = get_def_name(context, &name);
|
|
||||||
if (ret)
|
|
||||||
return _krb5_expand_default_cc_name(context, KRB5_SCACHE_NAME, str);
|
|
||||||
|
|
||||||
ret = asprintf(str, "SCC:%s", name);
|
|
||||||
free(name);
|
|
||||||
if (ret < 0 || *str == NULL)
|
|
||||||
return krb5_enomem(context);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
@@ -1364,7 +1457,7 @@ scc_set_default(krb5_context context, krb5_ccache id)
|
|||||||
return KRB5_CC_IO;
|
return KRB5_CC_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sqlite3_bind_text(s->umaster, 1, s->name, -1, NULL);
|
ret = sqlite3_bind_text(s->umaster, 1, s->sub, -1, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
sqlite3_reset(s->umaster);
|
sqlite3_reset(s->umaster);
|
||||||
krb5_set_error_message(context, KRB5_CC_IO,
|
krb5_set_error_message(context, KRB5_CC_IO,
|
||||||
|
@@ -669,6 +669,176 @@ test_cc_config(krb5_context context, const char *cc_type,
|
|||||||
krb5_free_principal(context, p);
|
krb5_free_principal(context, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
test_cccol(krb5_context context, const char *def_cccol, const char **what)
|
||||||
|
{
|
||||||
|
krb5_cc_cache_cursor cursor;
|
||||||
|
krb5_error_code ret;
|
||||||
|
krb5_principal p1, p2;
|
||||||
|
krb5_ccache id, id1, id2;
|
||||||
|
krb5_creds cred1, cred2;
|
||||||
|
size_t match1 = 0;
|
||||||
|
size_t match2 = 0;
|
||||||
|
|
||||||
|
memset(&cred1, 0, sizeof(cred1));
|
||||||
|
memset(&cred2, 0, sizeof(cred2));
|
||||||
|
|
||||||
|
*what = "krb5_parse_name";
|
||||||
|
ret = krb5_parse_name(context, "krbtgt/SU.SE@SU.SE", &cred1.server);
|
||||||
|
if (ret) return ret;
|
||||||
|
ret = krb5_parse_name(context, "lha@SU.SE", &cred1.client);
|
||||||
|
if (ret) return ret;
|
||||||
|
ret = krb5_parse_name(context, "krbtgt/H5L.SE@H5L.SE", &cred2.server);
|
||||||
|
if (ret) return ret;
|
||||||
|
ret = krb5_parse_name(context, "lha@H5L.SE", &cred2.client);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_set_default_name";
|
||||||
|
ret = krb5_cc_set_default_name(context, def_cccol);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_default";
|
||||||
|
ret = krb5_cc_default(context, &id1);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_initialize";
|
||||||
|
ret = krb5_cc_initialize(context, id1, cred1.client);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_store_cred";
|
||||||
|
ret = krb5_cc_store_cred(context, id1, &cred1);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_resolve";
|
||||||
|
ret = krb5_cc_resolve_for(context, NULL, def_cccol, cred2.client, &id2);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_initialize";
|
||||||
|
ret = krb5_cc_initialize(context, id2, cred2.client);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_store_cred";
|
||||||
|
ret = krb5_cc_store_cred(context, id2, &cred2);
|
||||||
|
if (ret) return ret;
|
||||||
|
|
||||||
|
krb5_cc_close(context, id1);
|
||||||
|
krb5_cc_close(context, id2);
|
||||||
|
id1 = id2 = NULL;
|
||||||
|
|
||||||
|
*what = "krb5_cc_default";
|
||||||
|
ret = krb5_cc_default(context, &id1);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_resolve";
|
||||||
|
ret = krb5_cc_resolve_for(context, NULL, def_cccol, cred2.client, &id2);
|
||||||
|
if (ret) return ret;
|
||||||
|
|
||||||
|
*what = "krb5_cc_get_principal";
|
||||||
|
ret = krb5_cc_get_principal(context, id1, &p1);
|
||||||
|
if (ret) return ret;
|
||||||
|
ret = krb5_cc_get_principal(context, id2, &p2);
|
||||||
|
if (ret) return ret;
|
||||||
|
|
||||||
|
if (!krb5_principal_compare(context, p1, cred1.client)) {
|
||||||
|
char *u1 = NULL;
|
||||||
|
char *u2 = NULL;
|
||||||
|
|
||||||
|
(void) krb5_unparse_name(context, p1, &u1);
|
||||||
|
(void) krb5_unparse_name(context, cred1.client, &u2);
|
||||||
|
warnx("Inconsistent principals for ccaches in %s: %s vs %s "
|
||||||
|
"(expected lha@SU.SE)", def_cccol, u1, u2);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if (!krb5_principal_compare(context, p2, cred2.client)) {
|
||||||
|
char *u1 = NULL;
|
||||||
|
char *u2 = NULL;
|
||||||
|
|
||||||
|
(void) krb5_unparse_name(context, p2, &u1);
|
||||||
|
(void) krb5_unparse_name(context, cred2.client, &u2);
|
||||||
|
warnx("Inconsistent principals for ccaches in %s: %s and %s "
|
||||||
|
"(expected lha@H5L.SE)", def_cccol, u1, u2);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
krb5_free_principal(context, p1);
|
||||||
|
krb5_free_principal(context, p2);
|
||||||
|
|
||||||
|
*what = "krb5_cc_cache_get_first";
|
||||||
|
ret = krb5_cc_cache_get_first(context, NULL, &cursor);
|
||||||
|
if (ret) return ret;
|
||||||
|
*what = "krb5_cc_cache_next";
|
||||||
|
while (krb5_cc_cache_next(context, cursor, &id) == 0) {
|
||||||
|
krb5_principal p;
|
||||||
|
|
||||||
|
*what = "krb5_cc_get_principal";
|
||||||
|
ret = krb5_cc_get_principal(context, id, &p);
|
||||||
|
if (ret) return ret;
|
||||||
|
if (krb5_principal_compare(context, p, cred1.client))
|
||||||
|
match1++;
|
||||||
|
else if (krb5_principal_compare(context, p, cred2.client))
|
||||||
|
match2++;
|
||||||
|
krb5_free_principal(context, p);
|
||||||
|
krb5_cc_close(context, id);
|
||||||
|
}
|
||||||
|
(void) krb5_cc_cache_end_seq_get(context, cursor);
|
||||||
|
|
||||||
|
*what = "cccol iteration inconsistency";
|
||||||
|
if (match1 != 1 || match2 != 1) return EINVAL;
|
||||||
|
|
||||||
|
krb5_cc_close(context, id1);
|
||||||
|
krb5_cc_close(context, id2);
|
||||||
|
|
||||||
|
krb5_free_cred_contents(context, &cred1);
|
||||||
|
krb5_free_cred_contents(context, &cred2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_cccol_dcache(krb5_context context)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
char template[sizeof("DIR:dcache-XXXXXX")];
|
||||||
|
char *s;
|
||||||
|
const char *what;
|
||||||
|
|
||||||
|
memcpy(template, "DIR:dcache-XXXXXX", sizeof("DIR:dcache-XXXXXX"));
|
||||||
|
if (mkdtemp(template + sizeof("DIR:") - 1) == NULL)
|
||||||
|
krb5_err(context, 1, errno, "mkdtemp");
|
||||||
|
|
||||||
|
ret = test_cccol(context, template, &what);
|
||||||
|
|
||||||
|
if (asprintf(&s, "%s/primary", template + sizeof("DIR:") - 1) > 0) {
|
||||||
|
(void) unlink(s);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
if (asprintf(&s, "%s/tkt", template + sizeof("DIR:") - 1) > 0) {
|
||||||
|
(void) unlink(s);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
if (asprintf(&s, "%s/tkt.lha@H5L.SE", template + sizeof("DIR:") - 1) > 0) {
|
||||||
|
(void) unlink(s);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
if (asprintf(&s, "%s/tkt.lha@SU.SE", template + sizeof("DIR:") - 1) > 0) {
|
||||||
|
(void) unlink(s);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
(void) rmdir(template + sizeof("DIR:") - 1); /* XXX Check that this succeeds */
|
||||||
|
if (ret)
|
||||||
|
krb5_err(context, 1, errno, "%s", what);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_cccol_scache(krb5_context context)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
char template[sizeof("SCC:scache-XXXXXX")];
|
||||||
|
const char *what;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
memcpy(template, "SCC:scache-XXXXXX", sizeof("SCC:scache-XXXXXX"));
|
||||||
|
if ((fd = mkstemp(template + sizeof("SCC:") - 1)) == -1)
|
||||||
|
krb5_err(context, 1, errno, "mkstemp");
|
||||||
|
(void) close(fd);
|
||||||
|
|
||||||
|
ret = test_cccol(context, template, &what);
|
||||||
|
(void) unlink(template + sizeof("SCC:") - 1);
|
||||||
|
if (ret)
|
||||||
|
krb5_err(context, 1, ret, "%s", what);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct getargs args[] = {
|
static struct getargs args[] = {
|
||||||
{"debug", 'd', arg_flag, &debug_flag,
|
{"debug", 'd', arg_flag, &debug_flag,
|
||||||
@@ -725,6 +895,10 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
test_default_name(context);
|
test_default_name(context);
|
||||||
test_mcache(context);
|
test_mcache(context);
|
||||||
|
/*
|
||||||
|
* XXX Make sure to set default ccache names for each cc type!
|
||||||
|
* Otherwise we clobber the user's ccaches.
|
||||||
|
*/
|
||||||
test_init_vs_destroy(context, krb5_cc_type_memory);
|
test_init_vs_destroy(context, krb5_cc_type_memory);
|
||||||
test_init_vs_destroy(context, krb5_cc_type_file);
|
test_init_vs_destroy(context, krb5_cc_type_file);
|
||||||
#if 0
|
#if 0
|
||||||
@@ -753,6 +927,14 @@ main(int argc, char **argv)
|
|||||||
test_cache_find(context, "lha@SU.SE", 1);
|
test_cache_find(context, "lha@SU.SE", 1);
|
||||||
test_cache_find(context, "hulabundulahotentot@SU.SE", 0);
|
test_cache_find(context, "hulabundulahotentot@SU.SE", 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX We should compose and krb5_cc_set_default_name() a default ccache
|
||||||
|
* for each cc type that we test with test_cache_iter(), and we should do
|
||||||
|
* that inside test_cache_iter().
|
||||||
|
*
|
||||||
|
* Alternatively we should remove test_cache_iter() in favor of
|
||||||
|
* test_cccol(), which is a much more complete test.
|
||||||
|
*/
|
||||||
test_cache_iter(context, krb5_cc_type_memory, 0);
|
test_cache_iter(context, krb5_cc_type_memory, 0);
|
||||||
test_cache_iter(context, krb5_cc_type_memory, 1);
|
test_cache_iter(context, krb5_cc_type_memory, 1);
|
||||||
test_cache_iter(context, krb5_cc_type_memory, 0);
|
test_cache_iter(context, krb5_cc_type_memory, 0);
|
||||||
@@ -860,6 +1042,22 @@ main(int argc, char **argv)
|
|||||||
test_cc_config(context, "MEMORY", "bar", 1000); /* 1000 because fast */
|
test_cc_config(context, "MEMORY", "bar", 1000); /* 1000 because fast */
|
||||||
test_cc_config(context, "FILE", "/tmp/foocc", 30); /* 30 because slower */
|
test_cc_config(context, "FILE", "/tmp/foocc", 30); /* 30 because slower */
|
||||||
|
|
||||||
|
test_cccol_dcache(context);
|
||||||
|
test_cccol_scache(context);
|
||||||
|
#ifdef HAVE_KEYUTILS_H
|
||||||
|
{
|
||||||
|
const char *what;
|
||||||
|
|
||||||
|
ret = test_cccol(context, "KEYRING:legacy:fooccol", &what);
|
||||||
|
if (ret)
|
||||||
|
krb5_err(context, 1, ret, "%s", what);
|
||||||
|
|
||||||
|
ret = test_cccol(context, "MEMORY:fooccol", &what);
|
||||||
|
if (ret)
|
||||||
|
krb5_err(context, 1, ret, "%s", what);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_KEYUTILS_H */
|
||||||
|
|
||||||
krb5_free_context(context);
|
krb5_free_context(context);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@@ -410,6 +410,7 @@ struct entry libdefaults_entries[] = {
|
|||||||
{ "default_client_keytab_name", krb5_config_string, NULL, 0 },
|
{ "default_client_keytab_name", krb5_config_string, NULL, 0 },
|
||||||
{ "default_cc_name", krb5_config_string, NULL, 0 },
|
{ "default_cc_name", krb5_config_string, NULL, 0 },
|
||||||
{ "default_cc_type", krb5_config_string, NULL, 0 },
|
{ "default_cc_type", krb5_config_string, NULL, 0 },
|
||||||
|
{ "default_cc_collection", krb5_config_string, NULL, 0 },
|
||||||
{ "default_etypes", krb5_config_string, NULL, 0 },
|
{ "default_etypes", krb5_config_string, NULL, 0 },
|
||||||
{ "default_etypes_des", krb5_config_string, NULL, 0 },
|
{ "default_etypes_des", krb5_config_string, NULL, 0 },
|
||||||
{ "default_keytab_modify_name", krb5_config_string, NULL, 0 },
|
{ "default_keytab_modify_name", krb5_config_string, NULL, 0 },
|
||||||
|
@@ -87,6 +87,8 @@ HEIMDAL_KRB5_2.0 {
|
|||||||
krb5_cc_copy_cache;
|
krb5_cc_copy_cache;
|
||||||
krb5_cc_copy_match_f;
|
krb5_cc_copy_match_f;
|
||||||
krb5_cc_default;
|
krb5_cc_default;
|
||||||
|
krb5_cc_default_for;
|
||||||
|
krb5_cc_default_sub;
|
||||||
krb5_cc_default_name;
|
krb5_cc_default_name;
|
||||||
krb5_cc_destroy;
|
krb5_cc_destroy;
|
||||||
krb5_cc_end_seq_get;
|
krb5_cc_end_seq_get;
|
||||||
@@ -111,6 +113,8 @@ HEIMDAL_KRB5_2.0 {
|
|||||||
krb5_cc_register;
|
krb5_cc_register;
|
||||||
krb5_cc_remove_cred;
|
krb5_cc_remove_cred;
|
||||||
krb5_cc_resolve;
|
krb5_cc_resolve;
|
||||||
|
krb5_cc_resolve_for;
|
||||||
|
krb5_cc_resolve_sub;
|
||||||
krb5_cc_retrieve_cred;
|
krb5_cc_retrieve_cred;
|
||||||
krb5_cc_set_config;
|
krb5_cc_set_config;
|
||||||
krb5_cc_set_default_name;
|
krb5_cc_set_default_name;
|
||||||
|
@@ -105,7 +105,7 @@ echo "initial ticket"
|
|||||||
${kinit} -c ${cache} --password-file=${objdir}/foopassword user@${R} || exitcode=1
|
${kinit} -c ${cache} --password-file=${objdir}/foopassword user@${R} || exitcode=1
|
||||||
|
|
||||||
echo "copy ccache with gss_store_cred"
|
echo "copy ccache with gss_store_cred"
|
||||||
${test_add_store_cred} ${cache} ${cache2} || exit 1
|
${test_add_store_cred} --default --overwrite --env ${cache} ${cache2} || exit 1
|
||||||
${klist} -c ${cache2} || exit 1
|
${klist} -c ${cache2} || exit 1
|
||||||
|
|
||||||
echo "keytab"
|
echo "keytab"
|
||||||
|
@@ -53,6 +53,7 @@ nokeytab="FILE:no-such-keytab"
|
|||||||
cache="FILE:krb5ccfile"
|
cache="FILE:krb5ccfile"
|
||||||
|
|
||||||
kinit="${TESTS_ENVIRONMENT} ../../kuser/kinit -c $cache ${afs_no_afslog}"
|
kinit="${TESTS_ENVIRONMENT} ../../kuser/kinit -c $cache ${afs_no_afslog}"
|
||||||
|
kdestroy="${TESTS_ENVIRONMENT} ../../kuser/kdestroy -c $cache"
|
||||||
klist="${TESTS_ENVIRONMENT} ../../kuser/heimtools klist -c $cache"
|
klist="${TESTS_ENVIRONMENT} ../../kuser/heimtools klist -c $cache"
|
||||||
kgetcred="${TESTS_ENVIRONMENT} ../../kuser/kgetcred -c $cache"
|
kgetcred="${TESTS_ENVIRONMENT} ../../kuser/kgetcred -c $cache"
|
||||||
kadmin="${TESTS_ENVIRONMENT} ../../kadmin/kadmin -l -r $R"
|
kadmin="${TESTS_ENVIRONMENT} ../../kadmin/kadmin -l -r $R"
|
||||||
@@ -121,17 +122,23 @@ trap "kill ${kdcpid}; echo signal killing kdc; exit 1;" EXIT
|
|||||||
testfailed="echo test failed; cat messages.log; exit 1"
|
testfailed="echo test failed; cat messages.log; exit 1"
|
||||||
|
|
||||||
echo "Test gss_acquire_cred_with_password" ; > messages.log
|
echo "Test gss_acquire_cred_with_password" ; > messages.log
|
||||||
|
${kdestroy}
|
||||||
${context} --client-name=user1@${R} --client-password=u1 --mech-type=krb5 \
|
${context} --client-name=user1@${R} --client-password=u1 --mech-type=krb5 \
|
||||||
host@lucid.test.h5l.se || { eval "$testfailed"; }
|
host@lucid.test.h5l.se || { eval "$testfailed"; }
|
||||||
|
${klist} && { eval "$testfailed"; }
|
||||||
# These must fail (because wrong password)
|
# These must fail (because wrong password)
|
||||||
${context} --client-name=user1@${R} --client-password=u2 --mech-type=krb5 \
|
${context} --client-name=user1@${R} --client-password=u2 --mech-type=krb5 \
|
||||||
host@lucid.test.h5l.se && { eval "$testfailed"; }
|
host@lucid.test.h5l.se && { eval "$testfailed"; }
|
||||||
|
${klist} && { eval "$testfailed"; }
|
||||||
${context} --client-name=user1@${R} --client-password=u2 --mech-type='' \
|
${context} --client-name=user1@${R} --client-password=u2 --mech-type='' \
|
||||||
--mech-types=krb5 host@lucid.test.h5l.se && { eval "$testfailed"; }
|
--mech-types=krb5 host@lucid.test.h5l.se && { eval "$testfailed"; }
|
||||||
|
${klist} && { eval "$testfailed"; }
|
||||||
${context} --client-name=user1@${R} --client-password=u2 --mech-type=krb5 \
|
${context} --client-name=user1@${R} --client-password=u2 --mech-type=krb5 \
|
||||||
--mech-types=krb5 host@lucid.test.h5l.se && { eval "$testfailed"; }
|
--mech-types=krb5 host@lucid.test.h5l.se && { eval "$testfailed"; }
|
||||||
|
${klist} && { eval "$testfailed"; }
|
||||||
${context} --client-name=user1@${R} --client-password=u2 --mech-type=all \
|
${context} --client-name=user1@${R} --client-password=u2 --mech-type=all \
|
||||||
--mech-types=krb5 host@lucid.test.h5l.se && { eval "$testfailed"; }
|
--mech-types=krb5 host@lucid.test.h5l.se && { eval "$testfailed"; }
|
||||||
|
${klist} && { eval "$testfailed"; }
|
||||||
${context} --client-name=user1@${R} --client-password=u2 \
|
${context} --client-name=user1@${R} --client-password=u2 \
|
||||||
--mech-type=krb5,ntlm --mech-types=krb5 host@lucid.test.h5l.se \
|
--mech-type=krb5,ntlm --mech-types=krb5 host@lucid.test.h5l.se \
|
||||||
&& { eval "$testfailed"; }
|
&& { eval "$testfailed"; }
|
||||||
|
@@ -4,6 +4,7 @@ noinst_DATA = \
|
|||||||
an2ln-db.txt \
|
an2ln-db.txt \
|
||||||
kdc-tester4.json \
|
kdc-tester4.json \
|
||||||
krb5.conf \
|
krb5.conf \
|
||||||
|
krb5-cccol.conf \
|
||||||
krb5-authz.conf \
|
krb5-authz.conf \
|
||||||
krb5-authz2.conf \
|
krb5-authz2.conf \
|
||||||
krb5-canon.conf \
|
krb5-canon.conf \
|
||||||
@@ -183,6 +184,13 @@ krb5.conf: krb5.conf.in Makefile
|
|||||||
-e 's,[@]kdc[@],,g' < $(srcdir)/krb5.conf.in > krb5.conf.tmp && \
|
-e 's,[@]kdc[@],,g' < $(srcdir)/krb5.conf.in > krb5.conf.tmp && \
|
||||||
mv krb5.conf.tmp krb5.conf
|
mv krb5.conf.tmp krb5.conf
|
||||||
|
|
||||||
|
krb5-cccol.conf: krb5-cccol.conf.in Makefile
|
||||||
|
$(do_subst) \
|
||||||
|
-e 's,[@]WEAK[@],false,g' \
|
||||||
|
-e 's,[@]dk[@],,g' \
|
||||||
|
-e 's,[@]kdc[@],,g' < $(srcdir)/krb5-cccol.conf.in > krb5-cccol.conf.tmp && \
|
||||||
|
mv krb5-cccol.conf.tmp krb5-cccol.conf
|
||||||
|
|
||||||
krb5-authz.conf: krb5-authz.conf.in Makefile
|
krb5-authz.conf: krb5-authz.conf.in Makefile
|
||||||
$(do_subst) < $(srcdir)/krb5-authz.conf.in > krb5-authz.conf.tmp && \
|
$(do_subst) < $(srcdir)/krb5-authz.conf.in > krb5-authz.conf.tmp && \
|
||||||
mv krb5-authz.conf.tmp krb5-authz.conf
|
mv krb5-authz.conf.tmp krb5-authz.conf
|
||||||
|
@@ -36,7 +36,7 @@ objdir="@objdir@"
|
|||||||
|
|
||||||
. ${env_setup}
|
. ${env_setup}
|
||||||
|
|
||||||
KRB5_CONFIG="${objdir}/krb5-cc.conf"
|
KRB5_CONFIG="${objdir}/krb5.conf"
|
||||||
export KRB5_CONFIG
|
export KRB5_CONFIG
|
||||||
|
|
||||||
unset KRB5CCNAME
|
unset KRB5CCNAME
|
||||||
@@ -68,8 +68,6 @@ rm -f mkey.file*
|
|||||||
|
|
||||||
> messages.log
|
> messages.log
|
||||||
|
|
||||||
cp "${objdir}/krb5.conf" "${objdir}/krb5-cc.conf"
|
|
||||||
|
|
||||||
echo Creating database
|
echo Creating database
|
||||||
${kadmin} \
|
${kadmin} \
|
||||||
init \
|
init \
|
||||||
@@ -95,12 +93,7 @@ trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT
|
|||||||
|
|
||||||
ec=0
|
ec=0
|
||||||
|
|
||||||
(cat ${objdir}/krb5.conf ; \
|
export KRB5CCNAME=SCC:${objdir}/sdb
|
||||||
echo '' ; \
|
|
||||||
echo '[libdefaults]' ; \
|
|
||||||
echo " default_cc_type = SCC" ; \
|
|
||||||
echo '' ) \
|
|
||||||
> ${objdir}/krb5-cc.conf
|
|
||||||
|
|
||||||
${kswitch} -p foo@${R} 2>/dev/null && ${kdestroy}
|
${kswitch} -p foo@${R} 2>/dev/null && ${kdestroy}
|
||||||
${kswitch} -p foo@${R} 2>/dev/null && ${kdestroy}
|
${kswitch} -p foo@${R} 2>/dev/null && ${kdestroy}
|
||||||
@@ -114,8 +107,8 @@ ${klist} -l | grep foo@ >/dev/null || { ec=1 ; eval "${testfailed}"; }
|
|||||||
${kdestroy}
|
${kdestroy}
|
||||||
|
|
||||||
echo "getting both tickets"; > messages.log
|
echo "getting both tickets"; > messages.log
|
||||||
${kinit} -c SCC:1 foo@${R} || { ec=1 ; eval "${testfailed}"; }
|
${kinit} -c ${KRB5CCNAME}:1 foo@${R} || { ec=1 ; eval "${testfailed}"; }
|
||||||
${kinit} -c SCC:2 bar@${R} || { ec=1 ; eval "${testfailed}"; }
|
${kinit} -c ${KRB5CCNAME}:2 bar@${R} || { ec=1 ; eval "${testfailed}"; }
|
||||||
echo "switch foo"
|
echo "switch foo"
|
||||||
${kswitch} -p foo@${R} || { ec=1 ; eval "${testfailed}"; }
|
${kswitch} -p foo@${R} || { ec=1 ; eval "${testfailed}"; }
|
||||||
${klist} | head -2 | grep foo@ >/dev/null || { ec=1 ; eval "${testfailed}"; }
|
${klist} | head -2 | grep foo@ >/dev/null || { ec=1 ; eval "${testfailed}"; }
|
||||||
@@ -140,6 +133,22 @@ ${klist} -l | grep foo@ >/dev/null && { ec=1 ; eval "${testfailed}"; }
|
|||||||
echo "check that bar is gone"
|
echo "check that bar is gone"
|
||||||
${klist} -l | grep bar@ >/dev/null && { ec=1 ; eval "${testfailed}"; }
|
${klist} -l | grep bar@ >/dev/null && { ec=1 ; eval "${testfailed}"; }
|
||||||
|
|
||||||
|
echo "getting tickets (DIR)"; > messages.log
|
||||||
|
KRB5_CONFIG="${objdir}/krb5-cccol.conf"
|
||||||
|
export KRB5_CONFIG
|
||||||
|
unset KRB5CCNAME
|
||||||
|
rm -rf ${objdir}/kt ${objdir}/cc_dir
|
||||||
|
mkdir ${objdir}/cc_dir || { ec=1 ; eval "${testfailed}"; }
|
||||||
|
${kinit} foo@${R} || { ec=1 ; eval "${testfailed}"; }
|
||||||
|
${kinit} --no-change-default bar@${R} || { ec=1 ; eval "${testfailed}"; }
|
||||||
|
primary=`cat ${objdir}/cc_dir/primary`
|
||||||
|
[ "x$primary" = xtkt.foo@${R} ] || { ec=1 ; eval "${testfailed}"; }
|
||||||
|
${klist} -l |
|
||||||
|
grep "foo@TEST.H5L.SE.*FILE:${objdir}/cc_dir/tkt.foo@TEST.H5L.SE" > /dev/null ||
|
||||||
|
{ ec=1 ; eval "${testfailed}"; }
|
||||||
|
${klist} -l |
|
||||||
|
grep "bar@TEST.H5L.SE.*FILE:${objdir}/cc_dir/tkt.bar@TEST.H5L.SE" > /dev/null ||
|
||||||
|
{ ec=1 ; eval "${testfailed}"; }
|
||||||
|
|
||||||
echo "killing kdc (${kdcpid})"
|
echo "killing kdc (${kdcpid})"
|
||||||
sh ${leaks_kill} kdc $kdcpid || exit 1
|
sh ${leaks_kill} kdc $kdcpid || exit 1
|
||||||
|
165
tests/kdc/krb5-cccol.conf.in
Normal file
165
tests/kdc/krb5-cccol.conf.in
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
[libdefaults]
|
||||||
|
default_realm = TEST.H5L.SE TEST2.H5L.SE
|
||||||
|
default_cc_collection = DIR:@objdir@/cc_dir/
|
||||||
|
no-addresses = TRUE
|
||||||
|
allow_weak_crypto = @WEAK@
|
||||||
|
dns_lookup_kdc = no
|
||||||
|
dns_lookup_realm = no
|
||||||
|
|
||||||
|
|
||||||
|
[appdefaults]
|
||||||
|
pkinit_anchors = FILE:@srcdir@/../../lib/hx509/data/ca.crt
|
||||||
|
reconnect-min = 2s
|
||||||
|
reconnect-backoff = 2s
|
||||||
|
reconnect-max = 10s
|
||||||
|
|
||||||
|
[realms]
|
||||||
|
TEST.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
admin_server = localhost:@admport@
|
||||||
|
kpasswd_server = localhost:@pwport@
|
||||||
|
}
|
||||||
|
SUB.TEST.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
TEST2.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
kpasswd_server = localhost:@pwport@
|
||||||
|
}
|
||||||
|
TEST3.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
TEST4.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
SOME-REALM5.FR = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
SOME-REALM6.US = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
SOME-REALM7.UK = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
SOME-REALM8.UK = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
TEST-HTTP.H5L.SE = {
|
||||||
|
kdc = http/localhost:@port@
|
||||||
|
}
|
||||||
|
H1.TEST.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
H2.TEST.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
H3.H2.TEST.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
H4.H2.TEST.H5L.SE = {
|
||||||
|
kdc = localhost:@port@
|
||||||
|
}
|
||||||
|
|
||||||
|
[domain_realm]
|
||||||
|
.test.h5l.se = TEST.H5L.SE
|
||||||
|
.sub.test.h5l.se = SUB.TEST.H5L.SE
|
||||||
|
.h1.test.h5l.se = H1.TEST.H5L.SE
|
||||||
|
.h2.test.h5l.se = H2.TEST.H5L.SE
|
||||||
|
.h3.h2.test.h5l.se = H3.H2.TEST.H5L.SE
|
||||||
|
.h4.h2.test.h5l.se = H4.H2.TEST.H5L.SE
|
||||||
|
.example.com = TEST2.H5L.SE
|
||||||
|
localhost = TEST.H5L.SE
|
||||||
|
.localdomain = TEST.H5L.SE
|
||||||
|
localdomain = TEST.H5L.SE
|
||||||
|
.localdomain6 = TEST.H5L.SE
|
||||||
|
localdomain6 = TEST.H5L.SE
|
||||||
|
|
||||||
|
|
||||||
|
[kdc]
|
||||||
|
enable-digest = true
|
||||||
|
allow-anonymous = true
|
||||||
|
digests_allowed = chap-md5,digest-md5,ntlm-v1,ntlm-v1-session,ntlm-v2,ms-chap-v2
|
||||||
|
strict-nametypes = true
|
||||||
|
|
||||||
|
enable-http = true
|
||||||
|
|
||||||
|
enable-pkinit = true
|
||||||
|
pkinit_identity = FILE:@srcdir@/../../lib/hx509/data/kdc.crt,@srcdir@/../../lib/hx509/data/kdc.key
|
||||||
|
pkinit_anchors = FILE:@srcdir@/../../lib/hx509/data/ca.crt
|
||||||
|
pkinit_pool = FILE:@srcdir@/../../lib/hx509/data/sub-ca.crt
|
||||||
|
# pkinit_revoke = CRL:@srcdir@/../../lib/hx509/data/crl1.crl
|
||||||
|
pkinit_mappings_file = @srcdir@/pki-mapping
|
||||||
|
pkinit_allow_proxy_certificate = true
|
||||||
|
|
||||||
|
database = {
|
||||||
|
label = {
|
||||||
|
dbname = @db_type@:@objdir@/current-db@kdc@
|
||||||
|
realm = TEST.H5L.SE
|
||||||
|
mkey_file = @objdir@/mkey.file
|
||||||
|
acl_file = @srcdir@/heimdal.acl
|
||||||
|
log_file = @objdir@/current@kdc@.log
|
||||||
|
}
|
||||||
|
label2 = {
|
||||||
|
dbname = @db_type@:@objdir@/current-db@kdc@
|
||||||
|
realm = TEST2.H5L.SE
|
||||||
|
mkey_file = @objdir@/mkey.file
|
||||||
|
acl_file = @srcdir@/heimdal.acl
|
||||||
|
log_file = @objdir@/current@kdc@.log
|
||||||
|
}
|
||||||
|
label3 = {
|
||||||
|
dbname = sqlite:@objdir@/current-db@kdc@.sqlite3
|
||||||
|
realm = SOME-REALM5.FR
|
||||||
|
mkey_file = @objdir@/mkey.file
|
||||||
|
acl_file = @srcdir@/heimdal.acl
|
||||||
|
log_file = @objdir@/current@kdc@.log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signal_socket = @objdir@/signal
|
||||||
|
iprop-stats = @objdir@/iprop-stats
|
||||||
|
iprop-acl = @srcdir@/iprop-acl
|
||||||
|
log-max-size = 40000
|
||||||
|
|
||||||
|
[hdb]
|
||||||
|
db-dir = @objdir@
|
||||||
|
|
||||||
|
[logging]
|
||||||
|
kdc = 0-/FILE:@objdir@/messages.log
|
||||||
|
krb5 = 0-/FILE:@objdir@/messages.log
|
||||||
|
default = 0-/FILE:@objdir@/messages.log
|
||||||
|
|
||||||
|
# If you are doing preformance measurements on OSX you want to change
|
||||||
|
# the kdc LOG line from = to - below to keep the FILE open and avoid
|
||||||
|
# open/write/close which is blocking (rdar:// ) on OSX.
|
||||||
|
# kdc = 0-/FILE=@objdir@/messages.log
|
||||||
|
|
||||||
|
[kadmin]
|
||||||
|
save-password = true
|
||||||
|
default_key_rules = {
|
||||||
|
*/des3-only@* = des3-cbc-sha1:pw-salt
|
||||||
|
*/aes-only@* = aes256-cts-hmac-sha1-96:pw-salt
|
||||||
|
}
|
||||||
|
@dk@
|
||||||
|
|
||||||
|
[capaths]
|
||||||
|
TEST.H5L.SE = {
|
||||||
|
TEST2.H5L.SE = .
|
||||||
|
SOME-REALM5.FR = 1
|
||||||
|
TEST3.H5L.SE = TEST2.H5L.SE
|
||||||
|
TEST4.H5L.SE = TEST2.H5L.SE
|
||||||
|
TEST4.H5L.SE = TEST3.H5L.SE
|
||||||
|
SOME-REALM6.US = SOME-REALM5.FR
|
||||||
|
SOME-REALM7.UK = SOME-REALM6.US
|
||||||
|
SOME-REALM7.UK = SOME-REALM5.FR
|
||||||
|
SOME-REALM8.UK = SOME-REALM6.US
|
||||||
|
}
|
||||||
|
H4.H2.TEST.H5L.SE = {
|
||||||
|
H1.TEST.H5L.SE = H3.H2.TEST.H5L.SE
|
||||||
|
H1.TEST.H5L.SE = H2.TEST.H5L.SE
|
||||||
|
H1.TEST.H5L.SE = TEST.H5L.SE
|
||||||
|
|
||||||
|
TEST.H5L.SE = H3.H2.TEST.H5L.SE
|
||||||
|
TEST.H5L.SE = H2.TEST.H5L.SE
|
||||||
|
|
||||||
|
H2.TEST.H5L.SE = H3.H2.TEST.H5L.SE
|
||||||
|
}
|
Reference in New Issue
Block a user