#include "kcm_locl.h"
#include <pwd.h>
krb5_error_code
kcm_ccache_resolve_client(krb5_context context,
kcm_client *client,
kcm_operation opcode,
const char *name,
kcm_ccache *ccache)
{
krb5_error_code ret;
ret = kcm_ccache_resolve_by_name(context, name, ccache);
if (ret) {
kcm_log(1, "Failed to resolve cache %s", name);
return ret;
}
ret = kcm_access(context, client, opcode, *ccache);
if (ret) {
ret = KRB5_FCC_NOFILE;
kcm_release_ccache(context, *ccache);
}
return ret;
}
krb5_error_code
kcm_ccache_destroy_client(krb5_context context,
kcm_client *client,
const char *name)
{
krb5_error_code ret;
kcm_ccache ccache;
ret = kcm_ccache_resolve_by_name(context, name, &ccache);
if (ret) {
kcm_log(1, "Failed to resolve cache %s", name);
return ret;
}
ret = kcm_access(context, client, KCM_OP_DESTROY, ccache);
kcm_release_ccache(context, ccache);
if (ret)
return ret;
return kcm_ccache_destroy(context, name);
}
krb5_error_code
kcm_ccache_new_client(krb5_context context,
kcm_client *client,
const char *name,
kcm_ccache *ccache_p)
{
krb5_error_code ret;
kcm_ccache ccache;
if (name_constraints != 0) {
char prefix[64];
size_t prefix_len;
int bad = 1;
snprintf(prefix, sizeof(prefix), "%ld:", (long)client->uid);
prefix_len = strlen(prefix);
if (strncmp(name, prefix, prefix_len) == 0)
bad = 0;
else {
prefix[prefix_len - 1] = '\0';
if (strcmp(name, prefix) == 0)
bad = 0;
}
if (bad && !CLIENT_IS_ROOT(client))
return KRB5_CC_BADNAME;
}
ret = kcm_ccache_resolve_by_name(context, name, &ccache);
if (ret == 0) {
if ((ccache->uid != client->uid) && !CLIENT_IS_ROOT(client))
return KRB5_FCC_PERM;
} else if (ret != KRB5_FCC_NOFILE && !(CLIENT_IS_ROOT(client) && ret == KRB5_FCC_PERM)) {
return ret;
}
if (ret == KRB5_FCC_NOFILE) {
ret = kcm_ccache_new(context, name, &ccache);
if (ret) {
kcm_log(1, "Failed to initialize cache %s", name);
return ret;
}
ccache->uid = client->uid;
ccache->session = client->session;
kcm_session_add(client->session);
} else {
ret = kcm_zero_ccache_data(context, ccache);
if (ret) {
kcm_log(1, "Failed to empty cache %s", name);
kcm_release_ccache(context, ccache);
return ret;
}
heim_ipc_event_cancel(ccache->renew_event);
heim_ipc_event_cancel(ccache->expire_event);
}
ret = kcm_access(context, client, KCM_OP_INITIALIZE, ccache);
if (ret) {
kcm_release_ccache(context, ccache);
kcm_ccache_destroy(context, name);
return ret;
}
if (CLIENT_IS_ROOT(client)) {
unsigned long uid;
int matches = sscanf(name,"%ld:",&uid);
if (matches == 0)
matches = sscanf(name,"%ld",&uid);
if (matches == 1) {
kcm_chown(context, client, ccache, uid);
}
}
*ccache_p = ccache;
return 0;
}