#include "k5-int.h"
#include "rc-int.h"
#include "k5-thread.h"
#include "../os/os-proto.h"
struct typelist {
const krb5_rc_ops *ops;
struct typelist *next;
};
static struct typelist none = { &k5_rc_none_ops, 0 };
static struct typelist file2 = { &k5_rc_file2_ops, &none };
static struct typelist dfl = { &k5_rc_dfl_ops, &file2 };
static struct typelist *typehead = &dfl;
krb5_error_code
k5_rc_default(krb5_context context, krb5_rcache *rc_out)
{
krb5_error_code ret;
const char *val;
char *profstr, *rcname;
*rc_out = NULL;
val = secure_getenv("KRB5RCACHENAME");
if (val != NULL)
return k5_rc_resolve(context, val, rc_out);
val = secure_getenv("KRB5RCACHETYPE");
if (val != NULL) {
if (asprintf(&rcname, "%s:", val) < 0)
return ENOMEM;
ret = k5_rc_resolve(context, rcname, rc_out);
free(rcname);
return ret;
}
if (profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
KRB5_CONF_DEFAULT_RCACHE_NAME, NULL, NULL,
&profstr) == 0 && profstr != NULL) {
ret = k5_expand_path_tokens(context, profstr, &rcname);
profile_release_string(profstr);
if (ret)
return ret;
ret = k5_rc_resolve(context, rcname, rc_out);
free(rcname);
return ret;
}
return k5_rc_resolve(context, "dfl:", rc_out);
}
krb5_error_code
k5_rc_resolve(krb5_context context, const char *name, krb5_rcache *rc_out)
{
krb5_error_code ret;
struct typelist *t;
const char *sep;
size_t len;
krb5_rcache rc = NULL;
*rc_out = NULL;
sep = strchr(name, ':');
if (sep == NULL)
return KRB5_RC_PARSE;
len = sep - name;
for (t = typehead; t != NULL; t = t->next) {
if (strncmp(t->ops->type, name, len) == 0 && t->ops->type[len] == '\0')
break;
}
if (t == NULL)
return KRB5_RC_TYPE_NOTFOUND;
rc = k5alloc(sizeof(*rc), &ret);
if (rc == NULL)
goto error;
rc->name = strdup(name);
if (rc->name == NULL) {
ret = ENOMEM;
goto error;
}
ret = t->ops->resolve(context, sep + 1, &rc->data);
if (ret)
goto error;
rc->ops = t->ops;
rc->magic = KV5M_RCACHE;
*rc_out = rc;
return 0;
error:
if (rc != NULL) {
free(rc->name);
free(rc);
}
return ret;
}
void
k5_rc_close(krb5_context context, krb5_rcache rc)
{
rc->ops->close(context, rc->data);
free(rc->name);
free(rc);
}
krb5_error_code
k5_rc_store(krb5_context context, krb5_rcache rc,
const krb5_enc_data *authenticator)
{
krb5_error_code ret;
krb5_data tag;
ret = k5_rc_tag_from_ciphertext(context, authenticator, &tag);
if (ret)
return ret;
return rc->ops->store(context, rc->data, &tag);
}
const char *
k5_rc_get_name(krb5_context context, krb5_rcache rc)
{
return rc->name;
}
krb5_error_code
k5_rc_tag_from_ciphertext(krb5_context context, const krb5_enc_data *enc,
krb5_data *tag_out)
{
krb5_error_code ret;
const krb5_data *cdata = &enc->ciphertext;
unsigned int len;
*tag_out = empty_data();
ret = krb5_c_crypto_length(context, enc->enctype,
KRB5_CRYPTO_TYPE_CHECKSUM, &len);
if (ret)
return ret;
if (cdata->length < len)
return EINVAL;
*tag_out = make_data(cdata->data + cdata->length - len, len);
return 0;
}
krb5_error_code krb5_rc_default(krb5_context, krb5_rcache *);
krb5_error_code KRB5_CALLCONV krb5_rc_destroy(krb5_context, krb5_rcache);
krb5_error_code KRB5_CALLCONV krb5_rc_get_lifespan(krb5_context, krb5_rcache,
krb5_deltat *);
krb5_error_code KRB5_CALLCONV krb5_rc_initialize(krb5_context, krb5_rcache,
krb5_deltat);
krb5_error_code
krb5_rc_default(krb5_context context, krb5_rcache *rc)
{
return EINVAL;
}
krb5_error_code KRB5_CALLCONV
krb5_rc_destroy(krb5_context context, krb5_rcache rc)
{
return EINVAL;
}
krb5_error_code KRB5_CALLCONV
krb5_rc_get_lifespan(krb5_context context, krb5_rcache rc, krb5_deltat *span)
{
return EINVAL;
}
krb5_error_code KRB5_CALLCONV
krb5_rc_initialize(krb5_context context, krb5_rcache rc, krb5_deltat span)
{
return EINVAL;
}