wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+307
View File
@@ -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 */
+396
View File
@@ -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__ */
+327
View File
@@ -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__ */
+123
View File
@@ -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
+406
View File
@@ -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);
}
+163
View File
@@ -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__ */
+28
View File
@@ -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
+74
View File
@@ -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__ */
+393
View File
@@ -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;
}
+272
View File
@@ -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 */
};
+598
View File
@@ -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;
}
+370
View File
@@ -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 */