wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hdb_locl.h"
|
||||
|
||||
RCSID("$Id: db.c,v 1.36 2006/09/12 18:12:37 lha Exp $");
|
||||
|
||||
#if HAVE_DB1
|
||||
|
||||
#if defined(HAVE_DB_185_H)
|
||||
#include <db_185.h>
|
||||
#elif defined(HAVE_DB_H)
|
||||
#include <db.h>
|
||||
#endif
|
||||
|
||||
static krb5_error_code
|
||||
DB_close(krb5_context context, HDB *db)
|
||||
{
|
||||
DB *d = (DB*)db->hdb_db;
|
||||
(*d->close)(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB_destroy(krb5_context context, HDB *db)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
ret = hdb_clear_master_key (context, db);
|
||||
free(db->hdb_name);
|
||||
free(db);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB_lock(krb5_context context, HDB *db, int operation)
|
||||
{
|
||||
DB *d = (DB*)db->hdb_db;
|
||||
int fd = (*d->fd)(d);
|
||||
if(fd < 0)
|
||||
return HDB_ERR_CANT_LOCK_DB;
|
||||
return hdb_lock(fd, operation);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB_unlock(krb5_context context, HDB *db)
|
||||
{
|
||||
DB *d = (DB*)db->hdb_db;
|
||||
int fd = (*d->fd)(d);
|
||||
if(fd < 0)
|
||||
return HDB_ERR_CANT_LOCK_DB;
|
||||
return hdb_unlock(fd);
|
||||
}
|
||||
|
||||
|
||||
static krb5_error_code
|
||||
DB_seq(krb5_context context, HDB *db,
|
||||
unsigned flags, hdb_entry_ex *entry, int flag)
|
||||
{
|
||||
DB *d = (DB*)db->hdb_db;
|
||||
DBT key, value;
|
||||
krb5_data key_data, data;
|
||||
int code;
|
||||
|
||||
code = db->hdb_lock(context, db, HDB_RLOCK);
|
||||
if(code == -1)
|
||||
return HDB_ERR_DB_INUSE;
|
||||
code = (*d->seq)(d, &key, &value, flag);
|
||||
db->hdb_unlock(context, db); /* XXX check value */
|
||||
if(code == -1)
|
||||
return errno;
|
||||
if(code == 1)
|
||||
return HDB_ERR_NOENTRY;
|
||||
|
||||
key_data.data = key.data;
|
||||
key_data.length = key.size;
|
||||
data.data = value.data;
|
||||
data.length = value.size;
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
if (hdb_value2entry(context, &data, &entry->entry))
|
||||
return DB_seq(context, db, flags, entry, R_NEXT);
|
||||
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
|
||||
code = hdb_unseal_keys (context, db, &entry->entry);
|
||||
if (code)
|
||||
hdb_free_entry (context, entry);
|
||||
}
|
||||
if (code == 0 && entry->entry.principal == NULL) {
|
||||
entry->entry.principal = malloc(sizeof(*entry->entry.principal));
|
||||
if (entry->entry.principal == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
code = ENOMEM;
|
||||
hdb_free_entry (context, entry);
|
||||
} else {
|
||||
hdb_key2principal(context, &key_data, entry->entry.principal);
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
static krb5_error_code
|
||||
DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
|
||||
{
|
||||
return DB_seq(context, db, flags, entry, R_FIRST);
|
||||
}
|
||||
|
||||
|
||||
static krb5_error_code
|
||||
DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
|
||||
{
|
||||
return DB_seq(context, db, flags, entry, R_NEXT);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB_rename(krb5_context context, HDB *db, const char *new_name)
|
||||
{
|
||||
int ret;
|
||||
char *old, *new;
|
||||
|
||||
asprintf(&old, "%s.db", db->hdb_name);
|
||||
asprintf(&new, "%s.db", new_name);
|
||||
ret = rename(old, new);
|
||||
free(old);
|
||||
free(new);
|
||||
if(ret)
|
||||
return errno;
|
||||
|
||||
free(db->hdb_name);
|
||||
db->hdb_name = strdup(new_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
|
||||
{
|
||||
DB *d = (DB*)db->hdb_db;
|
||||
DBT k, v;
|
||||
int code;
|
||||
|
||||
k.data = key.data;
|
||||
k.size = key.length;
|
||||
code = db->hdb_lock(context, db, HDB_RLOCK);
|
||||
if(code)
|
||||
return code;
|
||||
code = (*d->get)(d, &k, &v, 0);
|
||||
db->hdb_unlock(context, db);
|
||||
if(code < 0)
|
||||
return errno;
|
||||
if(code == 1)
|
||||
return HDB_ERR_NOENTRY;
|
||||
|
||||
krb5_data_copy(reply, v.data, v.size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB__put(krb5_context context, HDB *db, int replace,
|
||||
krb5_data key, krb5_data value)
|
||||
{
|
||||
DB *d = (DB*)db->hdb_db;
|
||||
DBT k, v;
|
||||
int code;
|
||||
|
||||
k.data = key.data;
|
||||
k.size = key.length;
|
||||
v.data = value.data;
|
||||
v.size = value.length;
|
||||
code = db->hdb_lock(context, db, HDB_WLOCK);
|
||||
if(code)
|
||||
return code;
|
||||
code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
|
||||
db->hdb_unlock(context, db);
|
||||
if(code < 0)
|
||||
return errno;
|
||||
if(code == 1)
|
||||
return HDB_ERR_EXISTS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB__del(krb5_context context, HDB *db, krb5_data key)
|
||||
{
|
||||
DB *d = (DB*)db->hdb_db;
|
||||
DBT k;
|
||||
krb5_error_code code;
|
||||
k.data = key.data;
|
||||
k.size = key.length;
|
||||
code = db->hdb_lock(context, db, HDB_WLOCK);
|
||||
if(code)
|
||||
return code;
|
||||
code = (*d->del)(d, &k, 0);
|
||||
db->hdb_unlock(context, db);
|
||||
if(code == 1)
|
||||
return HDB_ERR_NOENTRY;
|
||||
if(code < 0)
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
|
||||
{
|
||||
char *fn;
|
||||
krb5_error_code ret;
|
||||
|
||||
asprintf(&fn, "%s.db", db->hdb_name);
|
||||
if (fn == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
|
||||
free(fn);
|
||||
/* try to open without .db extension */
|
||||
if(db->hdb_db == NULL && errno == ENOENT)
|
||||
db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
|
||||
if(db->hdb_db == NULL) {
|
||||
ret = errno;
|
||||
krb5_set_error_string(context, "dbopen (%s): %s",
|
||||
db->hdb_name, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
if((flags & O_ACCMODE) == O_RDONLY)
|
||||
ret = hdb_check_db_format(context, db);
|
||||
else
|
||||
ret = hdb_init_db(context, db);
|
||||
if(ret == HDB_ERR_NOENTRY) {
|
||||
krb5_clear_error_string(context);
|
||||
return 0;
|
||||
}
|
||||
if (ret) {
|
||||
DB_close(context, db);
|
||||
krb5_set_error_string(context, "hdb_open: failed %s database %s",
|
||||
(flags & O_ACCMODE) == O_RDONLY ?
|
||||
"checking format of" : "initialize",
|
||||
db->hdb_name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_db_create(krb5_context context, HDB **db,
|
||||
const char *filename)
|
||||
{
|
||||
*db = calloc(1, sizeof(**db));
|
||||
if (*db == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
(*db)->hdb_db = NULL;
|
||||
(*db)->hdb_name = strdup(filename);
|
||||
if ((*db)->hdb_name == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
free(*db);
|
||||
*db = NULL;
|
||||
return ENOMEM;
|
||||
}
|
||||
(*db)->hdb_master_key_set = 0;
|
||||
(*db)->hdb_openp = 0;
|
||||
(*db)->hdb_open = DB_open;
|
||||
(*db)->hdb_close = DB_close;
|
||||
(*db)->hdb_fetch = _hdb_fetch;
|
||||
(*db)->hdb_store = _hdb_store;
|
||||
(*db)->hdb_remove = _hdb_remove;
|
||||
(*db)->hdb_firstkey = DB_firstkey;
|
||||
(*db)->hdb_nextkey= DB_nextkey;
|
||||
(*db)->hdb_lock = DB_lock;
|
||||
(*db)->hdb_unlock = DB_unlock;
|
||||
(*db)->hdb_rename = DB_rename;
|
||||
(*db)->hdb__get = DB__get;
|
||||
(*db)->hdb__put = DB__put;
|
||||
(*db)->hdb__del = DB__del;
|
||||
(*db)->hdb_destroy = DB_destroy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_DB1 */
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (c) 2004 - 2005 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hdb_locl.h"
|
||||
#include <der.h>
|
||||
|
||||
RCSID("$Id: ext.c,v 1.6 2006/10/14 10:13:03 lha Exp $");
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_check_mandatory(krb5_context context, const hdb_entry *ent)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ent->extensions == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* check for unknown extensions and if they where tagged mandatory
|
||||
*/
|
||||
|
||||
for (i = 0; i < ent->extensions->len; i++) {
|
||||
if (ent->extensions->val[i].data.element !=
|
||||
choice_HDB_extension_data_asn1_ellipsis)
|
||||
continue;
|
||||
if (ent->extensions->val[i].mandatory) {
|
||||
krb5_set_error_string(context, "Principal have unknown "
|
||||
"mandatory extension");
|
||||
return HDB_ERR_MANDATORY_OPTION;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
HDB_extension *
|
||||
hdb_find_extension(const hdb_entry *entry, int type)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (entry->extensions == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < entry->extensions->len; i++)
|
||||
if (entry->extensions->val[i].data.element == type)
|
||||
return &entry->extensions->val[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace the extension `ext' in `entry'. Make a copy of the
|
||||
* extension, so the caller must still free `ext' on both success and
|
||||
* failure. Returns 0 or error code.
|
||||
*/
|
||||
|
||||
krb5_error_code
|
||||
hdb_replace_extension(krb5_context context,
|
||||
hdb_entry *entry,
|
||||
const HDB_extension *ext)
|
||||
{
|
||||
HDB_extension *ext2;
|
||||
HDB_extension *es;
|
||||
int ret;
|
||||
|
||||
ext2 = NULL;
|
||||
|
||||
if (entry->extensions == NULL) {
|
||||
entry->extensions = calloc(1, sizeof(*entry->extensions));
|
||||
if (entry->extensions == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
} else if (ext->data.element != choice_HDB_extension_data_asn1_ellipsis) {
|
||||
ext2 = hdb_find_extension(entry, ext->data.element);
|
||||
} else {
|
||||
/*
|
||||
* This is an unknown extention, and we are asked to replace a
|
||||
* possible entry in `entry' that is of the same type. This
|
||||
* might seem impossible, but ASN.1 CHOICE comes to our
|
||||
* rescue. The first tag in each branch in the CHOICE is
|
||||
* unique, so just find the element in the list that have the
|
||||
* same tag was we are putting into the list.
|
||||
*/
|
||||
Der_class replace_class, list_class;
|
||||
Der_type replace_type, list_type;
|
||||
unsigned int replace_tag, list_tag;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
ret = der_get_tag(ext->data.u.asn1_ellipsis.data,
|
||||
ext->data.u.asn1_ellipsis.length,
|
||||
&replace_class, &replace_type, &replace_tag,
|
||||
&size);
|
||||
if (ret) {
|
||||
krb5_set_error_string(context, "hdb: failed to decode "
|
||||
"replacement hdb extention");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < entry->extensions->len; i++) {
|
||||
HDB_extension *ext3 = &entry->extensions->val[i];
|
||||
|
||||
if (ext3->data.element != choice_HDB_extension_data_asn1_ellipsis)
|
||||
continue;
|
||||
|
||||
ret = der_get_tag(ext3->data.u.asn1_ellipsis.data,
|
||||
ext3->data.u.asn1_ellipsis.length,
|
||||
&list_class, &list_type, &list_tag,
|
||||
&size);
|
||||
if (ret) {
|
||||
krb5_set_error_string(context, "hdb: failed to decode "
|
||||
"present hdb extention");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (MAKE_TAG(replace_class,replace_type,replace_type) ==
|
||||
MAKE_TAG(list_class,list_type,list_type)) {
|
||||
ext2 = ext3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ext2) {
|
||||
free_HDB_extension(ext2);
|
||||
ret = copy_HDB_extension(ext, ext2);
|
||||
if (ret)
|
||||
krb5_set_error_string(context, "hdb: failed to copy replacement "
|
||||
"hdb extention");
|
||||
return ret;
|
||||
}
|
||||
|
||||
es = realloc(entry->extensions->val,
|
||||
(entry->extensions->len+1)*sizeof(entry->extensions->val[0]));
|
||||
if (es == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
entry->extensions->val = es;
|
||||
|
||||
ret = copy_HDB_extension(ext,
|
||||
&entry->extensions->val[entry->extensions->len]);
|
||||
if (ret == 0)
|
||||
entry->extensions->len++;
|
||||
else
|
||||
krb5_set_error_string(context, "hdb: failed to copy new extension");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_clear_extension(krb5_context context,
|
||||
hdb_entry *entry,
|
||||
int type)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (entry->extensions == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < entry->extensions->len; i++) {
|
||||
if (entry->extensions->val[i].data.element == type) {
|
||||
free_HDB_extension(&entry->extensions->val[i]);
|
||||
memmove(&entry->extensions->val[i],
|
||||
&entry->extensions->val[i + 1],
|
||||
sizeof(entry->extensions->val[i]) * (entry->extensions->len - i - 1));
|
||||
entry->extensions->len--;
|
||||
}
|
||||
}
|
||||
if (entry->extensions->len == 0) {
|
||||
free(entry->extensions->val);
|
||||
free(entry->extensions);
|
||||
entry->extensions = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_pkinit_acl(const hdb_entry *entry, const HDB_Ext_PKINIT_acl **a)
|
||||
{
|
||||
const HDB_extension *ext;
|
||||
|
||||
ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_acl);
|
||||
if (ext)
|
||||
*a = &ext->data.u.pkinit_acl;
|
||||
else
|
||||
*a = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_pkinit_hash(const hdb_entry *entry, const HDB_Ext_PKINIT_hash **a)
|
||||
{
|
||||
const HDB_extension *ext;
|
||||
|
||||
ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert_hash);
|
||||
if (ext)
|
||||
*a = &ext->data.u.pkinit_cert_hash;
|
||||
else
|
||||
*a = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_pw_change_time(const hdb_entry *entry, time_t *t)
|
||||
{
|
||||
const HDB_extension *ext;
|
||||
|
||||
ext = hdb_find_extension(entry, choice_HDB_extension_data_last_pw_change);
|
||||
if (ext)
|
||||
*t = ext->data.u.last_pw_change;
|
||||
else
|
||||
*t = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_set_pw_change_time(krb5_context context,
|
||||
hdb_entry *entry,
|
||||
time_t t)
|
||||
{
|
||||
HDB_extension ext;
|
||||
|
||||
ext.mandatory = FALSE;
|
||||
ext.data.element = choice_HDB_extension_data_last_pw_change;
|
||||
if (t == 0)
|
||||
t = time(NULL);
|
||||
ext.data.u.last_pw_change = t;
|
||||
|
||||
return hdb_replace_extension(context, entry, &ext);
|
||||
}
|
||||
|
||||
int
|
||||
hdb_entry_get_password(krb5_context context, HDB *db,
|
||||
const hdb_entry *entry, char **p)
|
||||
{
|
||||
HDB_extension *ext;
|
||||
int ret;
|
||||
|
||||
ext = hdb_find_extension(entry, choice_HDB_extension_data_password);
|
||||
if (ext) {
|
||||
heim_utf8_string str;
|
||||
heim_octet_string pw;
|
||||
|
||||
if (db->hdb_master_key_set && ext->data.u.password.mkvno) {
|
||||
hdb_master_key key;
|
||||
|
||||
key = _hdb_find_master_key(ext->data.u.password.mkvno,
|
||||
db->hdb_master_key);
|
||||
|
||||
if (key == NULL) {
|
||||
krb5_set_error_string(context, "master key %d missing",
|
||||
*ext->data.u.password.mkvno);
|
||||
return HDB_ERR_NO_MKEY;
|
||||
}
|
||||
|
||||
ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
|
||||
ext->data.u.password.password.data,
|
||||
ext->data.u.password.password.length,
|
||||
&pw);
|
||||
} else {
|
||||
ret = der_copy_octet_string(&ext->data.u.password.password, &pw);
|
||||
}
|
||||
if (ret) {
|
||||
krb5_clear_error_string(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
str = pw.data;
|
||||
if (str[pw.length - 1] != '\0') {
|
||||
krb5_set_error_string(context, "password malformated");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*p = strdup(str);
|
||||
|
||||
der_free_octet_string(&pw);
|
||||
if (*p == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
krb5_set_error_string(context, "password attribute not found");
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
int
|
||||
hdb_entry_set_password(krb5_context context, HDB *db,
|
||||
hdb_entry *entry, const char *p)
|
||||
{
|
||||
HDB_extension ext;
|
||||
hdb_master_key key;
|
||||
int ret;
|
||||
|
||||
ext.mandatory = FALSE;
|
||||
ext.data.element = choice_HDB_extension_data_password;
|
||||
|
||||
if (db->hdb_master_key_set) {
|
||||
|
||||
key = _hdb_find_master_key(NULL, db->hdb_master_key);
|
||||
if (key == NULL) {
|
||||
krb5_set_error_string(context, "hdb_entry_set_password: "
|
||||
"failed to find masterkey");
|
||||
return HDB_ERR_NO_MKEY;
|
||||
}
|
||||
|
||||
ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY,
|
||||
p, strlen(p) + 1,
|
||||
&ext.data.u.password.password);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ext.data.u.password.mkvno =
|
||||
malloc(sizeof(*ext.data.u.password.mkvno));
|
||||
if (ext.data.u.password.mkvno == NULL) {
|
||||
free_HDB_extension(&ext);
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
*ext.data.u.password.mkvno = _hdb_mkey_version(key);
|
||||
|
||||
} else {
|
||||
ext.data.u.password.mkvno = NULL;
|
||||
|
||||
ret = krb5_data_copy(&ext.data.u.password.password,
|
||||
p, strlen(p) + 1);
|
||||
if (ret) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
free_HDB_extension(&ext);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = hdb_replace_extension(context, entry, &ext);
|
||||
|
||||
free_HDB_extension(&ext);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
hdb_entry_clear_password(krb5_context context, hdb_entry *entry)
|
||||
{
|
||||
return hdb_clear_extension(context, entry,
|
||||
choice_HDB_extension_data_password);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_ConstrainedDelegACL(const hdb_entry *entry,
|
||||
const HDB_Ext_Constrained_delegation_acl **a)
|
||||
{
|
||||
const HDB_extension *ext;
|
||||
|
||||
ext = hdb_find_extension(entry,
|
||||
choice_HDB_extension_data_allowed_to_delegate_to);
|
||||
if (ext)
|
||||
*a = &ext->data.u.allowed_to_delegate_to;
|
||||
else
|
||||
*a = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/* This is a generated file */
|
||||
#ifndef __hdb_private_h__
|
||||
#define __hdb_private_h__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
krb5_error_code
|
||||
_hdb_fetch (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
krb5_const_principal /*principal*/,
|
||||
unsigned /*flags*/,
|
||||
hdb_entry_ex */*entry*/);
|
||||
|
||||
hdb_master_key
|
||||
_hdb_find_master_key (
|
||||
uint32_t */*mkvno*/,
|
||||
hdb_master_key /*mkey*/);
|
||||
|
||||
int
|
||||
_hdb_mkey_decrypt (
|
||||
krb5_context /*context*/,
|
||||
hdb_master_key /*key*/,
|
||||
krb5_key_usage /*usage*/,
|
||||
void */*ptr*/,
|
||||
size_t /*size*/,
|
||||
krb5_data */*res*/);
|
||||
|
||||
int
|
||||
_hdb_mkey_encrypt (
|
||||
krb5_context /*context*/,
|
||||
hdb_master_key /*key*/,
|
||||
krb5_key_usage /*usage*/,
|
||||
const void */*ptr*/,
|
||||
size_t /*size*/,
|
||||
krb5_data */*res*/);
|
||||
|
||||
int
|
||||
_hdb_mkey_version (hdb_master_key /*mkey*/);
|
||||
|
||||
krb5_error_code
|
||||
_hdb_remove (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
krb5_const_principal /*principal*/);
|
||||
|
||||
krb5_error_code
|
||||
_hdb_store (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
unsigned /*flags*/,
|
||||
hdb_entry_ex */*entry*/);
|
||||
|
||||
#endif /* __hdb_private_h__ */
|
||||
@@ -0,0 +1,327 @@
|
||||
/* This is a generated file */
|
||||
#ifndef __hdb_protos_h__
|
||||
#define __hdb_protos_h__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
krb5_error_code
|
||||
hdb_add_master_key (
|
||||
krb5_context /*context*/,
|
||||
krb5_keyblock */*key*/,
|
||||
hdb_master_key */*inout*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_check_db_format (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_clear_extension (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*entry*/,
|
||||
int /*type*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_clear_master_key (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_create (
|
||||
krb5_context /*context*/,
|
||||
HDB **/*db*/,
|
||||
const char */*filename*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_db_create (
|
||||
krb5_context /*context*/,
|
||||
HDB **/*db*/,
|
||||
const char */*filename*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_enctype2key (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*e*/,
|
||||
krb5_enctype /*enctype*/,
|
||||
Key **/*key*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry2string (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*ent*/,
|
||||
char **/*str*/);
|
||||
|
||||
int
|
||||
hdb_entry2value (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*ent*/,
|
||||
krb5_data */*value*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_check_mandatory (
|
||||
krb5_context /*context*/,
|
||||
const hdb_entry */*ent*/);
|
||||
|
||||
int
|
||||
hdb_entry_clear_password (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*entry*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_ConstrainedDelegACL (
|
||||
const hdb_entry */*entry*/,
|
||||
const HDB_Ext_Constrained_delegation_acl **/*a*/);
|
||||
|
||||
int
|
||||
hdb_entry_get_password (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
const hdb_entry */*entry*/,
|
||||
char **/*p*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_pkinit_acl (
|
||||
const hdb_entry */*entry*/,
|
||||
const HDB_Ext_PKINIT_acl **/*a*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_pkinit_hash (
|
||||
const hdb_entry */*entry*/,
|
||||
const HDB_Ext_PKINIT_hash **/*a*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_get_pw_change_time (
|
||||
const hdb_entry */*entry*/,
|
||||
time_t */*t*/);
|
||||
|
||||
int
|
||||
hdb_entry_set_password (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
hdb_entry */*entry*/,
|
||||
const char */*p*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_entry_set_pw_change_time (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*entry*/,
|
||||
time_t /*t*/);
|
||||
|
||||
HDB_extension *
|
||||
hdb_find_extension (
|
||||
const hdb_entry */*entry*/,
|
||||
int /*type*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_foreach (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
unsigned /*flags*/,
|
||||
hdb_foreach_func_t /*func*/,
|
||||
void */*data*/);
|
||||
|
||||
void
|
||||
hdb_free_entry (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry_ex */*ent*/);
|
||||
|
||||
void
|
||||
hdb_free_key (Key */*key*/);
|
||||
|
||||
void
|
||||
hdb_free_keys (
|
||||
krb5_context /*context*/,
|
||||
int /*len*/,
|
||||
Key */*keys*/);
|
||||
|
||||
void
|
||||
hdb_free_master_key (
|
||||
krb5_context /*context*/,
|
||||
hdb_master_key /*mkey*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_generate_key_set (
|
||||
krb5_context /*context*/,
|
||||
krb5_principal /*principal*/,
|
||||
Key **/*ret_key_set*/,
|
||||
size_t */*nkeyset*/,
|
||||
int /*no_salt*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_generate_key_set_password (
|
||||
krb5_context /*context*/,
|
||||
krb5_principal /*principal*/,
|
||||
const char */*password*/,
|
||||
Key **/*keys*/,
|
||||
size_t */*num_keys*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_init_db (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/);
|
||||
|
||||
int
|
||||
hdb_key2principal (
|
||||
krb5_context /*context*/,
|
||||
krb5_data */*key*/,
|
||||
krb5_principal /*p*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_ldap_common (
|
||||
krb5_context /*context*/,
|
||||
HDB ** /*db*/,
|
||||
const char */*search_base*/,
|
||||
const char */*url*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_ldap_create (
|
||||
krb5_context /*context*/,
|
||||
HDB ** /*db*/,
|
||||
const char */*arg*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_ldapi_create (
|
||||
krb5_context /*context*/,
|
||||
HDB ** /*db*/,
|
||||
const char */*arg*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_list_builtin (
|
||||
krb5_context /*context*/,
|
||||
char **/*list*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_lock (
|
||||
int /*fd*/,
|
||||
int /*operation*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_ndbm_create (
|
||||
krb5_context /*context*/,
|
||||
HDB **/*db*/,
|
||||
const char */*filename*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_next_enctype2key (
|
||||
krb5_context /*context*/,
|
||||
const hdb_entry */*e*/,
|
||||
krb5_enctype /*enctype*/,
|
||||
Key **/*key*/);
|
||||
|
||||
int
|
||||
hdb_principal2key (
|
||||
krb5_context /*context*/,
|
||||
krb5_const_principal /*p*/,
|
||||
krb5_data */*key*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_print_entry (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
hdb_entry_ex */*entry*/,
|
||||
void */*data*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_process_master_key (
|
||||
krb5_context /*context*/,
|
||||
int /*kvno*/,
|
||||
krb5_keyblock */*key*/,
|
||||
krb5_enctype /*etype*/,
|
||||
hdb_master_key */*mkey*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_read_master_key (
|
||||
krb5_context /*context*/,
|
||||
const char */*filename*/,
|
||||
hdb_master_key */*mkey*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_replace_extension (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*entry*/,
|
||||
const HDB_extension */*ext*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_key (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
Key */*k*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_key_mkey (
|
||||
krb5_context /*context*/,
|
||||
Key */*k*/,
|
||||
hdb_master_key /*mkey*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_keys (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
hdb_entry */*ent*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_keys_mkey (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*ent*/,
|
||||
hdb_master_key /*mkey*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_set_master_key (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
krb5_keyblock */*key*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_set_master_keyfile (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
const char */*keyfile*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_unlock (int /*fd*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_key (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
Key */*k*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_key_mkey (
|
||||
krb5_context /*context*/,
|
||||
Key */*k*/,
|
||||
hdb_master_key /*mkey*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_keys (
|
||||
krb5_context /*context*/,
|
||||
HDB */*db*/,
|
||||
hdb_entry */*ent*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_keys_mkey (
|
||||
krb5_context /*context*/,
|
||||
hdb_entry */*ent*/,
|
||||
hdb_master_key /*mkey*/);
|
||||
|
||||
int
|
||||
hdb_value2entry (
|
||||
krb5_context /*context*/,
|
||||
krb5_data */*value*/,
|
||||
hdb_entry */*ent*/);
|
||||
|
||||
krb5_error_code
|
||||
hdb_write_master_key (
|
||||
krb5_context /*context*/,
|
||||
const char */*filename*/,
|
||||
hdb_master_key /*mkey*/);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __hdb_protos_h__ */
|
||||
@@ -0,0 +1,123 @@
|
||||
-- $Id: hdb.asn1,v 1.17 2006/08/24 10:45:19 lha Exp $
|
||||
HDB DEFINITIONS ::=
|
||||
BEGIN
|
||||
|
||||
IMPORTS EncryptionKey, KerberosTime, Principal FROM krb5;
|
||||
|
||||
HDB_DB_FORMAT INTEGER ::= 2 -- format of database,
|
||||
-- update when making changes
|
||||
|
||||
-- these must have the same value as the pa-* counterparts
|
||||
hdb-pw-salt INTEGER ::= 3
|
||||
hdb-afs3-salt INTEGER ::= 10
|
||||
|
||||
Salt ::= SEQUENCE {
|
||||
type[0] INTEGER (0..4294967295),
|
||||
salt[1] OCTET STRING
|
||||
}
|
||||
|
||||
Key ::= SEQUENCE {
|
||||
mkvno[0] INTEGER (0..4294967295) OPTIONAL, -- master key version number
|
||||
key[1] EncryptionKey,
|
||||
salt[2] Salt OPTIONAL
|
||||
}
|
||||
|
||||
Event ::= SEQUENCE {
|
||||
time[0] KerberosTime,
|
||||
principal[1] Principal OPTIONAL
|
||||
}
|
||||
|
||||
HDBFlags ::= BIT STRING {
|
||||
initial(0), -- require as-req
|
||||
forwardable(1), -- may issue forwardable
|
||||
proxiable(2), -- may issue proxiable
|
||||
renewable(3), -- may issue renewable
|
||||
postdate(4), -- may issue postdatable
|
||||
server(5), -- may be server
|
||||
client(6), -- may be client
|
||||
invalid(7), -- entry is invalid
|
||||
require-preauth(8), -- must use preauth
|
||||
change-pw(9), -- change password service
|
||||
require-hwauth(10), -- must use hwauth
|
||||
ok-as-delegate(11), -- as in TicketFlags
|
||||
user-to-user(12), -- may use user-to-user auth
|
||||
immutable(13), -- may not be deleted
|
||||
trusted-for-delegation(14), -- Trusted to print forwardabled tickets
|
||||
allow-kerberos4(15), -- Allow Kerberos 4 requests
|
||||
allow-digest(16) -- Allow digest requests
|
||||
}
|
||||
|
||||
GENERATION ::= SEQUENCE {
|
||||
time[0] KerberosTime, -- timestamp
|
||||
usec[1] INTEGER (0..4294967295), -- microseconds
|
||||
gen[2] INTEGER (0..4294967295) -- generation number
|
||||
}
|
||||
|
||||
HDB-Ext-PKINIT-acl ::= SEQUENCE OF SEQUENCE {
|
||||
subject[0] UTF8String,
|
||||
issuer[1] UTF8String OPTIONAL,
|
||||
anchor[2] UTF8String OPTIONAL
|
||||
}
|
||||
|
||||
HDB-Ext-PKINIT-hash ::= SEQUENCE OF SEQUENCE {
|
||||
digest-type[0] OBJECT IDENTIFIER,
|
||||
digest[1] OCTET STRING
|
||||
}
|
||||
|
||||
HDB-Ext-Constrained-delegation-acl ::= SEQUENCE OF Principal
|
||||
|
||||
-- hdb-ext-referrals ::= PA-SERVER-REFERRAL-DATA
|
||||
|
||||
HDB-Ext-Lan-Manager-OWF ::= OCTET STRING
|
||||
|
||||
HDB-Ext-Password ::= SEQUENCE {
|
||||
mkvno[0] INTEGER (0..4294967295) OPTIONAL, -- master key version number
|
||||
password OCTET STRING
|
||||
}
|
||||
|
||||
HDB-Ext-Aliases ::= SEQUENCE {
|
||||
case-insensitive[0] BOOLEAN, -- case insensitive name allowed
|
||||
aliases[1] SEQUENCE OF Principal -- all names, inc primary
|
||||
}
|
||||
|
||||
|
||||
HDB-extension ::= SEQUENCE {
|
||||
mandatory[0] BOOLEAN, -- kdc MUST understand this extension,
|
||||
-- if not the whole entry must
|
||||
-- be rejected
|
||||
data[1] CHOICE {
|
||||
pkinit-acl[0] HDB-Ext-PKINIT-acl,
|
||||
pkinit-cert-hash[1] HDB-Ext-PKINIT-hash,
|
||||
allowed-to-delegate-to[2] HDB-Ext-Constrained-delegation-acl,
|
||||
-- referral-info[3] HDB-Ext-Referrals,
|
||||
lm-owf[4] HDB-Ext-Lan-Manager-OWF,
|
||||
password[5] HDB-Ext-Password,
|
||||
aliases[6] HDB-Ext-Aliases,
|
||||
last-pw-change[7] KerberosTime,
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
|
||||
HDB-extensions ::= SEQUENCE OF HDB-extension
|
||||
|
||||
|
||||
hdb_entry ::= SEQUENCE {
|
||||
principal[0] Principal OPTIONAL, -- this is optional only
|
||||
-- for compatibility with libkrb5
|
||||
kvno[1] INTEGER (0..4294967295),
|
||||
keys[2] SEQUENCE OF Key,
|
||||
created-by[3] Event,
|
||||
modified-by[4] Event OPTIONAL,
|
||||
valid-start[5] KerberosTime OPTIONAL,
|
||||
valid-end[6] KerberosTime OPTIONAL,
|
||||
pw-end[7] KerberosTime OPTIONAL,
|
||||
max-life[8] INTEGER (0..4294967295) OPTIONAL,
|
||||
max-renew[9] INTEGER (0..4294967295) OPTIONAL,
|
||||
flags[10] HDBFlags,
|
||||
etypes[11] SEQUENCE OF INTEGER (0..4294967295) OPTIONAL,
|
||||
generation[12] GENERATION OPTIONAL,
|
||||
extensions[13] HDB-extensions OPTIONAL
|
||||
}
|
||||
|
||||
END
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hdb_locl.h"
|
||||
|
||||
RCSID("$Id: hdb.c,v 1.62 2006/10/06 16:47:22 lha Exp $");
|
||||
|
||||
#ifdef HAVE_DLFCN_H
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
struct hdb_method {
|
||||
const char *prefix;
|
||||
krb5_error_code (*create)(krb5_context, HDB **, const char *filename);
|
||||
};
|
||||
|
||||
static struct hdb_method methods[] = {
|
||||
#if HAVE_DB1 || HAVE_DB3
|
||||
{"db:", hdb_db_create},
|
||||
#endif
|
||||
#if HAVE_NDBM
|
||||
{"ndbm:", hdb_ndbm_create},
|
||||
#endif
|
||||
#if defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
|
||||
{"ldap:", hdb_ldap_create},
|
||||
{"ldapi:", hdb_ldapi_create},
|
||||
#endif
|
||||
#ifdef _SAMBA_BUILD_
|
||||
{"ldb:", hdb_ldb_create},
|
||||
#endif
|
||||
#ifdef HAVE_LDB /* Used for integrated samba build */
|
||||
{"ldb:", hdb_ldb_create},
|
||||
#endif
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
#if HAVE_DB1 || HAVE_DB3
|
||||
static struct hdb_method dbmetod = {"", hdb_db_create };
|
||||
#elif defined(HAVE_NDBM)
|
||||
static struct hdb_method dbmetod = {"", hdb_ndbm_create };
|
||||
#endif
|
||||
|
||||
|
||||
krb5_error_code
|
||||
hdb_next_enctype2key(krb5_context context,
|
||||
const hdb_entry *e,
|
||||
krb5_enctype enctype,
|
||||
Key **key)
|
||||
{
|
||||
Key *k;
|
||||
|
||||
for (k = *key ? (*key) + 1 : e->keys.val;
|
||||
k < e->keys.val + e->keys.len;
|
||||
k++)
|
||||
if(k->key.keytype == enctype){
|
||||
*key = k;
|
||||
return 0;
|
||||
}
|
||||
return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_enctype2key(krb5_context context,
|
||||
hdb_entry *e,
|
||||
krb5_enctype enctype,
|
||||
Key **key)
|
||||
{
|
||||
*key = NULL;
|
||||
return hdb_next_enctype2key(context, e, enctype, key);
|
||||
}
|
||||
|
||||
void
|
||||
hdb_free_key(Key *key)
|
||||
{
|
||||
memset(key->key.keyvalue.data,
|
||||
0,
|
||||
key->key.keyvalue.length);
|
||||
free_Key(key);
|
||||
free(key);
|
||||
}
|
||||
|
||||
|
||||
krb5_error_code
|
||||
hdb_lock(int fd, int operation)
|
||||
{
|
||||
int i, code = 0;
|
||||
|
||||
for(i = 0; i < 3; i++){
|
||||
code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
|
||||
if(code == 0 || errno != EWOULDBLOCK)
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
if(code == 0)
|
||||
return 0;
|
||||
if(errno == EWOULDBLOCK)
|
||||
return HDB_ERR_DB_INUSE;
|
||||
return HDB_ERR_CANT_LOCK_DB;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_unlock(int fd)
|
||||
{
|
||||
int code;
|
||||
code = flock(fd, LOCK_UN);
|
||||
if(code)
|
||||
return 4711 /* XXX */;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hdb_free_entry(krb5_context context, hdb_entry_ex *ent)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ent->free_entry)
|
||||
(*ent->free_entry)(context, ent);
|
||||
|
||||
for(i = 0; i < ent->entry.keys.len; ++i) {
|
||||
Key *k = &ent->entry.keys.val[i];
|
||||
|
||||
memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
|
||||
}
|
||||
free_hdb_entry(&ent->entry);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_foreach(krb5_context context,
|
||||
HDB *db,
|
||||
unsigned flags,
|
||||
hdb_foreach_func_t func,
|
||||
void *data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
hdb_entry_ex entry;
|
||||
ret = db->hdb_firstkey(context, db, flags, &entry);
|
||||
while(ret == 0){
|
||||
ret = (*func)(context, db, &entry, data);
|
||||
hdb_free_entry(context, &entry);
|
||||
if(ret == 0)
|
||||
ret = db->hdb_nextkey(context, db, flags, &entry);
|
||||
}
|
||||
if(ret == HDB_ERR_NOENTRY)
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_check_db_format(krb5_context context, HDB *db)
|
||||
{
|
||||
krb5_data tag;
|
||||
krb5_data version;
|
||||
krb5_error_code ret, ret2;
|
||||
unsigned ver;
|
||||
int foo;
|
||||
|
||||
ret = db->hdb_lock(context, db, HDB_RLOCK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tag.data = HDB_DB_FORMAT_ENTRY;
|
||||
tag.length = strlen(tag.data);
|
||||
ret = (*db->hdb__get)(context, db, tag, &version);
|
||||
ret2 = db->hdb_unlock(context, db);
|
||||
if(ret)
|
||||
return ret;
|
||||
if (ret2)
|
||||
return ret2;
|
||||
foo = sscanf(version.data, "%u", &ver);
|
||||
krb5_data_free (&version);
|
||||
if (foo != 1)
|
||||
return HDB_ERR_BADVERSION;
|
||||
if(ver != HDB_DB_FORMAT)
|
||||
return HDB_ERR_BADVERSION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_init_db(krb5_context context, HDB *db)
|
||||
{
|
||||
krb5_error_code ret, ret2;
|
||||
krb5_data tag;
|
||||
krb5_data version;
|
||||
char ver[32];
|
||||
|
||||
ret = hdb_check_db_format(context, db);
|
||||
if(ret != HDB_ERR_NOENTRY)
|
||||
return ret;
|
||||
|
||||
ret = db->hdb_lock(context, db, HDB_WLOCK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tag.data = HDB_DB_FORMAT_ENTRY;
|
||||
tag.length = strlen(tag.data);
|
||||
snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
|
||||
version.data = ver;
|
||||
version.length = strlen(version.data) + 1; /* zero terminated */
|
||||
ret = (*db->hdb__put)(context, db, 0, tag, version);
|
||||
ret2 = db->hdb_unlock(context, db);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ret2;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DLOPEN
|
||||
|
||||
/*
|
||||
* Load a dynamic backend from /usr/heimdal/lib/hdb_NAME.so,
|
||||
* looking for the hdb_NAME_create symbol.
|
||||
*/
|
||||
|
||||
static const struct hdb_method *
|
||||
find_dynamic_method (krb5_context context,
|
||||
const char *filename,
|
||||
const char **rest)
|
||||
{
|
||||
static struct hdb_method method;
|
||||
struct hdb_so_method *mso;
|
||||
char *prefix, *path, *symbol;
|
||||
const char *p;
|
||||
void *dl;
|
||||
size_t len;
|
||||
|
||||
p = strchr(filename, ':');
|
||||
|
||||
/* if no prefix, don't know what module to load, just ignore it */
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
len = p - filename;
|
||||
*rest = filename + len + 1;
|
||||
|
||||
prefix = strndup(filename, len);
|
||||
if (prefix == NULL)
|
||||
krb5_errx(context, 1, "out of memory");
|
||||
|
||||
if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1)
|
||||
krb5_errx(context, 1, "out of memory");
|
||||
|
||||
#ifndef RTLD_NOW
|
||||
#define RTLD_NOW 0
|
||||
#endif
|
||||
#ifndef RTLD_GLOBAL
|
||||
#define RTLD_GLOBAL 0
|
||||
#endif
|
||||
|
||||
dl = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (dl == NULL) {
|
||||
krb5_warnx(context, "error trying to load dynamic module %s: %s\n",
|
||||
path, dlerror());
|
||||
free(prefix);
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (asprintf(&symbol, "hdb_%s_interface", prefix) == -1)
|
||||
krb5_errx(context, 1, "out of memory");
|
||||
|
||||
mso = dlsym(dl, symbol);
|
||||
if (mso == NULL) {
|
||||
krb5_warnx(context, "error finding symbol %s in %s: %s\n",
|
||||
symbol, path, dlerror());
|
||||
dlclose(dl);
|
||||
free(symbol);
|
||||
free(prefix);
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
free(path);
|
||||
free(symbol);
|
||||
|
||||
if (mso->version != HDB_INTERFACE_VERSION) {
|
||||
krb5_warnx(context,
|
||||
"error wrong version in shared module %s "
|
||||
"version: %d should have been %d\n",
|
||||
prefix, mso->version, HDB_INTERFACE_VERSION);
|
||||
dlclose(dl);
|
||||
free(prefix);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mso->create == NULL) {
|
||||
krb5_errx(context, 1,
|
||||
"no entry point function in shared mod %s ",
|
||||
prefix);
|
||||
dlclose(dl);
|
||||
free(prefix);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
method.create = mso->create;
|
||||
method.prefix = prefix;
|
||||
|
||||
return &method;
|
||||
}
|
||||
#endif /* HAVE_DLOPEN */
|
||||
|
||||
/*
|
||||
* find the relevant method for `filename', returning a pointer to the
|
||||
* rest in `rest'.
|
||||
* return NULL if there's no such method.
|
||||
*/
|
||||
|
||||
static const struct hdb_method *
|
||||
find_method (const char *filename, const char **rest)
|
||||
{
|
||||
const struct hdb_method *h;
|
||||
|
||||
for (h = methods; h->prefix != NULL; ++h) {
|
||||
if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) {
|
||||
*rest = filename + strlen(h->prefix);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_DB1) || defined(HAVE_DB3) || defined(HAVE_NDBM)
|
||||
if (strncmp(filename, "/", 1) == 0
|
||||
|| strncmp(filename, "./", 2) == 0
|
||||
|| strncmp(filename, "../", 3) == 0)
|
||||
{
|
||||
*rest = filename;
|
||||
return &dbmetod;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_list_builtin(krb5_context context, char **list)
|
||||
{
|
||||
const struct hdb_method *h;
|
||||
size_t len = 0;
|
||||
char *buf = NULL;
|
||||
|
||||
for (h = methods; h->prefix != NULL; ++h) {
|
||||
if (h->prefix[0] == '\0')
|
||||
continue;
|
||||
len += strlen(h->prefix) + 2;
|
||||
}
|
||||
|
||||
len += 1;
|
||||
buf = malloc(len);
|
||||
if (buf == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
buf[0] = '\0';
|
||||
|
||||
for (h = methods; h->prefix != NULL; ++h) {
|
||||
if (h != methods)
|
||||
strlcat(buf, ", ", len);
|
||||
strlcat(buf, h->prefix, len);
|
||||
}
|
||||
*list = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_create(krb5_context context, HDB **db, const char *filename)
|
||||
{
|
||||
const struct hdb_method *h;
|
||||
const char *residual;
|
||||
|
||||
if(filename == NULL)
|
||||
filename = HDB_DEFAULT_DB;
|
||||
krb5_add_et_list(context, initialize_hdb_error_table_r);
|
||||
h = find_method (filename, &residual);
|
||||
#ifdef HAVE_DLOPEN
|
||||
if (h == NULL)
|
||||
h = find_dynamic_method (context, filename, &residual);
|
||||
#endif
|
||||
if (h == NULL)
|
||||
krb5_errx(context, 1, "No database support for %s", filename);
|
||||
return (*h->create)(context, db, residual);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id: hdb.h,v 1.38 2006/04/28 07:37:11 lha Exp $ */
|
||||
|
||||
#ifndef __HDB_H__
|
||||
#define __HDB_H__
|
||||
|
||||
#include <hdb_err.h>
|
||||
|
||||
#include <heim_asn1.h>
|
||||
#include <hdb_asn1.h>
|
||||
|
||||
enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK };
|
||||
|
||||
/* flags for various functions */
|
||||
#define HDB_F_DECRYPT 1 /* decrypt keys */
|
||||
#define HDB_F_REPLACE 2 /* replace entry */
|
||||
#define HDB_F_GET_CLIENT 4 /* fetch client */
|
||||
#define HDB_F_GET_SERVER 8 /* fetch server */
|
||||
#define HDB_F_GET_KRBTGT 16 /* fetch krbtgt */
|
||||
#define HDB_F_GET_ANY 28 /* fetch any of client,server,krbtgt */
|
||||
|
||||
/* key usage for master key */
|
||||
#define HDB_KU_MKEY 0x484442
|
||||
|
||||
typedef struct hdb_master_key_data *hdb_master_key;
|
||||
|
||||
typedef struct hdb_entry_ex {
|
||||
void *ctx;
|
||||
hdb_entry entry;
|
||||
void (*free_entry)(krb5_context, struct hdb_entry_ex *);
|
||||
krb5_error_code (*check_client_access)(krb5_context, struct hdb_entry_ex *,
|
||||
HostAddresses *);
|
||||
krb5_error_code (*authz_data_as_req)(krb5_context,
|
||||
struct hdb_entry_ex *,
|
||||
METHOD_DATA* pa_data_seq,
|
||||
time_t authtime,
|
||||
const EncryptionKey *tgtkey,
|
||||
const EncryptionKey *sessionkey,
|
||||
AuthorizationData **out);
|
||||
krb5_error_code (*authz_data_tgs_req)(krb5_context,
|
||||
struct hdb_entry_ex *,
|
||||
krb5_principal client,
|
||||
AuthorizationData *in,
|
||||
time_t authtime,
|
||||
const EncryptionKey *tgtkey,
|
||||
const EncryptionKey *servicekey,
|
||||
const EncryptionKey *sessionkey,
|
||||
AuthorizationData **out);
|
||||
} hdb_entry_ex;
|
||||
|
||||
|
||||
typedef struct HDB{
|
||||
void *hdb_db;
|
||||
void *hdb_dbc;
|
||||
char *hdb_name;
|
||||
int hdb_master_key_set;
|
||||
hdb_master_key hdb_master_key;
|
||||
void *hdb_openp;
|
||||
|
||||
krb5_error_code (*hdb_open)(krb5_context,
|
||||
struct HDB*,
|
||||
int,
|
||||
mode_t);
|
||||
krb5_error_code (*hdb_close)(krb5_context,
|
||||
struct HDB*);
|
||||
void (*hdb_free)(krb5_context,
|
||||
struct HDB*,
|
||||
hdb_entry_ex*);
|
||||
krb5_error_code (*hdb_fetch)(krb5_context,
|
||||
struct HDB*,
|
||||
krb5_const_principal,
|
||||
unsigned,
|
||||
hdb_entry_ex*);
|
||||
krb5_error_code (*hdb_store)(krb5_context,
|
||||
struct HDB*,
|
||||
unsigned,
|
||||
hdb_entry_ex*);
|
||||
krb5_error_code (*hdb_remove)(krb5_context,
|
||||
struct HDB*,
|
||||
krb5_const_principal);
|
||||
krb5_error_code (*hdb_firstkey)(krb5_context,
|
||||
struct HDB*,
|
||||
unsigned,
|
||||
hdb_entry_ex*);
|
||||
krb5_error_code (*hdb_nextkey)(krb5_context,
|
||||
struct HDB*,
|
||||
unsigned,
|
||||
hdb_entry_ex*);
|
||||
krb5_error_code (*hdb_lock)(krb5_context,
|
||||
struct HDB*,
|
||||
int operation);
|
||||
krb5_error_code (*hdb_unlock)(krb5_context,
|
||||
struct HDB*);
|
||||
krb5_error_code (*hdb_rename)(krb5_context,
|
||||
struct HDB*,
|
||||
const char*);
|
||||
krb5_error_code (*hdb__get)(krb5_context,
|
||||
struct HDB*,
|
||||
krb5_data,
|
||||
krb5_data*);
|
||||
krb5_error_code (*hdb__put)(krb5_context,
|
||||
struct HDB*,
|
||||
int,
|
||||
krb5_data,
|
||||
krb5_data);
|
||||
krb5_error_code (*hdb__del)(krb5_context,
|
||||
struct HDB*,
|
||||
krb5_data);
|
||||
krb5_error_code (*hdb_destroy)(krb5_context,
|
||||
struct HDB*);
|
||||
}HDB;
|
||||
|
||||
#define HDB_INTERFACE_VERSION 4
|
||||
|
||||
struct hdb_so_method {
|
||||
int version;
|
||||
const char *prefix;
|
||||
krb5_error_code (*create)(krb5_context, HDB **, const char *filename);
|
||||
};
|
||||
|
||||
#define HDB_DB_DIR "/var/heimdal"
|
||||
#define HDB_DEFAULT_DB HDB_DB_DIR "/heimdal"
|
||||
#define HDB_DB_FORMAT_ENTRY "hdb/db-format"
|
||||
|
||||
typedef krb5_error_code (*hdb_foreach_func_t)(krb5_context, HDB*,
|
||||
hdb_entry_ex*, void*);
|
||||
extern krb5_kt_ops hdb_kt_ops;
|
||||
|
||||
#include <hdb-protos.h>
|
||||
|
||||
#endif /* __HDB_H__ */
|
||||
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# Error messages for the hdb library
|
||||
#
|
||||
# This might look like a com_err file, but is not
|
||||
#
|
||||
id "$Id: hdb_err.et,v 1.6 2005/08/11 13:17:22 lha Exp $"
|
||||
|
||||
error_table hdb
|
||||
|
||||
prefix HDB_ERR
|
||||
|
||||
index 1
|
||||
#error_code INUSE, "Entry already exists in database"
|
||||
error_code UK_SERROR, "Database store error"
|
||||
error_code UK_RERROR, "Database read error"
|
||||
error_code NOENTRY, "No such entry in the database"
|
||||
error_code DB_INUSE, "Database is locked or in use--try again later"
|
||||
error_code DB_CHANGED, "Database was modified during read"
|
||||
error_code RECURSIVELOCK, "Attempt to lock database twice"
|
||||
error_code NOTLOCKED, "Attempt to unlock database when not locked"
|
||||
error_code BADLOCKMODE, "Invalid kdb lock mode"
|
||||
error_code CANT_LOCK_DB, "Insufficient access to lock database"
|
||||
error_code EXISTS, "Entry already exists in database"
|
||||
error_code BADVERSION, "Wrong database version"
|
||||
error_code NO_MKEY, "No correct master key"
|
||||
error_code MANDATORY_OPTION, "Entry contains unknown mandatory extension"
|
||||
|
||||
end
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 1997-2001 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id: hdb_locl.h,v 1.19 2003/09/10 21:54:58 lha Exp $ */
|
||||
|
||||
#ifndef __HDB_LOCL_H__
|
||||
#define __HDB_LOCL_H__
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <roken.h>
|
||||
|
||||
#include "crypto-headers.h"
|
||||
#include <krb5.h>
|
||||
#include <hdb.h>
|
||||
#include <hdb-private.h>
|
||||
|
||||
krb5_error_code
|
||||
hdb_ldb_create (
|
||||
krb5_context /*context*/,
|
||||
HDB ** /*db*/,
|
||||
const char */*arg*/);
|
||||
|
||||
|
||||
#endif /* __HDB_LOCL_H__ */
|
||||
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (c) 1997 - 2001, 2003 - 2004 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hdb_locl.h"
|
||||
|
||||
RCSID("$Id: keys.c,v 1.6 2006/10/22 09:40:12 lha Exp $");
|
||||
|
||||
/*
|
||||
* free all the memory used by (len, keys)
|
||||
*/
|
||||
|
||||
void
|
||||
hdb_free_keys (krb5_context context, int len, Key *keys)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
free(keys[i].mkvno);
|
||||
keys[i].mkvno = NULL;
|
||||
if (keys[i].salt != NULL) {
|
||||
free_Salt(keys[i].salt);
|
||||
free(keys[i].salt);
|
||||
keys[i].salt = NULL;
|
||||
}
|
||||
krb5_free_keyblock_contents(context, &keys[i].key);
|
||||
}
|
||||
free (keys);
|
||||
}
|
||||
|
||||
/*
|
||||
* for each entry in `default_keys' try to parse it as a sequence
|
||||
* of etype:salttype:salt, syntax of this if something like:
|
||||
* [(des|des3|etype):](pw-salt|afs3)[:string], if etype is omitted it
|
||||
* means all etypes, and if string is omitted is means the default
|
||||
* string (for that principal). Additional special values:
|
||||
* v5 == pw-salt, and
|
||||
* v4 == des:pw-salt:
|
||||
* afs or afs3 == des:afs3-salt
|
||||
*/
|
||||
|
||||
/* the 3 DES types must be first */
|
||||
static const krb5_enctype all_etypes[] = {
|
||||
ETYPE_DES_CBC_MD5,
|
||||
ETYPE_DES_CBC_MD4,
|
||||
ETYPE_DES_CBC_CRC,
|
||||
ETYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
ETYPE_ARCFOUR_HMAC_MD5,
|
||||
ETYPE_DES3_CBC_SHA1
|
||||
};
|
||||
|
||||
static krb5_error_code
|
||||
parse_key_set(krb5_context context, const char *key,
|
||||
krb5_enctype **ret_enctypes, size_t *ret_num_enctypes,
|
||||
krb5_salt *salt, krb5_principal principal)
|
||||
{
|
||||
const char *p;
|
||||
char buf[3][256];
|
||||
int num_buf = 0;
|
||||
int i, num_enctypes = 0;
|
||||
krb5_enctype e;
|
||||
const krb5_enctype *enctypes = NULL;
|
||||
krb5_error_code ret;
|
||||
|
||||
p = key;
|
||||
|
||||
*ret_enctypes = NULL;
|
||||
*ret_num_enctypes = 0;
|
||||
|
||||
/* split p in a list of :-separated strings */
|
||||
for(num_buf = 0; num_buf < 3; num_buf++)
|
||||
if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1)
|
||||
break;
|
||||
|
||||
salt->saltvalue.data = NULL;
|
||||
salt->saltvalue.length = 0;
|
||||
|
||||
for(i = 0; i < num_buf; i++) {
|
||||
if(enctypes == NULL) {
|
||||
/* this might be a etype specifier */
|
||||
/* XXX there should be a string_to_etypes handling
|
||||
special cases like `des' and `all' */
|
||||
if(strcmp(buf[i], "des") == 0) {
|
||||
enctypes = all_etypes;
|
||||
num_enctypes = 3;
|
||||
} else if(strcmp(buf[i], "des3") == 0) {
|
||||
e = ETYPE_DES3_CBC_SHA1;
|
||||
enctypes = &e;
|
||||
num_enctypes = 1;
|
||||
} else {
|
||||
ret = krb5_string_to_enctype(context, buf[i], &e);
|
||||
if (ret == 0) {
|
||||
enctypes = &e;
|
||||
num_enctypes = 1;
|
||||
} else
|
||||
return ret;
|
||||
}
|
||||
} else if(salt->salttype == 0) {
|
||||
/* interpret string as a salt specifier, if no etype
|
||||
is set, this sets default values */
|
||||
/* XXX should perhaps use string_to_salttype, but that
|
||||
interface sucks */
|
||||
if(strcmp(buf[i], "pw-salt") == 0) {
|
||||
if(enctypes == NULL) {
|
||||
enctypes = all_etypes;
|
||||
num_enctypes = sizeof(all_etypes)/sizeof(all_etypes[0]);
|
||||
}
|
||||
salt->salttype = KRB5_PW_SALT;
|
||||
} else if(strcmp(buf[i], "afs3-salt") == 0) {
|
||||
if(enctypes == NULL) {
|
||||
enctypes = all_etypes;
|
||||
num_enctypes = 3;
|
||||
}
|
||||
salt->salttype = KRB5_AFS3_SALT;
|
||||
}
|
||||
} else {
|
||||
/* if there is a final string, use it as the string to
|
||||
salt with, this is mostly useful with null salt for
|
||||
v4 compat, and a cell name for afs compat */
|
||||
salt->saltvalue.data = strdup(buf[i]);
|
||||
if (salt->saltvalue.data == NULL) {
|
||||
krb5_set_error_string(context, "out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
salt->saltvalue.length = strlen(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(enctypes == NULL || salt->salttype == 0) {
|
||||
krb5_set_error_string(context, "bad value for default_keys `%s'", key);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* if no salt was specified make up default salt */
|
||||
if(salt->saltvalue.data == NULL) {
|
||||
if(salt->salttype == KRB5_PW_SALT)
|
||||
ret = krb5_get_pw_salt(context, principal, salt);
|
||||
else if(salt->salttype == KRB5_AFS3_SALT) {
|
||||
krb5_realm *realm = krb5_princ_realm(context, principal);
|
||||
salt->saltvalue.data = strdup(*realm);
|
||||
if(salt->saltvalue.data == NULL) {
|
||||
krb5_set_error_string(context, "out of memory while "
|
||||
"parsing salt specifiers");
|
||||
return ENOMEM;
|
||||
}
|
||||
strlwr(salt->saltvalue.data);
|
||||
salt->saltvalue.length = strlen(*realm);
|
||||
}
|
||||
}
|
||||
|
||||
*ret_enctypes = malloc(sizeof(enctypes[0]) * num_enctypes);
|
||||
if (*ret_enctypes == NULL) {
|
||||
krb5_free_salt(context, *salt);
|
||||
krb5_set_error_string(context, "out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * num_enctypes);
|
||||
*ret_num_enctypes = num_enctypes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
add_enctype_to_key_set(Key **key_set, size_t *nkeyset,
|
||||
krb5_enctype enctype, krb5_salt *salt)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
Key key, *tmp;
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
|
||||
tmp = realloc(*key_set, (*nkeyset + 1) * sizeof((*key_set)[0]));
|
||||
if (tmp == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
*key_set = tmp;
|
||||
|
||||
key.key.keytype = enctype;
|
||||
key.key.keyvalue.length = 0;
|
||||
key.key.keyvalue.data = NULL;
|
||||
|
||||
if (salt) {
|
||||
key.salt = malloc(sizeof(*key.salt));
|
||||
if (key.salt == NULL) {
|
||||
free_Key(&key);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
key.salt->type = salt->salttype;
|
||||
krb5_data_zero (&key.salt->salt);
|
||||
|
||||
ret = krb5_data_copy(&key.salt->salt,
|
||||
salt->saltvalue.data,
|
||||
salt->saltvalue.length);
|
||||
if (ret) {
|
||||
free_Key(&key);
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
key.salt = NULL;
|
||||
|
||||
(*key_set)[*nkeyset] = key;
|
||||
|
||||
*nkeyset += 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate the `key_set' from the [kadmin]default_keys statement. If
|
||||
* `no_salt' is set, salt is not important (and will not be set) since
|
||||
* its random keys that is going to be created.
|
||||
*/
|
||||
|
||||
krb5_error_code
|
||||
hdb_generate_key_set(krb5_context context, krb5_principal principal,
|
||||
Key **ret_key_set, size_t *nkeyset, int no_salt)
|
||||
{
|
||||
char **ktypes, **kp;
|
||||
krb5_error_code ret;
|
||||
Key *k, *key_set;
|
||||
int i, j;
|
||||
char *default_keytypes[] = {
|
||||
"des:pw-salt",
|
||||
"aes256-cts-hmac-sha1-96:pw-salt",
|
||||
"des3-cbc-sha1:pw-salt",
|
||||
"arcfour-hmac-md5:pw-salt",
|
||||
NULL
|
||||
};
|
||||
|
||||
ktypes = krb5_config_get_strings(context, NULL, "kadmin",
|
||||
"default_keys", NULL);
|
||||
if (ktypes == NULL)
|
||||
ktypes = default_keytypes;
|
||||
|
||||
if (ktypes == NULL)
|
||||
abort();
|
||||
|
||||
*ret_key_set = key_set = NULL;
|
||||
*nkeyset = 0;
|
||||
|
||||
ret = 0;
|
||||
|
||||
for(kp = ktypes; kp && *kp; kp++) {
|
||||
const char *p;
|
||||
krb5_salt salt;
|
||||
krb5_enctype *enctypes;
|
||||
size_t num_enctypes;
|
||||
|
||||
p = *kp;
|
||||
/* check alias */
|
||||
if(strcmp(p, "v5") == 0)
|
||||
p = "pw-salt";
|
||||
else if(strcmp(p, "v4") == 0)
|
||||
p = "des:pw-salt:";
|
||||
else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0)
|
||||
p = "des:afs3-salt";
|
||||
else if (strcmp(p, "arcfour-hmac-md5") == 0)
|
||||
p = "arcfour-hmac-md5:pw-salt";
|
||||
|
||||
memset(&salt, 0, sizeof(salt));
|
||||
|
||||
ret = parse_key_set(context, p,
|
||||
&enctypes, &num_enctypes, &salt, principal);
|
||||
if (ret) {
|
||||
krb5_warn(context, ret, "bad value for default_keys `%s'", *kp);
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_enctypes; i++) {
|
||||
/* find duplicates */
|
||||
for (j = 0; j < *nkeyset; j++) {
|
||||
|
||||
k = &key_set[j];
|
||||
|
||||
if (k->key.keytype == enctypes[i]) {
|
||||
if (no_salt)
|
||||
break;
|
||||
if (k->salt == NULL && salt.salttype == KRB5_PW_SALT)
|
||||
break;
|
||||
if (k->salt->type == salt.salttype &&
|
||||
k->salt->salt.length == salt.saltvalue.length &&
|
||||
memcmp(k->salt->salt.data, salt.saltvalue.data,
|
||||
salt.saltvalue.length) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* not a duplicate, lets add it */
|
||||
if (j == *nkeyset) {
|
||||
ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i],
|
||||
no_salt ? NULL : &salt);
|
||||
if (ret) {
|
||||
free(enctypes);
|
||||
krb5_free_salt(context, salt);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(enctypes);
|
||||
krb5_free_salt(context, salt);
|
||||
}
|
||||
|
||||
*ret_key_set = key_set;
|
||||
|
||||
out:
|
||||
if (ktypes != default_keytypes)
|
||||
krb5_config_free_strings(ktypes);
|
||||
|
||||
if (ret) {
|
||||
krb5_warn(context, ret,
|
||||
"failed to parse the [kadmin]default_keys values");
|
||||
|
||||
for (i = 0; i < *nkeyset; i++)
|
||||
free_Key(&key_set[i]);
|
||||
free(key_set);
|
||||
} else if (*nkeyset == 0) {
|
||||
krb5_warnx(context,
|
||||
"failed to parse any of the [kadmin]default_keys values");
|
||||
ret = EINVAL; /* XXX */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
krb5_error_code
|
||||
hdb_generate_key_set_password(krb5_context context,
|
||||
krb5_principal principal,
|
||||
const char *password,
|
||||
Key **keys, size_t *num_keys)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
int i;
|
||||
|
||||
ret = hdb_generate_key_set(context, principal,
|
||||
keys, num_keys, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < (*num_keys); i++) {
|
||||
krb5_salt salt;
|
||||
|
||||
salt.salttype = (*keys)[i].salt->type;
|
||||
salt.saltvalue.length = (*keys)[i].salt->salt.length;
|
||||
salt.saltvalue.data = (*keys)[i].salt->salt.data;
|
||||
|
||||
ret = krb5_string_to_key_salt (context,
|
||||
(*keys)[i].key.keytype,
|
||||
password,
|
||||
salt,
|
||||
&(*keys)[i].key);
|
||||
|
||||
if(ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if(ret) {
|
||||
hdb_free_keys (context, *num_keys, *keys);
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hdb_locl.h"
|
||||
|
||||
/* keytab backend for HDB databases */
|
||||
|
||||
RCSID("$Id: keytab.c,v 1.16 2006/10/09 12:36:40 lha Exp $");
|
||||
|
||||
struct hdb_data {
|
||||
char *dbname;
|
||||
char *mkey;
|
||||
};
|
||||
|
||||
/*
|
||||
* the format for HDB keytabs is:
|
||||
* HDB:[database:file:mkey]
|
||||
*/
|
||||
|
||||
static krb5_error_code
|
||||
hdb_resolve(krb5_context context, const char *name, krb5_keytab id)
|
||||
{
|
||||
struct hdb_data *d;
|
||||
const char *db, *mkey;
|
||||
|
||||
d = malloc(sizeof(*d));
|
||||
if(d == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
db = name;
|
||||
mkey = strrchr(name, ':');
|
||||
if(mkey == NULL || mkey[1] == '\0') {
|
||||
if(*name == '\0')
|
||||
d->dbname = NULL;
|
||||
else {
|
||||
d->dbname = strdup(name);
|
||||
if(d->dbname == NULL) {
|
||||
free(d);
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
d->mkey = NULL;
|
||||
} else {
|
||||
if((mkey - db) == 0) {
|
||||
d->dbname = NULL;
|
||||
} else {
|
||||
d->dbname = malloc(mkey - db + 1);
|
||||
if(d->dbname == NULL) {
|
||||
free(d);
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
memmove(d->dbname, db, mkey - db);
|
||||
d->dbname[mkey - db] = '\0';
|
||||
}
|
||||
d->mkey = strdup(mkey + 1);
|
||||
if(d->mkey == NULL) {
|
||||
free(d->dbname);
|
||||
free(d);
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
id->data = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
hdb_close(krb5_context context, krb5_keytab id)
|
||||
{
|
||||
struct hdb_data *d = id->data;
|
||||
|
||||
free(d->dbname);
|
||||
free(d->mkey);
|
||||
free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
hdb_get_name(krb5_context context,
|
||||
krb5_keytab id,
|
||||
char *name,
|
||||
size_t namesize)
|
||||
{
|
||||
struct hdb_data *d = id->data;
|
||||
|
||||
snprintf(name, namesize, "%s%s%s",
|
||||
d->dbname ? d->dbname : "",
|
||||
(d->dbname || d->mkey) ? ":" : "",
|
||||
d->mkey ? d->mkey : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_config (krb5_context context,
|
||||
const krb5_config_binding *binding,
|
||||
const char **dbname,
|
||||
const char **mkey)
|
||||
{
|
||||
*dbname = krb5_config_get_string(context, binding, "dbname", NULL);
|
||||
*mkey = krb5_config_get_string(context, binding, "mkey_file", NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* try to figure out the database (`dbname') and master-key (`mkey')
|
||||
* that should be used for `principal'.
|
||||
*/
|
||||
|
||||
static void
|
||||
find_db (krb5_context context,
|
||||
const char **dbname,
|
||||
const char **mkey,
|
||||
krb5_const_principal principal)
|
||||
{
|
||||
const krb5_config_binding *top_bind = NULL;
|
||||
const krb5_config_binding *default_binding = NULL;
|
||||
const krb5_config_binding *db;
|
||||
krb5_realm *prealm = krb5_princ_realm(context, rk_UNCONST(principal));
|
||||
|
||||
*dbname = *mkey = NULL;
|
||||
|
||||
while ((db =
|
||||
krb5_config_get_next(context,
|
||||
NULL,
|
||||
&top_bind,
|
||||
krb5_config_list,
|
||||
"kdc",
|
||||
"database",
|
||||
NULL)) != NULL) {
|
||||
const char *p;
|
||||
|
||||
p = krb5_config_get_string (context, db, "realm", NULL);
|
||||
if (p == NULL) {
|
||||
if(default_binding) {
|
||||
krb5_warnx(context, "WARNING: more than one realm-less "
|
||||
"database specification");
|
||||
krb5_warnx(context, "WARNING: using the first encountered");
|
||||
} else
|
||||
default_binding = db;
|
||||
} else if (strcmp (*prealm, p) == 0) {
|
||||
set_config (context, db, dbname, mkey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*dbname == NULL && default_binding != NULL)
|
||||
set_config (context, default_binding, dbname, mkey);
|
||||
if (*dbname == NULL)
|
||||
*dbname = HDB_DEFAULT_DB;
|
||||
}
|
||||
|
||||
/*
|
||||
* find the keytab entry in `id' for `principal, kvno, enctype' and return
|
||||
* it in `entry'. return 0 or an error code
|
||||
*/
|
||||
|
||||
static krb5_error_code
|
||||
hdb_get_entry(krb5_context context,
|
||||
krb5_keytab id,
|
||||
krb5_const_principal principal,
|
||||
krb5_kvno kvno,
|
||||
krb5_enctype enctype,
|
||||
krb5_keytab_entry *entry)
|
||||
{
|
||||
hdb_entry_ex ent;
|
||||
krb5_error_code ret;
|
||||
struct hdb_data *d = id->data;
|
||||
int i;
|
||||
HDB *db;
|
||||
const char *dbname = d->dbname;
|
||||
const char *mkey = d->mkey;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
|
||||
if (dbname == NULL)
|
||||
find_db (context, &dbname, &mkey, principal);
|
||||
|
||||
ret = hdb_create (context, &db, dbname);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = hdb_set_master_keyfile (context, db, mkey);
|
||||
if (ret) {
|
||||
(*db->hdb_destroy)(context, db);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = (*db->hdb_open)(context, db, O_RDONLY, 0);
|
||||
if (ret) {
|
||||
(*db->hdb_destroy)(context, db);
|
||||
return ret;
|
||||
}
|
||||
ret = (*db->hdb_fetch)(context, db, principal,
|
||||
HDB_F_DECRYPT|
|
||||
HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
|
||||
&ent);
|
||||
|
||||
if(ret == HDB_ERR_NOENTRY) {
|
||||
ret = KRB5_KT_NOTFOUND;
|
||||
goto out;
|
||||
}else if(ret)
|
||||
goto out;
|
||||
|
||||
if(kvno && ent.entry.kvno != kvno) {
|
||||
hdb_free_entry(context, &ent);
|
||||
ret = KRB5_KT_NOTFOUND;
|
||||
goto out;
|
||||
}
|
||||
if(enctype == 0)
|
||||
if(ent.entry.keys.len > 0)
|
||||
enctype = ent.entry.keys.val[0].key.keytype;
|
||||
ret = KRB5_KT_NOTFOUND;
|
||||
for(i = 0; i < ent.entry.keys.len; i++) {
|
||||
if(ent.entry.keys.val[i].key.keytype == enctype) {
|
||||
krb5_copy_principal(context, principal, &entry->principal);
|
||||
entry->vno = ent.entry.kvno;
|
||||
krb5_copy_keyblock_contents(context,
|
||||
&ent.entry.keys.val[i].key,
|
||||
&entry->keyblock);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hdb_free_entry(context, &ent);
|
||||
out:
|
||||
(*db->hdb_close)(context, db);
|
||||
(*db->hdb_destroy)(context, db);
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_kt_ops hdb_kt_ops = {
|
||||
"HDB",
|
||||
hdb_resolve,
|
||||
hdb_get_name,
|
||||
hdb_close,
|
||||
hdb_get_entry,
|
||||
NULL, /* start_seq_get */
|
||||
NULL, /* next_entry */
|
||||
NULL, /* end_seq_get */
|
||||
NULL, /* add */
|
||||
NULL /* remove */
|
||||
};
|
||||
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hdb_locl.h"
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
RCSID("$Id: mkey.c,v 1.22 2006/05/05 10:27:59 lha Exp $");
|
||||
|
||||
struct hdb_master_key_data {
|
||||
krb5_keytab_entry keytab;
|
||||
krb5_crypto crypto;
|
||||
struct hdb_master_key_data *next;
|
||||
};
|
||||
|
||||
void
|
||||
hdb_free_master_key(krb5_context context, hdb_master_key mkey)
|
||||
{
|
||||
struct hdb_master_key_data *ptr;
|
||||
while(mkey) {
|
||||
krb5_kt_free_entry(context, &mkey->keytab);
|
||||
if (mkey->crypto)
|
||||
krb5_crypto_destroy(context, mkey->crypto);
|
||||
ptr = mkey;
|
||||
mkey = mkey->next;
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_process_master_key(krb5_context context,
|
||||
int kvno, krb5_keyblock *key, krb5_enctype etype,
|
||||
hdb_master_key *mkey)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
*mkey = calloc(1, sizeof(**mkey));
|
||||
if(*mkey == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
(*mkey)->keytab.vno = kvno;
|
||||
ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
|
||||
if(ret)
|
||||
goto fail;
|
||||
ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
|
||||
if(ret)
|
||||
goto fail;
|
||||
if(etype != 0)
|
||||
(*mkey)->keytab.keyblock.keytype = etype;
|
||||
(*mkey)->keytab.timestamp = time(NULL);
|
||||
ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
|
||||
if(ret)
|
||||
goto fail;
|
||||
return 0;
|
||||
fail:
|
||||
hdb_free_master_key(context, *mkey);
|
||||
*mkey = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_add_master_key(krb5_context context, krb5_keyblock *key,
|
||||
hdb_master_key *inout)
|
||||
{
|
||||
int vno = 0;
|
||||
hdb_master_key p;
|
||||
krb5_error_code ret;
|
||||
|
||||
for(p = *inout; p; p = p->next)
|
||||
vno = max(vno, p->keytab.vno);
|
||||
vno++;
|
||||
ret = hdb_process_master_key(context, vno, key, 0, &p);
|
||||
if(ret)
|
||||
return ret;
|
||||
p->next = *inout;
|
||||
*inout = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
read_master_keytab(krb5_context context, const char *filename,
|
||||
hdb_master_key *mkey)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_keytab id;
|
||||
krb5_kt_cursor cursor;
|
||||
krb5_keytab_entry entry;
|
||||
hdb_master_key p;
|
||||
|
||||
ret = krb5_kt_resolve(context, filename, &id);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
ret = krb5_kt_start_seq_get(context, id, &cursor);
|
||||
if(ret)
|
||||
goto out;
|
||||
*mkey = NULL;
|
||||
while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) {
|
||||
p = calloc(1, sizeof(*p));
|
||||
p->keytab = entry;
|
||||
ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto);
|
||||
p->next = *mkey;
|
||||
*mkey = p;
|
||||
}
|
||||
krb5_kt_end_seq_get(context, id, &cursor);
|
||||
out:
|
||||
krb5_kt_close(context, id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read a MIT master keyfile */
|
||||
static krb5_error_code
|
||||
read_master_mit(krb5_context context, const char *filename,
|
||||
hdb_master_key *mkey)
|
||||
{
|
||||
int fd;
|
||||
krb5_error_code ret;
|
||||
krb5_storage *sp;
|
||||
int16_t enctype;
|
||||
krb5_keyblock key;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if(fd < 0) {
|
||||
int save_errno = errno;
|
||||
krb5_set_error_string(context, "failed to open %s: %s", filename,
|
||||
strerror(save_errno));
|
||||
return save_errno;
|
||||
}
|
||||
sp = krb5_storage_from_fd(fd);
|
||||
if(sp == NULL) {
|
||||
close(fd);
|
||||
return errno;
|
||||
}
|
||||
krb5_storage_set_flags(sp, KRB5_STORAGE_HOST_BYTEORDER);
|
||||
#if 0
|
||||
/* could possibly use ret_keyblock here, but do it with more
|
||||
checks for now */
|
||||
ret = krb5_ret_keyblock(sp, &key);
|
||||
#else
|
||||
ret = krb5_ret_int16(sp, &enctype);
|
||||
if((htons(enctype) & 0xff00) == 0x3000) {
|
||||
krb5_set_error_string(context, "unknown keytype in %s: %#x, expected %#x",
|
||||
filename, htons(enctype), 0x3000);
|
||||
ret = HEIM_ERR_BAD_MKEY;
|
||||
goto out;
|
||||
}
|
||||
key.keytype = enctype;
|
||||
ret = krb5_ret_data(sp, &key.keyvalue);
|
||||
if(ret)
|
||||
goto out;
|
||||
#endif
|
||||
ret = hdb_process_master_key(context, 0, &key, 0, mkey);
|
||||
krb5_free_keyblock_contents(context, &key);
|
||||
out:
|
||||
krb5_storage_free(sp);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read an old master key file */
|
||||
static krb5_error_code
|
||||
read_master_encryptionkey(krb5_context context, const char *filename,
|
||||
hdb_master_key *mkey)
|
||||
{
|
||||
int fd;
|
||||
krb5_keyblock key;
|
||||
krb5_error_code ret;
|
||||
unsigned char buf[256];
|
||||
ssize_t len;
|
||||
size_t ret_len;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if(fd < 0) {
|
||||
int save_errno = errno;
|
||||
krb5_set_error_string(context, "failed to open %s: %s",
|
||||
filename, strerror(save_errno));
|
||||
return save_errno;
|
||||
}
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if(len < 0) {
|
||||
int save_errno = errno;
|
||||
krb5_set_error_string(context, "error reading %s: %s",
|
||||
filename, strerror(save_errno));
|
||||
return save_errno;
|
||||
}
|
||||
|
||||
ret = decode_EncryptionKey(buf, len, &key, &ret_len);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
/* Originally, the keytype was just that, and later it got changed
|
||||
to des-cbc-md5, but we always used des in cfb64 mode. This
|
||||
should cover all cases, but will break if someone has hacked
|
||||
this code to really use des-cbc-md5 -- but then that's not my
|
||||
problem. */
|
||||
if(key.keytype == KEYTYPE_DES || key.keytype == ETYPE_DES_CBC_MD5)
|
||||
key.keytype = ETYPE_DES_CFB64_NONE;
|
||||
|
||||
ret = hdb_process_master_key(context, 0, &key, 0, mkey);
|
||||
krb5_free_keyblock_contents(context, &key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read a krb4 /.k style file */
|
||||
static krb5_error_code
|
||||
read_master_krb4(krb5_context context, const char *filename,
|
||||
hdb_master_key *mkey)
|
||||
{
|
||||
int fd;
|
||||
krb5_keyblock key;
|
||||
krb5_error_code ret;
|
||||
unsigned char buf[256];
|
||||
ssize_t len;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if(fd < 0) {
|
||||
int save_errno = errno;
|
||||
krb5_set_error_string(context, "failed to open %s: %s",
|
||||
filename, strerror(save_errno));
|
||||
return save_errno;
|
||||
}
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if(len < 0) {
|
||||
int save_errno = errno;
|
||||
krb5_set_error_string(context, "error reading %s: %s",
|
||||
filename, strerror(save_errno));
|
||||
return save_errno;
|
||||
}
|
||||
if(len != 8) {
|
||||
krb5_set_error_string(context, "bad contents of %s", filename);
|
||||
return HEIM_ERR_EOF; /* XXX file might be too large */
|
||||
}
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.keytype = ETYPE_DES_PCBC_NONE;
|
||||
ret = krb5_data_copy(&key.keyvalue, buf, len);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
ret = hdb_process_master_key(context, 0, &key, 0, mkey);
|
||||
krb5_free_keyblock_contents(context, &key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_read_master_key(krb5_context context, const char *filename,
|
||||
hdb_master_key *mkey)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned char buf[16];
|
||||
krb5_error_code ret;
|
||||
|
||||
off_t len;
|
||||
|
||||
*mkey = NULL;
|
||||
|
||||
if(filename == NULL)
|
||||
filename = HDB_DB_DIR "/m-key";
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if(f == NULL) {
|
||||
int save_errno = errno;
|
||||
krb5_set_error_string(context, "failed to open %s: %s",
|
||||
filename, strerror(save_errno));
|
||||
return save_errno;
|
||||
}
|
||||
|
||||
if(fread(buf, 1, 2, f) != 2) {
|
||||
krb5_set_error_string(context, "end of file reading %s", filename);
|
||||
fclose(f);
|
||||
return HEIM_ERR_EOF;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
|
||||
if(fclose(f) != 0)
|
||||
return errno;
|
||||
|
||||
if(len < 0)
|
||||
return errno;
|
||||
|
||||
if(len == 8) {
|
||||
ret = read_master_krb4(context, filename, mkey);
|
||||
} else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) {
|
||||
ret = read_master_encryptionkey(context, filename, mkey);
|
||||
} else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) {
|
||||
ret = read_master_keytab(context, filename, mkey);
|
||||
} else {
|
||||
ret = read_master_mit(context, filename, mkey);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_write_master_key(krb5_context context, const char *filename,
|
||||
hdb_master_key mkey)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
hdb_master_key p;
|
||||
krb5_keytab kt;
|
||||
|
||||
if(filename == NULL)
|
||||
filename = HDB_DB_DIR "/m-key";
|
||||
|
||||
ret = krb5_kt_resolve(context, filename, &kt);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
for(p = mkey; p; p = p->next) {
|
||||
ret = krb5_kt_add_entry(context, kt, &p->keytab);
|
||||
}
|
||||
|
||||
krb5_kt_close(context, kt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdb_master_key
|
||||
_hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey)
|
||||
{
|
||||
hdb_master_key ret = NULL;
|
||||
while(mkey) {
|
||||
if(ret == NULL && mkey->keytab.vno == 0)
|
||||
ret = mkey;
|
||||
if(mkvno == NULL) {
|
||||
if(ret == NULL || mkey->keytab.vno > ret->keytab.vno)
|
||||
ret = mkey;
|
||||
} else if(mkey->keytab.vno == *mkvno)
|
||||
return mkey;
|
||||
mkey = mkey->next;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
_hdb_mkey_version(hdb_master_key mkey)
|
||||
{
|
||||
return mkey->keytab.vno;
|
||||
}
|
||||
|
||||
int
|
||||
_hdb_mkey_decrypt(krb5_context context, hdb_master_key key,
|
||||
krb5_key_usage usage,
|
||||
void *ptr, size_t size, krb5_data *res)
|
||||
{
|
||||
return krb5_decrypt(context, key->crypto, usage,
|
||||
ptr, size, res);
|
||||
}
|
||||
|
||||
int
|
||||
_hdb_mkey_encrypt(krb5_context context, hdb_master_key key,
|
||||
krb5_key_usage usage,
|
||||
const void *ptr, size_t size, krb5_data *res)
|
||||
{
|
||||
return krb5_encrypt(context, key->crypto, usage,
|
||||
ptr, size, res);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
|
||||
{
|
||||
|
||||
krb5_error_code ret;
|
||||
krb5_data res;
|
||||
size_t keysize;
|
||||
|
||||
hdb_master_key key;
|
||||
|
||||
if(k->mkvno == NULL)
|
||||
return 0;
|
||||
|
||||
key = _hdb_find_master_key(k->mkvno, mkey);
|
||||
|
||||
if (key == NULL)
|
||||
return HDB_ERR_NO_MKEY;
|
||||
|
||||
ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
|
||||
k->key.keyvalue.data,
|
||||
k->key.keyvalue.length,
|
||||
&res);
|
||||
if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
|
||||
/* try to decrypt with MIT key usage */
|
||||
ret = _hdb_mkey_decrypt(context, key, 0,
|
||||
k->key.keyvalue.data,
|
||||
k->key.keyvalue.length,
|
||||
&res);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* fixup keylength if the key got padded when encrypting it */
|
||||
ret = krb5_enctype_keysize(context, k->key.keytype, &keysize);
|
||||
if (ret) {
|
||||
krb5_data_free(&res);
|
||||
return ret;
|
||||
}
|
||||
if (keysize > res.length) {
|
||||
krb5_data_free(&res);
|
||||
return KRB5_BAD_KEYSIZE;
|
||||
}
|
||||
|
||||
memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
|
||||
free(k->key.keyvalue.data);
|
||||
k->key.keyvalue = res;
|
||||
k->key.keyvalue.length = keysize;
|
||||
free(k->mkvno);
|
||||
k->mkvno = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < ent->keys.len; i++){
|
||||
krb5_error_code ret;
|
||||
|
||||
ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
|
||||
{
|
||||
if (db->hdb_master_key_set == 0)
|
||||
return 0;
|
||||
return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_unseal_key(krb5_context context, HDB *db, Key *k)
|
||||
{
|
||||
if (db->hdb_master_key_set == 0)
|
||||
return 0;
|
||||
return hdb_unseal_key_mkey(context, k, db->hdb_master_key);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_data res;
|
||||
hdb_master_key key;
|
||||
|
||||
if(k->mkvno != NULL)
|
||||
return 0;
|
||||
|
||||
key = _hdb_find_master_key(k->mkvno, mkey);
|
||||
|
||||
if (key == NULL)
|
||||
return HDB_ERR_NO_MKEY;
|
||||
|
||||
ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY,
|
||||
k->key.keyvalue.data,
|
||||
k->key.keyvalue.length,
|
||||
&res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
|
||||
free(k->key.keyvalue.data);
|
||||
k->key.keyvalue = res;
|
||||
|
||||
if (k->mkvno == NULL) {
|
||||
k->mkvno = malloc(sizeof(*k->mkvno));
|
||||
if (k->mkvno == NULL)
|
||||
return ENOMEM;
|
||||
}
|
||||
*k->mkvno = key->keytab.vno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < ent->keys.len; i++){
|
||||
krb5_error_code ret;
|
||||
|
||||
ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent)
|
||||
{
|
||||
if (db->hdb_master_key_set == 0)
|
||||
return 0;
|
||||
|
||||
return hdb_seal_keys_mkey(context, ent, db->hdb_master_key);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_seal_key(krb5_context context, HDB *db, Key *k)
|
||||
{
|
||||
if (db->hdb_master_key_set == 0)
|
||||
return 0;
|
||||
|
||||
return hdb_seal_key_mkey(context, k, db->hdb_master_key);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_set_master_key (krb5_context context,
|
||||
HDB *db,
|
||||
krb5_keyblock *key)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
hdb_master_key mkey;
|
||||
|
||||
ret = hdb_process_master_key(context, 0, key, 0, &mkey);
|
||||
if (ret)
|
||||
return ret;
|
||||
db->hdb_master_key = mkey;
|
||||
#if 0 /* XXX - why? */
|
||||
des_set_random_generator_seed(key.keyvalue.data);
|
||||
#endif
|
||||
db->hdb_master_key_set = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_set_master_keyfile (krb5_context context,
|
||||
HDB *db,
|
||||
const char *keyfile)
|
||||
{
|
||||
hdb_master_key key;
|
||||
krb5_error_code ret;
|
||||
|
||||
ret = hdb_read_master_key(context, keyfile, &key);
|
||||
if (ret) {
|
||||
if (ret != ENOENT)
|
||||
return ret;
|
||||
krb5_clear_error_string(context);
|
||||
return 0;
|
||||
}
|
||||
db->hdb_master_key = key;
|
||||
db->hdb_master_key_set = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_clear_master_key (krb5_context context,
|
||||
HDB *db)
|
||||
{
|
||||
if (db->hdb_master_key_set) {
|
||||
hdb_free_master_key(context, db->hdb_master_key);
|
||||
db->hdb_master_key_set = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hdb_locl.h"
|
||||
|
||||
RCSID("$Id: ndbm.c,v 1.38 2005/12/13 11:54:10 lha Exp $");
|
||||
|
||||
#if HAVE_NDBM
|
||||
|
||||
#if defined(HAVE_GDBM_NDBM_H)
|
||||
#include <gdbm/ndbm.h>
|
||||
#elif defined(HAVE_NDBM_H)
|
||||
#include <ndbm.h>
|
||||
#elif defined(HAVE_DBM_H)
|
||||
#include <dbm.h>
|
||||
#endif
|
||||
|
||||
struct ndbm_db {
|
||||
DBM *db;
|
||||
int lock_fd;
|
||||
};
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_destroy(krb5_context context, HDB *db)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
ret = hdb_clear_master_key (context, db);
|
||||
free(db->hdb_name);
|
||||
free(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_lock(krb5_context context, HDB *db, int operation)
|
||||
{
|
||||
struct ndbm_db *d = db->hdb_db;
|
||||
return hdb_lock(d->lock_fd, operation);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_unlock(krb5_context context, HDB *db)
|
||||
{
|
||||
struct ndbm_db *d = db->hdb_db;
|
||||
return hdb_unlock(d->lock_fd);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_seq(krb5_context context, HDB *db,
|
||||
unsigned flags, hdb_entry_ex *entry, int first)
|
||||
|
||||
{
|
||||
struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
|
||||
datum key, value;
|
||||
krb5_data key_data, data;
|
||||
krb5_error_code ret = 0;
|
||||
|
||||
if(first)
|
||||
key = dbm_firstkey(d->db);
|
||||
else
|
||||
key = dbm_nextkey(d->db);
|
||||
if(key.dptr == NULL)
|
||||
return HDB_ERR_NOENTRY;
|
||||
key_data.data = key.dptr;
|
||||
key_data.length = key.dsize;
|
||||
ret = db->hdb_lock(context, db, HDB_RLOCK);
|
||||
if(ret) return ret;
|
||||
value = dbm_fetch(d->db, key);
|
||||
db->hdb_unlock(context, db);
|
||||
data.data = value.dptr;
|
||||
data.length = value.dsize;
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
if(hdb_value2entry(context, &data, &entry->entry))
|
||||
return NDBM_seq(context, db, flags, entry, 0);
|
||||
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
|
||||
ret = hdb_unseal_keys (context, db, &entry->entry);
|
||||
if (ret)
|
||||
hdb_free_entry (context, entry);
|
||||
}
|
||||
if (ret == 0 && entry->entry.principal == NULL) {
|
||||
entry->entry.principal = malloc (sizeof(*entry->entry.principal));
|
||||
if (entry->entry.principal == NULL) {
|
||||
ret = ENOMEM;
|
||||
hdb_free_entry (context, entry);
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
} else {
|
||||
hdb_key2principal (context, &key_data, entry->entry.principal);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry_ex *entry)
|
||||
{
|
||||
return NDBM_seq(context, db, flags, entry, 1);
|
||||
}
|
||||
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry_ex *entry)
|
||||
{
|
||||
return NDBM_seq(context, db, flags, entry, 0);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_rename(krb5_context context, HDB *db, const char *new_name)
|
||||
{
|
||||
/* XXX this function will break */
|
||||
struct ndbm_db *d = db->hdb_db;
|
||||
|
||||
int ret;
|
||||
char *old_dir, *old_pag, *new_dir, *new_pag;
|
||||
char *new_lock;
|
||||
int lock_fd;
|
||||
|
||||
/* lock old and new databases */
|
||||
ret = db->hdb_lock(context, db, HDB_WLOCK);
|
||||
if(ret)
|
||||
return ret;
|
||||
asprintf(&new_lock, "%s.lock", new_name);
|
||||
if(new_lock == NULL) {
|
||||
db->hdb_unlock(context, db);
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600);
|
||||
if(lock_fd < 0) {
|
||||
ret = errno;
|
||||
db->hdb_unlock(context, db);
|
||||
krb5_set_error_string(context, "open(%s): %s", new_lock,
|
||||
strerror(ret));
|
||||
free(new_lock);
|
||||
return ret;
|
||||
}
|
||||
free(new_lock);
|
||||
ret = hdb_lock(lock_fd, HDB_WLOCK);
|
||||
if(ret) {
|
||||
db->hdb_unlock(context, db);
|
||||
close(lock_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
asprintf(&old_dir, "%s.dir", db->hdb_name);
|
||||
asprintf(&old_pag, "%s.pag", db->hdb_name);
|
||||
asprintf(&new_dir, "%s.dir", new_name);
|
||||
asprintf(&new_pag, "%s.pag", new_name);
|
||||
|
||||
ret = rename(old_dir, new_dir) || rename(old_pag, new_pag);
|
||||
free(old_dir);
|
||||
free(old_pag);
|
||||
free(new_dir);
|
||||
free(new_pag);
|
||||
hdb_unlock(lock_fd);
|
||||
db->hdb_unlock(context, db);
|
||||
|
||||
if(ret) {
|
||||
ret = errno;
|
||||
close(lock_fd);
|
||||
krb5_set_error_string(context, "rename: %s", strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
close(d->lock_fd);
|
||||
d->lock_fd = lock_fd;
|
||||
|
||||
free(db->hdb_name);
|
||||
db->hdb_name = strdup(new_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
|
||||
{
|
||||
struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
|
||||
datum k, v;
|
||||
int code;
|
||||
|
||||
k.dptr = key.data;
|
||||
k.dsize = key.length;
|
||||
code = db->hdb_lock(context, db, HDB_RLOCK);
|
||||
if(code)
|
||||
return code;
|
||||
v = dbm_fetch(d->db, k);
|
||||
db->hdb_unlock(context, db);
|
||||
if(v.dptr == NULL)
|
||||
return HDB_ERR_NOENTRY;
|
||||
|
||||
krb5_data_copy(reply, v.dptr, v.dsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM__put(krb5_context context, HDB *db, int replace,
|
||||
krb5_data key, krb5_data value)
|
||||
{
|
||||
struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
|
||||
datum k, v;
|
||||
int code;
|
||||
|
||||
k.dptr = key.data;
|
||||
k.dsize = key.length;
|
||||
v.dptr = value.data;
|
||||
v.dsize = value.length;
|
||||
|
||||
code = db->hdb_lock(context, db, HDB_WLOCK);
|
||||
if(code)
|
||||
return code;
|
||||
code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT);
|
||||
db->hdb_unlock(context, db);
|
||||
if(code == 1)
|
||||
return HDB_ERR_EXISTS;
|
||||
if (code < 0)
|
||||
return code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM__del(krb5_context context, HDB *db, krb5_data key)
|
||||
{
|
||||
struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
|
||||
datum k;
|
||||
int code;
|
||||
krb5_error_code ret;
|
||||
|
||||
k.dptr = key.data;
|
||||
k.dsize = key.length;
|
||||
ret = db->hdb_lock(context, db, HDB_WLOCK);
|
||||
if(ret) return ret;
|
||||
code = dbm_delete(d->db, k);
|
||||
db->hdb_unlock(context, db);
|
||||
if(code < 0)
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_close(krb5_context context, HDB *db)
|
||||
{
|
||||
struct ndbm_db *d = db->hdb_db;
|
||||
dbm_close(d->db);
|
||||
close(d->lock_fd);
|
||||
free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
struct ndbm_db *d = malloc(sizeof(*d));
|
||||
char *lock_file;
|
||||
|
||||
if(d == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
asprintf(&lock_file, "%s.lock", (char*)db->hdb_name);
|
||||
if(lock_file == NULL) {
|
||||
free(d);
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
d->db = dbm_open((char*)db->hdb_name, flags, mode);
|
||||
if(d->db == NULL){
|
||||
ret = errno;
|
||||
free(d);
|
||||
free(lock_file);
|
||||
krb5_set_error_string(context, "dbm_open(%s): %s", db->hdb_name,
|
||||
strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600);
|
||||
if(d->lock_fd < 0){
|
||||
ret = errno;
|
||||
dbm_close(d->db);
|
||||
free(d);
|
||||
krb5_set_error_string(context, "open(%s): %s", lock_file,
|
||||
strerror(ret));
|
||||
free(lock_file);
|
||||
return ret;
|
||||
}
|
||||
free(lock_file);
|
||||
db->hdb_db = d;
|
||||
if((flags & O_ACCMODE) == O_RDONLY)
|
||||
ret = hdb_check_db_format(context, db);
|
||||
else
|
||||
ret = hdb_init_db(context, db);
|
||||
if(ret == HDB_ERR_NOENTRY)
|
||||
return 0;
|
||||
if (ret) {
|
||||
NDBM_close(context, db);
|
||||
krb5_set_error_string(context, "hdb_open: failed %s database %s",
|
||||
(flags & O_ACCMODE) == O_RDONLY ?
|
||||
"checking format of" : "initialize",
|
||||
db->hdb_name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
hdb_ndbm_create(krb5_context context, HDB **db,
|
||||
const char *filename)
|
||||
{
|
||||
*db = calloc(1, sizeof(**db));
|
||||
if (*db == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
(*db)->hdb_db = NULL;
|
||||
(*db)->hdb_name = strdup(filename);
|
||||
if ((*db)->hdb_name == NULL) {
|
||||
krb5_set_error_string(context, "malloc: out of memory");
|
||||
free(*db);
|
||||
*db = NULL;
|
||||
return ENOMEM;
|
||||
}
|
||||
(*db)->hdb_master_key_set = 0;
|
||||
(*db)->hdb_openp = 0;
|
||||
(*db)->hdb_open = NDBM_open;
|
||||
(*db)->hdb_close = NDBM_close;
|
||||
(*db)->hdb_fetch = _hdb_fetch;
|
||||
(*db)->hdb_store = _hdb_store;
|
||||
(*db)->hdb_remove = _hdb_remove;
|
||||
(*db)->hdb_firstkey = NDBM_firstkey;
|
||||
(*db)->hdb_nextkey= NDBM_nextkey;
|
||||
(*db)->hdb_lock = NDBM_lock;
|
||||
(*db)->hdb_unlock = NDBM_unlock;
|
||||
(*db)->hdb_rename = NDBM_rename;
|
||||
(*db)->hdb__get = NDBM__get;
|
||||
(*db)->hdb__put = NDBM__put;
|
||||
(*db)->hdb__del = NDBM__del;
|
||||
(*db)->hdb_destroy = NDBM_destroy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_NDBM */
|
||||
Reference in New Issue
Block a user