clean up and make work, require libheim-ipcs
This commit is contained in:
57
kcm/acl.c
57
kcm/acl.c
@@ -2,6 +2,8 @@
|
|||||||
* Copyright (c) 2005, PADL Software Pty Ltd.
|
* Copyright (c) 2005, PADL Software Pty Ltd.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||||
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@@ -32,8 +34,6 @@
|
|||||||
|
|
||||||
#include "kcm_locl.h"
|
#include "kcm_locl.h"
|
||||||
|
|
||||||
RCSID("$Id$");
|
|
||||||
|
|
||||||
krb5_error_code
|
krb5_error_code
|
||||||
kcm_access(krb5_context context,
|
kcm_access(krb5_context context,
|
||||||
kcm_client *client,
|
kcm_client *client,
|
||||||
@@ -58,6 +58,8 @@ kcm_access(krb5_context context,
|
|||||||
case KCM_OP_GET_INITIAL_TICKET:
|
case KCM_OP_GET_INITIAL_TICKET:
|
||||||
case KCM_OP_GET_TICKET:
|
case KCM_OP_GET_TICKET:
|
||||||
case KCM_OP_MOVE_CACHE:
|
case KCM_OP_MOVE_CACHE:
|
||||||
|
case KCM_OP_SET_DEFAULT_CACHE:
|
||||||
|
case KCM_OP_SET_KDC_OFFSET:
|
||||||
write_p = 1;
|
write_p = 1;
|
||||||
read_p = 0;
|
read_p = 0;
|
||||||
break;
|
break;
|
||||||
@@ -67,13 +69,18 @@ kcm_access(krb5_context context,
|
|||||||
case KCM_OP_GEN_NEW:
|
case KCM_OP_GEN_NEW:
|
||||||
case KCM_OP_RETRIEVE:
|
case KCM_OP_RETRIEVE:
|
||||||
case KCM_OP_GET_PRINCIPAL:
|
case KCM_OP_GET_PRINCIPAL:
|
||||||
case KCM_OP_GET_FIRST:
|
case KCM_OP_GET_CRED_UUID_LIST:
|
||||||
case KCM_OP_GET_NEXT:
|
case KCM_OP_GET_CRED_BY_UUID:
|
||||||
case KCM_OP_END_GET:
|
case KCM_OP_GET_CACHE_UUID_LIST:
|
||||||
case KCM_OP_MAX:
|
case KCM_OP_GET_CACHE_BY_UUID:
|
||||||
|
case KCM_OP_GET_DEFAULT_CACHE:
|
||||||
|
case KCM_OP_GET_KDC_OFFSET:
|
||||||
write_p = 0;
|
write_p = 0;
|
||||||
read_p = 1;
|
read_p = 1;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
ret = KRB5_FCC_PERM;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ccache->flags & KCM_FLAGS_OWNER_IS_SYSTEM) {
|
if (ccache->flags & KCM_FLAGS_OWNER_IS_SYSTEM) {
|
||||||
@@ -87,33 +94,45 @@ kcm_access(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Let root always read system caches */
|
/* Let root always read system caches */
|
||||||
if (client->uid == 0) {
|
if (CLIENT_IS_ROOT(client)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mask = 0;
|
/* start out with "other" mask */
|
||||||
|
mask = S_IROTH|S_IWOTH;
|
||||||
|
|
||||||
/* Root may do whatever they like */
|
/* root can do anything */
|
||||||
if (client->uid == ccache->uid || CLIENT_IS_ROOT(client)) {
|
if (CLIENT_IS_ROOT(client)) {
|
||||||
if (read_p)
|
if (read_p)
|
||||||
mask |= S_IRUSR;
|
mask |= S_IRUSR|S_IRGRP|S_IROTH;
|
||||||
if (write_p)
|
if (write_p)
|
||||||
mask |= S_IWUSR;
|
mask |= S_IWUSR|S_IWGRP|S_IWOTH;
|
||||||
} else if (client->gid == ccache->gid || CLIENT_IS_ROOT(client)) {
|
}
|
||||||
if (read_p)
|
/* same session same as owner */
|
||||||
mask |= S_IRGRP;
|
if (kcm_is_same_session(client, ccache->uid, ccache->session)) {
|
||||||
if (write_p)
|
|
||||||
mask |= S_IWGRP;
|
|
||||||
} else {
|
|
||||||
if (read_p)
|
if (read_p)
|
||||||
mask |= S_IROTH;
|
mask |= S_IROTH;
|
||||||
if (write_p)
|
if (write_p)
|
||||||
mask |= S_IWOTH;
|
mask |= S_IWOTH;
|
||||||
}
|
}
|
||||||
|
/* owner */
|
||||||
|
if (client->uid == ccache->uid) {
|
||||||
|
if (read_p)
|
||||||
|
mask |= S_IRUSR;
|
||||||
|
if (write_p)
|
||||||
|
mask |= S_IWUSR;
|
||||||
|
}
|
||||||
|
/* group */
|
||||||
|
if (client->gid == ccache->gid) {
|
||||||
|
if (read_p)
|
||||||
|
mask |= S_IRGRP;
|
||||||
|
if (write_p)
|
||||||
|
mask |= S_IWGRP;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ((ccache->mode & mask) == mask) ? 0 : KRB5_FCC_PERM;
|
ret = (ccache->mode & mask) ? 0 : KRB5_FCC_PERM;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@@ -32,8 +32,6 @@
|
|||||||
|
|
||||||
#include "kcm_locl.h"
|
#include "kcm_locl.h"
|
||||||
|
|
||||||
RCSID("$Id$");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a new ticket using a keytab/cached key and swap it into
|
* Get a new ticket using a keytab/cached key and swap it into
|
||||||
* an existing redentials cache
|
* an existing redentials cache
|
||||||
|
225
kcm/cache.c
225
kcm/cache.c
@@ -2,6 +2,8 @@
|
|||||||
* Copyright (c) 2005, PADL Software Pty Ltd.
|
* Copyright (c) 2005, PADL Software Pty Ltd.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||||
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@@ -32,10 +34,8 @@
|
|||||||
|
|
||||||
#include "kcm_locl.h"
|
#include "kcm_locl.h"
|
||||||
|
|
||||||
RCSID("$Id$");
|
HEIMDAL_MUTEX ccache_mutex = HEIMDAL_MUTEX_INITIALIZER;
|
||||||
|
kcm_ccache_data *ccache_head = NULL;
|
||||||
static HEIMDAL_MUTEX ccache_mutex = HEIMDAL_MUTEX_INITIALIZER;
|
|
||||||
static kcm_ccache_data *ccache_head = NULL;
|
|
||||||
static unsigned int ccache_nextid = 0;
|
static unsigned int ccache_nextid = 0;
|
||||||
|
|
||||||
char *kcm_ccache_nextid(pid_t pid, uid_t uid, gid_t gid)
|
char *kcm_ccache_nextid(pid_t pid, uid_t uid, gid_t gid)
|
||||||
@@ -52,10 +52,10 @@ char *kcm_ccache_nextid(pid_t pid, uid_t uid, gid_t gid)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
krb5_error_code
|
||||||
kcm_ccache_resolve_internal(krb5_context context,
|
kcm_ccache_resolve(krb5_context context,
|
||||||
const char *name,
|
const char *name,
|
||||||
kcm_ccache *ccache)
|
kcm_ccache *ccache)
|
||||||
{
|
{
|
||||||
kcm_ccache p;
|
kcm_ccache p;
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
@@ -85,6 +85,66 @@ kcm_ccache_resolve_internal(krb5_context context,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
kcm_ccache_resolve_by_uuid(krb5_context context,
|
||||||
|
kcmuuid_t uuid,
|
||||||
|
kcm_ccache *ccache)
|
||||||
|
{
|
||||||
|
kcm_ccache p;
|
||||||
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
*ccache = NULL;
|
||||||
|
|
||||||
|
ret = KRB5_FCC_NOFILE;
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_lock(&ccache_mutex);
|
||||||
|
|
||||||
|
for (p = ccache_head; p != NULL; p = p->next) {
|
||||||
|
if ((p->flags & KCM_FLAGS_VALID) == 0)
|
||||||
|
continue;
|
||||||
|
if (memcmp(p->uuid, uuid, sizeof(uuid)) == 0) {
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
kcm_retain_ccache(context, p);
|
||||||
|
*ccache = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_unlock(&ccache_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
kcm_ccache_get_uuids(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *sp)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
kcm_ccache p;
|
||||||
|
|
||||||
|
ret = KRB5_FCC_NOFILE;
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_lock(&ccache_mutex);
|
||||||
|
|
||||||
|
for (p = ccache_head; p != NULL; p = p->next) {
|
||||||
|
if ((p->flags & KCM_FLAGS_VALID) == 0)
|
||||||
|
continue;
|
||||||
|
ret = kcm_access(context, client, opcode, p);
|
||||||
|
if (ret) {
|
||||||
|
ret = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
krb5_storage_write(sp, p->uuid, sizeof(p->uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_unlock(&ccache_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
krb5_error_code kcm_debug_ccache(krb5_context context)
|
krb5_error_code kcm_debug_ccache(krb5_context context)
|
||||||
{
|
{
|
||||||
kcm_ccache p;
|
kcm_ccache p;
|
||||||
@@ -125,10 +185,48 @@ krb5_error_code kcm_debug_ccache(krb5_context context)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static void
|
||||||
kcm_ccache_destroy_internal(krb5_context context, const char *name)
|
kcm_free_ccache_data_internal(krb5_context context,
|
||||||
|
kcm_ccache_data *cache)
|
||||||
{
|
{
|
||||||
kcm_ccache *p;
|
KCM_ASSERT_VALID(cache);
|
||||||
|
|
||||||
|
if (cache->name != NULL) {
|
||||||
|
free(cache->name);
|
||||||
|
cache->name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache->flags & KCM_FLAGS_USE_KEYTAB) {
|
||||||
|
krb5_kt_close(context, cache->key.keytab);
|
||||||
|
cache->key.keytab = NULL;
|
||||||
|
} else if (cache->flags & KCM_FLAGS_USE_CACHED_KEY) {
|
||||||
|
krb5_free_keyblock_contents(context, &cache->key.keyblock);
|
||||||
|
krb5_keyblock_zero(&cache->key.keyblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->flags = 0;
|
||||||
|
cache->mode = 0;
|
||||||
|
cache->uid = -1;
|
||||||
|
cache->gid = -1;
|
||||||
|
cache->session = -1;
|
||||||
|
|
||||||
|
kcm_zero_ccache_data_internal(context, cache);
|
||||||
|
|
||||||
|
cache->tkt_life = 0;
|
||||||
|
cache->renew_life = 0;
|
||||||
|
|
||||||
|
cache->next = NULL;
|
||||||
|
cache->refcnt = 0;
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_unlock(&cache->mutex);
|
||||||
|
HEIMDAL_MUTEX_destroy(&cache->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
kcm_ccache_destroy(krb5_context context, const char *name)
|
||||||
|
{
|
||||||
|
kcm_ccache *p, ccache;
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
|
||||||
ret = KRB5_FCC_NOFILE;
|
ret = KRB5_FCC_NOFILE;
|
||||||
@@ -142,11 +240,18 @@ kcm_ccache_destroy_internal(krb5_context context, const char *name)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
kcm_release_ccache(context, p);
|
if ((*p)->refcnt != 1) {
|
||||||
|
ret = EAGAIN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccache = *p;
|
||||||
|
*p = (*p)->next;
|
||||||
|
kcm_free_ccache_data_internal(context, ccache);
|
||||||
|
free(ccache);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
HEIMDAL_MUTEX_unlock(&ccache_mutex);
|
HEIMDAL_MUTEX_unlock(&ccache_mutex);
|
||||||
@@ -195,6 +300,8 @@ kcm_ccache_alloc(krb5_context context,
|
|||||||
new_slot = 1;
|
new_slot = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RAND_bytes(slot->uuid, sizeof(slot->uuid));
|
||||||
|
|
||||||
slot->name = strdup(name);
|
slot->name = strdup(name);
|
||||||
if (slot->name == NULL) {
|
if (slot->name == NULL) {
|
||||||
ret = KRB5_CC_NOMEM;
|
ret = KRB5_CC_NOMEM;
|
||||||
@@ -299,44 +406,6 @@ kcm_zero_ccache_data(krb5_context context,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
|
||||||
kcm_free_ccache_data_internal(krb5_context context,
|
|
||||||
kcm_ccache_data *cache)
|
|
||||||
{
|
|
||||||
KCM_ASSERT_VALID(cache);
|
|
||||||
|
|
||||||
if (cache->name != NULL) {
|
|
||||||
free(cache->name);
|
|
||||||
cache->name = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cache->flags & KCM_FLAGS_USE_KEYTAB) {
|
|
||||||
krb5_kt_close(context, cache->key.keytab);
|
|
||||||
cache->key.keytab = NULL;
|
|
||||||
} else if (cache->flags & KCM_FLAGS_USE_CACHED_KEY) {
|
|
||||||
krb5_free_keyblock_contents(context, &cache->key.keyblock);
|
|
||||||
krb5_keyblock_zero(&cache->key.keyblock);
|
|
||||||
}
|
|
||||||
|
|
||||||
cache->flags = 0;
|
|
||||||
cache->mode = 0;
|
|
||||||
cache->uid = -1;
|
|
||||||
cache->gid = -1;
|
|
||||||
|
|
||||||
kcm_zero_ccache_data_internal(context, cache);
|
|
||||||
|
|
||||||
cache->tkt_life = 0;
|
|
||||||
cache->renew_life = 0;
|
|
||||||
|
|
||||||
cache->next = NULL;
|
|
||||||
cache->refcnt = 0;
|
|
||||||
|
|
||||||
HEIMDAL_MUTEX_unlock(&cache->mutex);
|
|
||||||
HEIMDAL_MUTEX_destroy(&cache->mutex);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
krb5_error_code
|
krb5_error_code
|
||||||
kcm_retain_ccache(krb5_context context,
|
kcm_retain_ccache(krb5_context context,
|
||||||
kcm_ccache ccache)
|
kcm_ccache ccache)
|
||||||
@@ -351,26 +420,19 @@ kcm_retain_ccache(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code
|
krb5_error_code
|
||||||
kcm_release_ccache(krb5_context context,
|
kcm_release_ccache(krb5_context context, kcm_ccache c)
|
||||||
kcm_ccache *ccache)
|
|
||||||
{
|
{
|
||||||
kcm_ccache c = *ccache;
|
|
||||||
krb5_error_code ret = 0;
|
krb5_error_code ret = 0;
|
||||||
|
|
||||||
KCM_ASSERT_VALID(c);
|
KCM_ASSERT_VALID(c);
|
||||||
|
|
||||||
HEIMDAL_MUTEX_lock(&c->mutex);
|
HEIMDAL_MUTEX_lock(&c->mutex);
|
||||||
if (c->refcnt == 1) {
|
if (c->refcnt == 1) {
|
||||||
ret = kcm_free_ccache_data_internal(context, c);
|
|
||||||
if (ret == 0)
|
|
||||||
free(c);
|
|
||||||
} else {
|
} else {
|
||||||
c->refcnt--;
|
c->refcnt--;
|
||||||
HEIMDAL_MUTEX_unlock(&c->mutex);
|
HEIMDAL_MUTEX_unlock(&c->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
*ccache = NULL;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,29 +476,6 @@ kcm_ccache_new(krb5_context context,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code
|
|
||||||
kcm_ccache_resolve(krb5_context context,
|
|
||||||
const char *name,
|
|
||||||
kcm_ccache *ccache)
|
|
||||||
{
|
|
||||||
krb5_error_code ret;
|
|
||||||
|
|
||||||
ret = kcm_ccache_resolve_internal(context, name, ccache);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
krb5_error_code
|
|
||||||
kcm_ccache_destroy(krb5_context context,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
krb5_error_code ret;
|
|
||||||
|
|
||||||
ret = kcm_ccache_destroy_internal(context, name);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
krb5_error_code
|
krb5_error_code
|
||||||
kcm_ccache_destroy_if_empty(krb5_context context,
|
kcm_ccache_destroy_if_empty(krb5_context context,
|
||||||
kcm_ccache ccache)
|
kcm_ccache ccache)
|
||||||
@@ -446,7 +485,7 @@ kcm_ccache_destroy_if_empty(krb5_context context,
|
|||||||
KCM_ASSERT_VALID(ccache);
|
KCM_ASSERT_VALID(ccache);
|
||||||
|
|
||||||
if (ccache->creds == NULL) {
|
if (ccache->creds == NULL) {
|
||||||
ret = kcm_ccache_destroy_internal(context, ccache->name);
|
ret = kcm_ccache_destroy(context, ccache->name);
|
||||||
} else
|
} else
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
@@ -541,6 +580,8 @@ kcm_ccache_remove_cred_internal(krb5_context context,
|
|||||||
krb5_free_cred_contents(context, &cred->cred);
|
krb5_free_cred_contents(context, &cred->cred);
|
||||||
free(cred);
|
free(cred);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
if (*c == NULL)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,3 +653,21 @@ kcm_ccache_retrieve_cred(krb5_context context,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
kcm_ccache_first_name(kcm_client *client)
|
||||||
|
{
|
||||||
|
kcm_ccache p;
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_lock(&ccache_mutex);
|
||||||
|
|
||||||
|
for (p = ccache_head; p != NULL; p = p->next) {
|
||||||
|
if (kcm_is_same_session(client, p->uid, p->session))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p)
|
||||||
|
name = strdup(p->name);
|
||||||
|
HEIMDAL_MUTEX_unlock(&ccache_mutex);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
26
kcm/client.c
26
kcm/client.c
@@ -2,6 +2,8 @@
|
|||||||
* Copyright (c) 2005, PADL Software Pty Ltd.
|
* Copyright (c) 2005, PADL Software Pty Ltd.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||||
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@@ -33,8 +35,6 @@
|
|||||||
#include "kcm_locl.h"
|
#include "kcm_locl.h"
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
|
||||||
RCSID("$Id$");
|
|
||||||
|
|
||||||
krb5_error_code
|
krb5_error_code
|
||||||
kcm_ccache_resolve_client(krb5_context context,
|
kcm_ccache_resolve_client(krb5_context context,
|
||||||
kcm_client *client,
|
kcm_client *client,
|
||||||
@@ -54,7 +54,7 @@ kcm_ccache_resolve_client(krb5_context context,
|
|||||||
ret = kcm_access(context, client, opcode, *ccache);
|
ret = kcm_access(context, client, opcode, *ccache);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = KRB5_FCC_NOFILE; /* don't disclose */
|
ret = KRB5_FCC_NOFILE; /* don't disclose */
|
||||||
kcm_release_ccache(context, ccache);
|
kcm_release_ccache(context, *ccache);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -76,19 +76,12 @@ kcm_ccache_destroy_client(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = kcm_access(context, client, KCM_OP_DESTROY, ccache);
|
ret = kcm_access(context, client, KCM_OP_DESTROY, ccache);
|
||||||
if (ret) {
|
kcm_cleanup_events(context, ccache);
|
||||||
kcm_release_ccache(context, &ccache);
|
kcm_release_ccache(context, ccache);
|
||||||
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
ret = kcm_ccache_destroy(context, ccache->name);
|
return kcm_ccache_destroy(context, name);
|
||||||
if (ret == 0) {
|
|
||||||
/* don't leave any events dangling */
|
|
||||||
kcm_cleanup_events(context, ccache);
|
|
||||||
}
|
|
||||||
|
|
||||||
kcm_release_ccache(context, &ccache);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code
|
krb5_error_code
|
||||||
@@ -142,12 +135,13 @@ kcm_ccache_new_client(krb5_context context,
|
|||||||
/* bind to current client */
|
/* bind to current client */
|
||||||
ccache->uid = client->uid;
|
ccache->uid = client->uid;
|
||||||
ccache->gid = client->gid;
|
ccache->gid = client->gid;
|
||||||
|
ccache->session = client->session;
|
||||||
} else {
|
} else {
|
||||||
ret = kcm_zero_ccache_data(context, ccache);
|
ret = kcm_zero_ccache_data(context, ccache);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kcm_log(1, "Failed to empty cache %s: %s",
|
kcm_log(1, "Failed to empty cache %s: %s",
|
||||||
name, krb5_get_err_text(context, ret));
|
name, krb5_get_err_text(context, ret));
|
||||||
kcm_release_ccache(context, &ccache);
|
kcm_release_ccache(context, ccache);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
kcm_cleanup_events(context, ccache);
|
kcm_cleanup_events(context, ccache);
|
||||||
@@ -155,7 +149,7 @@ kcm_ccache_new_client(krb5_context context,
|
|||||||
|
|
||||||
ret = kcm_access(context, client, KCM_OP_INITIALIZE, ccache);
|
ret = kcm_access(context, client, KCM_OP_INITIALIZE, ccache);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kcm_release_ccache(context, &ccache);
|
kcm_release_ccache(context, ccache);
|
||||||
kcm_ccache_destroy(context, name);
|
kcm_ccache_destroy(context, name);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
18
kcm/config.c
18
kcm/config.c
@@ -2,6 +2,8 @@
|
|||||||
* Copyright (c) 2005, PADL Software Pty Ltd.
|
* Copyright (c) 2005, PADL Software Pty Ltd.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||||
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@@ -34,8 +36,6 @@
|
|||||||
#include <getarg.h>
|
#include <getarg.h>
|
||||||
#include <parse_bytes.h>
|
#include <parse_bytes.h>
|
||||||
|
|
||||||
RCSID("$Id$");
|
|
||||||
|
|
||||||
static const char *config_file; /* location of kcm config file */
|
static const char *config_file; /* location of kcm config file */
|
||||||
|
|
||||||
size_t max_request = 0; /* maximal size of a request */
|
size_t max_request = 0; /* maximal size of a request */
|
||||||
@@ -60,7 +60,7 @@ static const char *system_group = NULL;
|
|||||||
static const char *renew_life = NULL;
|
static const char *renew_life = NULL;
|
||||||
static const char *ticket_life = NULL;
|
static const char *ticket_life = NULL;
|
||||||
|
|
||||||
int disallow_getting_krbtgt = -1;
|
int disallow_getting_krbtgt = 0;
|
||||||
int name_constraints = -1;
|
int name_constraints = -1;
|
||||||
|
|
||||||
static int help_flag;
|
static int help_flag;
|
||||||
@@ -240,7 +240,7 @@ ccache_init_system(void)
|
|||||||
|
|
||||||
ret = krb5_parse_name(kcm_context, system_principal, &ccache->client);
|
ret = krb5_parse_name(kcm_context, system_principal, &ccache->client);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kcm_release_ccache(kcm_context, &ccache);
|
kcm_release_ccache(kcm_context, ccache);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ ccache_init_system(void)
|
|||||||
if (system_server != NULL) {
|
if (system_server != NULL) {
|
||||||
ret = krb5_parse_name(kcm_context, system_server, &ccache->server);
|
ret = krb5_parse_name(kcm_context, system_server, &ccache->server);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kcm_release_ccache(kcm_context, &ccache);
|
kcm_release_ccache(kcm_context, ccache);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ ccache_init_system(void)
|
|||||||
ret = krb5_kt_default(kcm_context, &ccache->key.keytab);
|
ret = krb5_kt_default(kcm_context, &ccache->key.keytab);
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kcm_release_ccache(kcm_context, &ccache);
|
kcm_release_ccache(kcm_context, ccache);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ ccache_init_system(void)
|
|||||||
if (renew_life != NULL) {
|
if (renew_life != NULL) {
|
||||||
ccache->renew_life = parse_time(renew_life, "s");
|
ccache->renew_life = parse_time(renew_life, "s");
|
||||||
if (ccache->renew_life < 0) {
|
if (ccache->renew_life < 0) {
|
||||||
kcm_release_ccache(kcm_context, &ccache);
|
kcm_release_ccache(kcm_context, ccache);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ ccache_init_system(void)
|
|||||||
if (ticket_life != NULL) {
|
if (ticket_life != NULL) {
|
||||||
ccache->tkt_life = parse_time(ticket_life, "s");
|
ccache->tkt_life = parse_time(ticket_life, "s");
|
||||||
if (ccache->tkt_life < 0) {
|
if (ccache->tkt_life < 0) {
|
||||||
kcm_release_ccache(kcm_context, &ccache);
|
kcm_release_ccache(kcm_context, ccache);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ ccache_init_system(void)
|
|||||||
/* enqueue default actions for credentials cache */
|
/* enqueue default actions for credentials cache */
|
||||||
ret = kcm_ccache_enqueue_default(kcm_context, ccache, NULL);
|
ret = kcm_ccache_enqueue_default(kcm_context, ccache, NULL);
|
||||||
|
|
||||||
kcm_release_ccache(kcm_context, &ccache); /* retained by event queue */
|
kcm_release_ccache(kcm_context, ccache); /* retained by event queue */
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
667
kcm/connect.c
667
kcm/connect.c
@@ -3,6 +3,8 @@
|
|||||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||||
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@@ -32,657 +34,62 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kcm_locl.h"
|
#include "kcm_locl.h"
|
||||||
|
#include <heim-ipc.h>
|
||||||
|
|
||||||
RCSID("$Id$");
|
static void
|
||||||
|
kcm_service(void *ctx, const heim_idata *req,
|
||||||
struct descr {
|
const heim_icred cred,
|
||||||
int s;
|
heim_ipc_complete complete,
|
||||||
int type;
|
heim_sipc_call cctx)
|
||||||
char *path;
|
{
|
||||||
unsigned char *buf;
|
|
||||||
size_t size;
|
|
||||||
size_t len;
|
|
||||||
time_t timeout;
|
|
||||||
struct sockaddr_storage __ss;
|
|
||||||
struct sockaddr *sa;
|
|
||||||
socklen_t sock_len;
|
|
||||||
kcm_client peercred;
|
kcm_client peercred;
|
||||||
};
|
krb5_error_code ret;
|
||||||
|
krb5_data request, rep;
|
||||||
|
unsigned char *buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
static void
|
krb5_data_zero(&rep);
|
||||||
init_descr(struct descr *d)
|
|
||||||
{
|
|
||||||
memset(d, 0, sizeof(*d));
|
|
||||||
d->sa = (struct sockaddr *)&d->__ss;
|
|
||||||
d->s = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
peercred.uid = heim_ipc_cred_get_uid(cred);
|
||||||
* re-initialize all `n' ->sa in `d'.
|
peercred.gid = heim_ipc_cred_get_gid(cred);
|
||||||
*/
|
peercred.pid = heim_ipc_cred_get_pid(cred);
|
||||||
|
peercred.session = heim_ipc_cred_get_session(cred);
|
||||||
|
|
||||||
static void
|
if (req->length < 4) {
|
||||||
reinit_descrs (struct descr *d, int n)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < n; ++i)
|
|
||||||
d[i].sa = (struct sockaddr *)&d[i].__ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update peer credentials from socket.
|
|
||||||
*
|
|
||||||
* SCM_CREDS can only be updated the first time there is read data to
|
|
||||||
* read from the filedescriptor, so if we read do it before this
|
|
||||||
* point, the cred data might not be is not there yet.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
update_client_creds(int s, kcm_client *peer)
|
|
||||||
{
|
|
||||||
#ifdef GETPEERUCRED
|
|
||||||
/* Solaris 10 */
|
|
||||||
{
|
|
||||||
ucred_t *peercred;
|
|
||||||
|
|
||||||
if (getpeerucred(s, &peercred) != 0) {
|
|
||||||
peer->uid = ucred_geteuid(peercred);
|
|
||||||
peer->gid = ucred_getegid(peercred);
|
|
||||||
peer->pid = 0;
|
|
||||||
ucred_free(peercred);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef GETPEEREID
|
|
||||||
/* FreeBSD, OpenBSD */
|
|
||||||
{
|
|
||||||
uid_t uid;
|
|
||||||
gid_t gid;
|
|
||||||
|
|
||||||
if (getpeereid(s, &uid, &gid) == 0) {
|
|
||||||
peer->uid = uid;
|
|
||||||
peer->gid = gid;
|
|
||||||
peer->pid = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef SO_PEERCRED
|
|
||||||
/* Linux */
|
|
||||||
{
|
|
||||||
struct ucred pc;
|
|
||||||
socklen_t pclen = sizeof(pc);
|
|
||||||
|
|
||||||
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) {
|
|
||||||
peer->uid = pc.uid;
|
|
||||||
peer->gid = pc.gid;
|
|
||||||
peer->pid = pc.pid;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
|
|
||||||
{
|
|
||||||
struct xucred peercred;
|
|
||||||
socklen_t peercredlen = sizeof(peercred);
|
|
||||||
|
|
||||||
if (getsockopt(s, LOCAL_PEERCRED, 1,
|
|
||||||
(void *)&peercred, &peercredlen) == 0
|
|
||||||
&& peercred.cr_version == XUCRED_VERSION)
|
|
||||||
{
|
|
||||||
peer->uid = peercred.cr_uid;
|
|
||||||
peer->gid = peercred.cr_gid;
|
|
||||||
peer->pid = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
|
|
||||||
/* NetBSD */
|
|
||||||
if (peer->uid == -1) {
|
|
||||||
struct msghdr msg;
|
|
||||||
socklen_t crmsgsize;
|
|
||||||
void *crmsg;
|
|
||||||
struct cmsghdr *cmp;
|
|
||||||
struct sockcred *sc;
|
|
||||||
|
|
||||||
memset(&msg, 0, sizeof(msg));
|
|
||||||
crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
|
|
||||||
if (crmsgsize == 0)
|
|
||||||
return 1 ;
|
|
||||||
|
|
||||||
crmsg = malloc(crmsgsize);
|
|
||||||
if (crmsg == NULL)
|
|
||||||
goto failed_scm_creds;
|
|
||||||
|
|
||||||
memset(crmsg, 0, crmsgsize);
|
|
||||||
|
|
||||||
msg.msg_control = crmsg;
|
|
||||||
msg.msg_controllen = crmsgsize;
|
|
||||||
|
|
||||||
if (recvmsg(s, &msg, 0) < 0) {
|
|
||||||
free(crmsg);
|
|
||||||
goto failed_scm_creds;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
|
|
||||||
free(crmsg);
|
|
||||||
goto failed_scm_creds;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmp = CMSG_FIRSTHDR(&msg);
|
|
||||||
if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
|
|
||||||
free(crmsg);
|
|
||||||
goto failed_scm_creds;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
|
|
||||||
|
|
||||||
peer->uid = sc->sc_euid;
|
|
||||||
peer->gid = sc->sc_egid;
|
|
||||||
peer->pid = 0;
|
|
||||||
|
|
||||||
free(crmsg);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
/* we already got the cred, just return it */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
failed_scm_creds:
|
|
||||||
#endif
|
|
||||||
krb5_warn(kcm_context, errno, "failed to determine peer identity");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create the socket (family, type, port) in `d'
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_socket(struct descr *d)
|
|
||||||
{
|
|
||||||
struct sockaddr_un un;
|
|
||||||
struct sockaddr *sa = (struct sockaddr *)&un;
|
|
||||||
krb5_socklen_t sa_size = sizeof(un);
|
|
||||||
|
|
||||||
init_descr (d);
|
|
||||||
|
|
||||||
un.sun_family = AF_UNIX;
|
|
||||||
|
|
||||||
if (socket_path != NULL)
|
|
||||||
d->path = socket_path;
|
|
||||||
else
|
|
||||||
d->path = _PATH_KCM_SOCKET;
|
|
||||||
|
|
||||||
strlcpy(un.sun_path, d->path, sizeof(un.sun_path));
|
|
||||||
|
|
||||||
d->s = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (d->s < 0){
|
|
||||||
krb5_warn(kcm_context, errno, "socket(%d, %d, 0)", AF_UNIX, SOCK_STREAM);
|
|
||||||
d->s = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR)
|
|
||||||
{
|
|
||||||
int one = 1;
|
|
||||||
setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef LOCAL_CREDS
|
|
||||||
{
|
|
||||||
int one = 1;
|
|
||||||
setsockopt(d->s, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
d->type = SOCK_STREAM;
|
|
||||||
|
|
||||||
unlink(d->path);
|
|
||||||
|
|
||||||
if (bind(d->s, sa, sa_size) < 0) {
|
|
||||||
krb5_warn(kcm_context, errno, "bind %s", un.sun_path);
|
|
||||||
close(d->s);
|
|
||||||
d->s = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(d->s, SOMAXCONN) < 0) {
|
|
||||||
krb5_warn(kcm_context, errno, "listen %s", un.sun_path);
|
|
||||||
close(d->s);
|
|
||||||
d->s = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
chmod(d->path, 0777);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate descriptors for all the sockets that we should listen on
|
|
||||||
* and return the number of them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
init_sockets(struct descr **desc)
|
|
||||||
{
|
|
||||||
struct descr *d;
|
|
||||||
size_t num = 0;
|
|
||||||
|
|
||||||
d = (struct descr *)malloc(sizeof(*d));
|
|
||||||
if (d == NULL) {
|
|
||||||
krb5_errx(kcm_context, 1, "malloc failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
init_socket(d);
|
|
||||||
if (d->s != -1) {
|
|
||||||
kcm_log(5, "listening on domain socket %s", d->path);
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
reinit_descrs (d, num);
|
|
||||||
*desc = d;
|
|
||||||
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* handle the request in `buf, len', from `addr' (or `from' as a string),
|
|
||||||
* sending a reply in `reply'.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
process_request(unsigned char *buf,
|
|
||||||
size_t len,
|
|
||||||
krb5_data *reply,
|
|
||||||
kcm_client *client)
|
|
||||||
{
|
|
||||||
krb5_data request;
|
|
||||||
|
|
||||||
if (len < 4) {
|
|
||||||
kcm_log(1, "malformed request from process %d (too short)",
|
kcm_log(1, "malformed request from process %d (too short)",
|
||||||
client->pid);
|
peercred.pid);
|
||||||
return -1;
|
(*complete)(cctx, EINVAL, NULL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf = req->data;
|
||||||
|
len = req->length;
|
||||||
|
|
||||||
if (buf[0] != KCM_PROTOCOL_VERSION_MAJOR ||
|
if (buf[0] != KCM_PROTOCOL_VERSION_MAJOR ||
|
||||||
buf[1] != KCM_PROTOCOL_VERSION_MINOR) {
|
buf[1] != KCM_PROTOCOL_VERSION_MINOR) {
|
||||||
kcm_log(1, "incorrect protocol version %d.%d from process %d",
|
kcm_log(1, "incorrect protocol version %d.%d from process %d",
|
||||||
buf[0], buf[1], client->pid);
|
buf[0], buf[1], peercred.pid);
|
||||||
return -1;
|
(*complete)(cctx, EINVAL, NULL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf += 2;
|
request.data = buf + 2;
|
||||||
len -= 2;
|
request.length = len - 2;
|
||||||
|
|
||||||
/* buf is now pointing at opcode */
|
/* buf is now pointing at opcode */
|
||||||
|
|
||||||
request.data = buf;
|
ret = kcm_dispatch(kcm_context, &peercred, &request, &rep);
|
||||||
request.length = len;
|
|
||||||
|
|
||||||
return kcm_dispatch(kcm_context, client, &request, reply);
|
(*complete)(cctx, ret, &rep);
|
||||||
|
krb5_data_free(&rep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle the request in `buf, len' to socket `d'
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
do_request(void *buf, size_t len, struct descr *d)
|
|
||||||
{
|
|
||||||
krb5_error_code ret;
|
|
||||||
krb5_data reply;
|
|
||||||
|
|
||||||
reply.length = 0;
|
|
||||||
|
|
||||||
ret = process_request(buf, len, &reply, &d->peercred);
|
|
||||||
if (reply.length != 0) {
|
|
||||||
unsigned char len[4];
|
|
||||||
struct msghdr msghdr;
|
|
||||||
struct iovec iov[2];
|
|
||||||
|
|
||||||
kcm_log(5, "sending %lu bytes to process %d",
|
|
||||||
(unsigned long)reply.length,
|
|
||||||
(int)d->peercred.pid);
|
|
||||||
|
|
||||||
memset (&msghdr, 0, sizeof(msghdr));
|
|
||||||
msghdr.msg_name = NULL;
|
|
||||||
msghdr.msg_namelen = 0;
|
|
||||||
msghdr.msg_iov = iov;
|
|
||||||
msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov);
|
|
||||||
#if 0
|
|
||||||
msghdr.msg_control = NULL;
|
|
||||||
msghdr.msg_controllen = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
len[0] = (reply.length >> 24) & 0xff;
|
|
||||||
len[1] = (reply.length >> 16) & 0xff;
|
|
||||||
len[2] = (reply.length >> 8) & 0xff;
|
|
||||||
len[3] = reply.length & 0xff;
|
|
||||||
|
|
||||||
iov[0].iov_base = (void*)len;
|
|
||||||
iov[0].iov_len = 4;
|
|
||||||
iov[1].iov_base = reply.data;
|
|
||||||
iov[1].iov_len = reply.length;
|
|
||||||
|
|
||||||
if (sendmsg (d->s, &msghdr, 0) < 0) {
|
|
||||||
kcm_log (0, "sendmsg(%d): %d %s", (int)d->peercred.pid,
|
|
||||||
errno, strerror(errno));
|
|
||||||
krb5_data_free(&reply);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
krb5_data_free(&reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
kcm_log(0, "Failed processing %lu byte request from process %d",
|
|
||||||
(unsigned long)len, d->peercred.pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clear_descr(struct descr *d)
|
|
||||||
{
|
|
||||||
if(d->buf)
|
|
||||||
memset(d->buf, 0, d->size);
|
|
||||||
d->len = 0;
|
|
||||||
if(d->s != -1)
|
|
||||||
close(d->s);
|
|
||||||
d->s = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STREAM_TIMEOUT 4
|
|
||||||
|
|
||||||
/*
|
|
||||||
* accept a new stream connection on `d[parent]' and store it in `d[child]'
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_new_stream (struct descr *d, int parent, int child)
|
|
||||||
{
|
|
||||||
int s;
|
|
||||||
|
|
||||||
if (child == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
d[child].peercred.pid = -1;
|
|
||||||
d[child].peercred.uid = -1;
|
|
||||||
d[child].peercred.gid = -1;
|
|
||||||
|
|
||||||
d[child].sock_len = sizeof(d[child].__ss);
|
|
||||||
s = accept(d[parent].s, d[child].sa, &d[child].sock_len);
|
|
||||||
if(s < 0) {
|
|
||||||
krb5_warn(kcm_context, errno, "accept");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s >= FD_SETSIZE) {
|
|
||||||
krb5_warnx(kcm_context, "socket FD too large");
|
|
||||||
close (s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d[child].s = s;
|
|
||||||
d[child].timeout = time(NULL) + STREAM_TIMEOUT;
|
|
||||||
d[child].type = SOCK_STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Grow `d' to handle at least `n'.
|
|
||||||
* Return != 0 if fails
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
grow_descr (struct descr *d, size_t n)
|
|
||||||
{
|
|
||||||
if (d->size - d->len < n) {
|
|
||||||
unsigned char *tmp;
|
|
||||||
size_t grow;
|
|
||||||
|
|
||||||
grow = max(1024, d->len + n);
|
|
||||||
if (d->size + grow > max_request) {
|
|
||||||
kcm_log(0, "Request exceeds max request size (%lu bytes).",
|
|
||||||
(unsigned long)d->size + grow);
|
|
||||||
clear_descr(d);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tmp = realloc (d->buf, d->size + grow);
|
|
||||||
if (tmp == NULL) {
|
|
||||||
kcm_log(0, "Failed to re-allocate %lu bytes.",
|
|
||||||
(unsigned long)d->size + grow);
|
|
||||||
clear_descr(d);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
d->size += grow;
|
|
||||||
d->buf = tmp;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle incoming data to the stream socket in `d[index]'
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_stream(struct descr *d, int index, int min_free)
|
|
||||||
{
|
|
||||||
unsigned char buf[1024];
|
|
||||||
int n;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (d[index].timeout == 0) {
|
|
||||||
add_new_stream (d, index, min_free);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (update_client_creds(d[index].s, &d[index].peercred)) {
|
|
||||||
krb5_warnx(kcm_context, "failed to update peer identity");
|
|
||||||
clear_descr(d + index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d[index].peercred.uid == -1) {
|
|
||||||
krb5_warnx(kcm_context, "failed to determine peer identity");
|
|
||||||
clear_descr (d + index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = recvfrom(d[index].s, buf, sizeof(buf), 0, NULL, NULL);
|
|
||||||
if (n < 0) {
|
|
||||||
krb5_warn(kcm_context, errno, "recvfrom");
|
|
||||||
return;
|
|
||||||
} else if (n == 0) {
|
|
||||||
krb5_warnx(kcm_context, "connection closed before end of data "
|
|
||||||
"after %lu bytes from process %ld",
|
|
||||||
(unsigned long) d[index].len, (long) d[index].peercred.pid);
|
|
||||||
clear_descr (d + index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (grow_descr (&d[index], n))
|
|
||||||
return;
|
|
||||||
memcpy(d[index].buf + d[index].len, buf, n);
|
|
||||||
d[index].len += n;
|
|
||||||
if (d[index].len > 4) {
|
|
||||||
krb5_storage *sp;
|
|
||||||
int32_t len;
|
|
||||||
|
|
||||||
sp = krb5_storage_from_mem(d[index].buf, d[index].len);
|
|
||||||
if (sp == NULL) {
|
|
||||||
kcm_log (0, "krb5_storage_from_mem failed");
|
|
||||||
ret = -1;
|
|
||||||
} else {
|
|
||||||
krb5_ret_int32(sp, &len);
|
|
||||||
krb5_storage_free(sp);
|
|
||||||
if (d[index].len - 4 >= len) {
|
|
||||||
memmove(d[index].buf, d[index].buf + 4, d[index].len - 4);
|
|
||||||
ret = 1;
|
|
||||||
} else
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ret < 0)
|
|
||||||
return;
|
|
||||||
else if (ret == 1) {
|
|
||||||
do_request(d[index].buf, d[index].len, &d[index]);
|
|
||||||
clear_descr(d + index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_DOOR_CREATE
|
|
||||||
|
|
||||||
static void
|
|
||||||
kcm_door_server(void *cookie, char *argp, size_t arg_size,
|
|
||||||
door_desc_t *dp, uint_t n_desc)
|
|
||||||
{
|
|
||||||
kcm_client peercred;
|
|
||||||
door_cred_t cred;
|
|
||||||
krb5_error_code ret;
|
|
||||||
krb5_data reply;
|
|
||||||
size_t length;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
reply.length = 0;
|
|
||||||
|
|
||||||
p = NULL;
|
|
||||||
length = 0;
|
|
||||||
|
|
||||||
if (door_cred(&cred) != 0) {
|
|
||||||
kcm_log(0, "door_cred failed with %s", strerror(errno));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
peercred.uid = cred.dc_euid;
|
|
||||||
peercred.gid = cred.dc_egid;
|
|
||||||
peercred.pid = cred.dc_pid;
|
|
||||||
|
|
||||||
ret = process_request((unsigned char*)argp, arg_size, &reply, &peercred);
|
|
||||||
if (reply.length != 0) {
|
|
||||||
p = alloca(reply.length); /* XXX don't use alloca */
|
|
||||||
if (p) {
|
|
||||||
memcpy(p, reply.data, reply.length);
|
|
||||||
length = reply.length;
|
|
||||||
}
|
|
||||||
krb5_data_free(&reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
door_return(p, length, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
kcm_setup_door(void)
|
|
||||||
{
|
|
||||||
int fd, ret;
|
|
||||||
char *path;
|
|
||||||
|
|
||||||
fd = door_create(kcm_door_server, NULL, 0);
|
|
||||||
if (fd < 0)
|
|
||||||
krb5_err(kcm_context, 1, errno, "Failed to create door");
|
|
||||||
|
|
||||||
if (door_path != NULL)
|
|
||||||
path = door_path;
|
|
||||||
else
|
|
||||||
path = _PATH_KCM_DOOR;
|
|
||||||
|
|
||||||
unlink(path);
|
|
||||||
ret = open(path, O_RDWR | O_CREAT, 0666);
|
|
||||||
if (ret < 0)
|
|
||||||
krb5_err(kcm_context, 1, errno, "Failed to create/open door");
|
|
||||||
close(ret);
|
|
||||||
|
|
||||||
ret = fattach(fd, path);
|
|
||||||
if (ret < 0)
|
|
||||||
krb5_err(kcm_context, 1, errno, "Failed to attach door");
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif /* HAVE_DOOR_CREATE */
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
kcm_loop(void)
|
kcm_loop(void)
|
||||||
{
|
{
|
||||||
struct descr *d;
|
heim_sipc mach;
|
||||||
unsigned int ndescr;
|
heim_sipc_launchd_mach_init("org.h5l.kcm", kcm_service, NULL, &mach);
|
||||||
|
|
||||||
#ifdef HAVE_DOOR_CREATE
|
heim_ipc_main();
|
||||||
kcm_setup_door();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ndescr = init_sockets(&d);
|
|
||||||
if (ndescr <= 0) {
|
|
||||||
krb5_warnx(kcm_context, "No sockets!");
|
|
||||||
#ifndef HAVE_DOOR_CREATE
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
while (exit_flag == 0){
|
|
||||||
struct timeval tmout;
|
|
||||||
fd_set fds;
|
|
||||||
int min_free = -1;
|
|
||||||
int max_fd = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
for(i = 0; i < ndescr; i++) {
|
|
||||||
if (d[i].s >= 0){
|
|
||||||
if(d[i].type == SOCK_STREAM &&
|
|
||||||
d[i].timeout && d[i].timeout < time(NULL)) {
|
|
||||||
kcm_log(1, "Stream connection from %d expired after %lu bytes",
|
|
||||||
d[i].peercred.pid, (unsigned long)d[i].len);
|
|
||||||
clear_descr(&d[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (max_fd < d[i].s)
|
|
||||||
max_fd = d[i].s;
|
|
||||||
if (max_fd >= FD_SETSIZE)
|
|
||||||
krb5_errx(kcm_context, 1, "fd too large");
|
|
||||||
FD_SET(d[i].s, &fds);
|
|
||||||
} else if (min_free < 0 || i < min_free)
|
|
||||||
min_free = i;
|
|
||||||
}
|
|
||||||
if (min_free == -1) {
|
|
||||||
struct descr *tmp;
|
|
||||||
tmp = realloc(d, (ndescr + 4) * sizeof(*d));
|
|
||||||
if(tmp == NULL)
|
|
||||||
krb5_warnx(kcm_context, "No memory");
|
|
||||||
else {
|
|
||||||
d = tmp;
|
|
||||||
reinit_descrs (d, ndescr);
|
|
||||||
memset(d + ndescr, 0, 4 * sizeof(*d));
|
|
||||||
for(i = ndescr; i < ndescr + 4; i++)
|
|
||||||
init_descr (&d[i]);
|
|
||||||
min_free = ndescr;
|
|
||||||
ndescr += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmout.tv_sec = STREAM_TIMEOUT;
|
|
||||||
tmout.tv_usec = 0;
|
|
||||||
switch (select(max_fd + 1, &fds, 0, 0, &tmout)){
|
|
||||||
case 0:
|
|
||||||
kcm_run_events(kcm_context, time(NULL));
|
|
||||||
break;
|
|
||||||
case -1:
|
|
||||||
if (errno != EINTR)
|
|
||||||
krb5_warn(kcm_context, errno, "select");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
for(i = 0; i < ndescr; i++) {
|
|
||||||
if(d[i].s >= 0 && FD_ISSET(d[i].s, &fds)) {
|
|
||||||
if (d[i].type == SOCK_STREAM)
|
|
||||||
handle_stream(d, i, min_free);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kcm_run_events(kcm_context, time(NULL));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d->path != NULL)
|
|
||||||
unlink(d->path);
|
|
||||||
free(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -161,7 +161,7 @@ kcm_remove_event_internal(krb5_context context,
|
|||||||
(*e)->fire_count = 0;
|
(*e)->fire_count = 0;
|
||||||
(*e)->expire_time = 0;
|
(*e)->expire_time = 0;
|
||||||
(*e)->backoff_time = 0;
|
(*e)->backoff_time = 0;
|
||||||
kcm_release_ccache(context, &(*e)->ccache);
|
kcm_release_ccache(context, (*e)->ccache);
|
||||||
(*e)->next = NULL;
|
(*e)->next = NULL;
|
||||||
free(*e);
|
free(*e);
|
||||||
|
|
||||||
|
@@ -33,9 +33,9 @@
|
|||||||
#ifndef __HEADERS_H__
|
#ifndef __HEADERS_H__
|
||||||
#define __HEADERS_H__
|
#define __HEADERS_H__
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -85,7 +85,9 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <krb5.h>
|
#include <krb5.h>
|
||||||
#include <krb5_locl.h>
|
#include <heim_threads.h>
|
||||||
|
|
||||||
|
#include "crypto-headers.h"
|
||||||
|
|
||||||
#endif /* __HEADERS_H__ */
|
#endif /* __HEADERS_H__ */
|
||||||
|
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
* Copyright (c) 2005, PADL Software Pty Ltd.
|
* Copyright (c) 2005, PADL Software Pty Ltd.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||||
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@@ -65,6 +67,15 @@
|
|||||||
struct kcm_ccache_data;
|
struct kcm_ccache_data;
|
||||||
struct kcm_creds;
|
struct kcm_creds;
|
||||||
|
|
||||||
|
struct kcm_default_cache {
|
||||||
|
uid_t uid;
|
||||||
|
pid_t session; /* really au_asid_t */
|
||||||
|
char *name;
|
||||||
|
struct kcm_default_cache *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct kcm_default_cache *default_caches;
|
||||||
|
|
||||||
struct kcm_creds {
|
struct kcm_creds {
|
||||||
kcmuuid_t uuid;
|
kcmuuid_t uuid;
|
||||||
krb5_creds cred;
|
krb5_creds cred;
|
||||||
@@ -73,16 +84,19 @@ struct kcm_creds {
|
|||||||
|
|
||||||
typedef struct kcm_ccache_data {
|
typedef struct kcm_ccache_data {
|
||||||
char *name;
|
char *name;
|
||||||
|
kcmuuid_t uuid;
|
||||||
unsigned refcnt;
|
unsigned refcnt;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint16_t mode;
|
uint16_t mode;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
|
pid_t session; /* really au_asid_t */
|
||||||
krb5_principal client; /* primary client principal */
|
krb5_principal client; /* primary client principal */
|
||||||
krb5_principal server; /* primary server principal (TGS if NULL) */
|
krb5_principal server; /* primary server principal (TGS if NULL) */
|
||||||
struct kcm_creds *creds;
|
struct kcm_creds *creds;
|
||||||
krb5_deltat tkt_life;
|
krb5_deltat tkt_life;
|
||||||
krb5_deltat renew_life;
|
krb5_deltat renew_life;
|
||||||
|
int32_t kdc_offset;
|
||||||
union {
|
union {
|
||||||
krb5_keytab keytab;
|
krb5_keytab keytab;
|
||||||
krb5_keyblock keyblock;
|
krb5_keyblock keyblock;
|
||||||
@@ -132,6 +146,7 @@ typedef struct kcm_client {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
|
pid_t session;
|
||||||
} kcm_client;
|
} kcm_client;
|
||||||
|
|
||||||
#define CLIENT_IS_ROOT(client) ((client)->uid == 0)
|
#define CLIENT_IS_ROOT(client) ((client)->uid == 0)
|
||||||
|
831
kcm/protocol.c
831
kcm/protocol.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user