summaryrefslogtreecommitdiff
path: root/source4/kdc/mit-kdb
diff options
context:
space:
mode:
authorAndreas Schneider <asn@samba.org>2014-05-12 10:49:24 +0200
committerAndrew Bartlett <abartlet@samba.org>2016-03-17 04:32:28 +0100
commitade958e20b561b702e2fec86a28659144dbe4a9e (patch)
tree05714e9d40a0d0c2824bd378b6f09ddc66ef092c /source4/kdc/mit-kdb
parent7feb650a372094f2ecfa82e41756d5e2fa92ff9a (diff)
downloadsamba-ade958e20b561b702e2fec86a28659144dbe4a9e.tar.gz
mit-kdb: Add initial MIT KDB Samba driver
Signed-off-by: Andreas Schneider <asn@samba.org> Signed-off-by: Simo Sorce <idra@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Pair-Programmed-With: Simo Sorce <idra@samba.org> Reviewed-by: Sumit Bose <sbose@redhat.com> Reviewed-by: Guenther Deschner <gd@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source4/kdc/mit-kdb')
-rw-r--r--source4/kdc/mit-kdb/kdb_samba.c185
-rw-r--r--source4/kdc/mit-kdb/kdb_samba.h137
-rw-r--r--source4/kdc/mit-kdb/kdb_samba_common.c119
-rw-r--r--source4/kdc/mit-kdb/kdb_samba_masterkey.c66
-rw-r--r--source4/kdc/mit-kdb/kdb_samba_pac.c112
-rw-r--r--source4/kdc/mit-kdb/kdb_samba_policies.c437
-rw-r--r--source4/kdc/mit-kdb/kdb_samba_principals.c227
-rw-r--r--source4/kdc/mit-kdb/wscript_build21
8 files changed, 1304 insertions, 0 deletions
diff --git a/source4/kdc/mit-kdb/kdb_samba.c b/source4/kdc/mit-kdb/kdb_samba.c
new file mode 100644
index 00000000000..1f3fb7300ae
--- /dev/null
+++ b/source4/kdc/mit-kdb/kdb_samba.c
@@ -0,0 +1,185 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Samba KDB plugin for MIT Kerberos
+
+ Copyright (c) 2010 Simo Sorce <idra@samba.org>.
+ Copyright (c) 2014 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "system/kerberos.h"
+
+#include <profile.h>
+#include <kdb.h>
+
+#include "kdc/mit_samba.h"
+#include "kdb_samba.h"
+
+static krb5_error_code kdb_samba_init_library(void)
+{
+ return 0;
+}
+
+static krb5_error_code kdb_samba_fini_library(void)
+{
+ return 0;
+}
+
+static krb5_error_code kdb_samba_init_module(krb5_context context,
+ char *conf_section,
+ char **db_args,
+ int mode)
+{
+ /* TODO mit_samba_context_init */
+ struct mit_samba_context *mit_ctx;
+ krb5_error_code code;
+ int rc;
+
+ rc = mit_samba_context_init(&mit_ctx);
+ if (rc != 0) {
+ return ENOMEM;
+ }
+
+
+ code = krb5_db_set_context(context, mit_ctx);
+
+ return code;
+}
+static krb5_error_code kdb_samba_fini_module(krb5_context context)
+{
+ struct mit_samba_context *mit_ctx;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return 0;
+ }
+
+ mit_samba_context_free(mit_ctx);
+
+ return 0;
+}
+
+static krb5_error_code kdb_samba_db_create(krb5_context context,
+ char *conf_section,
+ char **db_args)
+{
+ /* NOTE: used only by kadmin */
+ return KRB5_KDB_DBTYPE_NOSUP;
+}
+
+static krb5_error_code kdb_samba_db_destroy(krb5_context context,
+ char *conf_section,
+ char **db_args)
+{
+ /* NOTE: used only by kadmin */
+ return KRB5_KDB_DBTYPE_NOSUP;
+}
+
+static krb5_error_code kdb_samba_db_get_age(krb5_context context,
+ char *db_name,
+ time_t *age)
+{
+ /* TODO: returns last modification time of the db */
+
+ /* NOTE: used by and affects only lookaside cache,
+ * defer implementation until needed as samba doesn't keep this
+ * specific value readily available and it would require a full
+ * database search to get it. */
+
+ *age = time(NULL);
+
+ return 0;
+}
+
+static krb5_error_code kdb_samba_db_lock(krb5_context context, int kmode)
+{
+
+ /* NOTE: important only for kadmin */
+ /* NOTE: deferred as samba's DB cannot be easily locked and doesn't
+ * really make sense to do so anyway as the db is shared and support
+ * transactions */
+ return 0;
+}
+
+static krb5_error_code kdb_samba_db_unlock(krb5_context context)
+{
+
+ /* NOTE: important only for kadmin */
+ /* NOTE: deferred as samba's DB cannot be easily locked and doesn't
+ * really make sense to do so anyway as the db is shared and support
+ * transactions */
+ return 0;
+}
+
+static void *kdb_samba_db_alloc(krb5_context context, void *ptr, size_t size)
+{
+ return realloc(ptr, size);
+}
+
+static void kdb_samba_db_free(krb5_context context, void *ptr)
+{
+ free(ptr);
+}
+
+kdb_vftabl kdb_function_table = {
+ KRB5_KDB_DAL_MAJOR_VERSION, /* major version number */
+ 0, /* minor version number */
+ kdb_samba_init_library, /* init_library */
+ kdb_samba_fini_library, /* fini_library */
+ kdb_samba_init_module, /* init_module */
+ kdb_samba_fini_module, /* fini_module */
+
+ kdb_samba_db_create, /* db_create */
+ kdb_samba_db_destroy, /* db_destroy */
+ kdb_samba_db_get_age, /* db_get_age */
+ kdb_samba_db_lock, /* db_lock */
+ kdb_samba_db_unlock, /* db_unlock */
+
+ kdb_samba_db_get_principal, /* db_get_principal */
+ kdb_samba_db_free_principal, /* db_free_principal */
+ kdb_samba_db_put_principal, /* db_put_principal */
+ kdb_samba_db_delete_principal, /* db_delete_principal */
+ kdb_samba_db_iterate, /* db_iterate */
+
+ NULL, /* create_policy */
+ NULL, /* get_policy */
+ NULL, /* put_policy */
+ NULL, /* iter_policy */
+ NULL, /* delete_policy */
+ NULL, /* free_policy */
+
+ kdb_samba_db_alloc, /* db_alloc */
+ kdb_samba_db_free, /* db_free */
+
+ kdb_samba_fetch_master_key, /* fetch_master_key */
+ kdb_samba_fetch_master_key_list, /* fetch_master_key_list */
+ NULL, /* store_master_key_list */
+ NULL, /* dbe_search_enctype */
+ NULL, /* change_pwd */
+ NULL, /* promote_db */
+ kdb_samba_dbekd_decrypt_key_data, /* decrypt_key_data */
+ kdb_samba_dbekd_encrypt_key_data, /* encrypt_key_data */
+
+ kdb_samba_db_sign_auth_data, /* sign_authdata */
+ NULL, /* check_transited_realms */
+ kdb_samba_db_check_policy_as, /* check_policy_as */
+ NULL, /* check_policy_tgs */
+ NULL, /* audit_as_req */
+ NULL, /* refresh_config */
+ kdb_samba_db_check_allowed_to_delegate
+};
diff --git a/source4/kdc/mit-kdb/kdb_samba.h b/source4/kdc/mit-kdb/kdb_samba.h
new file mode 100644
index 00000000000..89c628fff63
--- /dev/null
+++ b/source4/kdc/mit-kdb/kdb_samba.h
@@ -0,0 +1,137 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * plugins/kdb/samba/kdb_samba.h
+ *
+ * Copyright (c) 2009, Simo Sorce <idra@samba.org>
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#ifndef _KDB_SAMBA_H_
+#define _KDB_SAMBA_H_
+
+#include <stdbool.h>
+
+#include <krb5/krb5.h>
+#include <krb5/plugin.h>
+
+#define PAC_LOGON_INFO 1
+
+#ifndef discard_const_p
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* from kdb_samba_common.c */
+
+struct mit_samba_context *ks_get_context(krb5_context kcontext);
+
+void ks_free_krb5_db_entry(krb5_context context,
+ krb5_db_entry *entry);
+
+bool ks_data_eq_string(krb5_data d, const char *s);
+
+krb5_data ks_make_data(void *data, unsigned int len);
+
+/* from kdb_samba_principals.c */
+
+krb5_error_code kdb_samba_db_get_principal(krb5_context context,
+ krb5_const_principal princ,
+ unsigned int kflags,
+ krb5_db_entry **kentry);
+
+void kdb_samba_db_free_principal(krb5_context context,
+ krb5_db_entry *entry);
+
+krb5_error_code kdb_samba_db_put_principal(krb5_context context,
+ krb5_db_entry *entry,
+ char **db_args);
+
+krb5_error_code kdb_samba_db_delete_principal(krb5_context context,
+ krb5_const_principal princ);
+
+krb5_error_code kdb_samba_db_iterate(krb5_context context,
+ char *match_entry,
+ int (*func)(krb5_pointer, krb5_db_entry *),
+ krb5_pointer func_arg);
+
+/* from kdb_samba_masterkey.c */
+
+krb5_error_code kdb_samba_fetch_master_key(krb5_context context,
+ krb5_principal name,
+ krb5_keyblock *key,
+ krb5_kvno *kvno,
+ char *db_args);
+
+krb5_error_code kdb_samba_fetch_master_key_list(krb5_context context,
+ krb5_principal mname,
+ const krb5_keyblock *key,
+ krb5_keylist_node **mkeys_list);
+
+/* from kdb_samba_pac.c */
+
+krb5_error_code kdb_samba_dbekd_decrypt_key_data(krb5_context context,
+ const krb5_keyblock *mkey,
+ const krb5_key_data *key_data,
+ krb5_keyblock *kkey,
+ krb5_keysalt *keysalt);
+
+krb5_error_code kdb_samba_dbekd_encrypt_key_data(krb5_context context,
+ const krb5_keyblock *mkey,
+ const krb5_keyblock *kkey,
+ const krb5_keysalt *keysalt,
+ int keyver,
+ krb5_key_data *key_data);
+
+/* from kdb_samba_policies.c */
+
+krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
+ unsigned int flags,
+ krb5_const_principal client_princ,
+ krb5_db_entry *client,
+ krb5_db_entry *server,
+ krb5_db_entry *krbtgt,
+ krb5_keyblock *client_key,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_keyblock *session_key,
+ krb5_timestamp authtime,
+ krb5_authdata **tgt_auth_data,
+ krb5_authdata ***signed_auth_data);
+
+krb5_error_code kdb_samba_db_check_policy_as(krb5_context context,
+ krb5_kdc_req *kdcreq,
+ krb5_db_entry *client,
+ krb5_db_entry *server,
+ krb5_timestamp kdc_time,
+ const char **status,
+ krb5_pa_data ***e_data_out);
+
+krb5_error_code kdb_samba_db_check_allowed_to_delegate(krb5_context context,
+ krb5_const_principal client,
+ const krb5_db_entry *server,
+ krb5_const_principal proxy);
+
+#endif /* _KDB_SAMBA_H_ */
diff --git a/source4/kdc/mit-kdb/kdb_samba_common.c b/source4/kdc/mit-kdb/kdb_samba_common.c
new file mode 100644
index 00000000000..de94f03719b
--- /dev/null
+++ b/source4/kdc/mit-kdb/kdb_samba_common.c
@@ -0,0 +1,119 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Samba KDB plugin for MIT Kerberos
+
+ Copyright (c) 2010 Simo Sorce <idra@samba.org>.
+ Copyright (c) 2014 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "system/kerberos.h"
+
+#include <profile.h>
+#include <kdb.h>
+
+#include "kdc/mit_samba.h"
+#include "kdb_samba.h"
+
+struct mit_samba_context *ks_get_context(krb5_context kcontext)
+{
+ void *db_ctx;
+ krb5_error_code code;
+
+ code = krb5_db_get_context(kcontext, &db_ctx);
+ if (code != 0) {
+ return NULL;
+ }
+
+ return (struct mit_samba_context *)db_ctx;
+}
+
+void ks_free_krb5_db_entry(krb5_context context,
+ krb5_db_entry *entry)
+{
+ krb5_tl_data *tl_data_next = NULL;
+ krb5_tl_data *tl_data = NULL;
+ int i, j;
+
+ if (entry == NULL) {
+ return;
+ }
+
+#if 0 /* TODO FIXME do we have something to free? */
+ if (entry->e_data != NULL) {
+ /* FREE ME! */
+ }
+#endif
+
+ krb5_free_principal(context, entry->princ);
+
+ for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) {
+ tl_data_next = tl_data->tl_data_next;
+ if (tl_data->tl_data_contents != NULL)
+ free(tl_data->tl_data_contents);
+ free(tl_data);
+ }
+
+ if (entry->key_data != NULL) {
+ for (i = 0; i < entry->n_key_data; i++) {
+ for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+ if (entry->key_data[i].key_data_length[j] != 0) {
+ if (entry->key_data[i].key_data_contents[j] != NULL) {
+ memset(entry->key_data[i].key_data_contents[j],
+ 0,
+ entry->key_data[i].key_data_length[j]);
+ free(entry->key_data[i].key_data_contents[j]);
+ }
+ }
+ entry->key_data[i].key_data_contents[j] = NULL;
+ entry->key_data[i].key_data_length[j] = 0;
+ entry->key_data[i].key_data_type[j] = 0;
+ }
+ }
+ free(entry->key_data);
+ }
+
+ free(entry);
+}
+
+bool ks_data_eq_string(krb5_data d, const char *s)
+{
+ int rc;
+
+ if (d.length != strlen(s) || d.length == 0) {
+ return false;
+ }
+
+ rc = memcmp(d.data, s, d.length);
+ if (rc != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+krb5_data ks_make_data(void *data, unsigned int len)
+{
+ krb5_data d;
+
+ d.magic = KV5M_DATA;
+ d.data = data;
+ d.length = len;
+
+ return d;
+}
diff --git a/source4/kdc/mit-kdb/kdb_samba_masterkey.c b/source4/kdc/mit-kdb/kdb_samba_masterkey.c
new file mode 100644
index 00000000000..3de3868cac8
--- /dev/null
+++ b/source4/kdc/mit-kdb/kdb_samba_masterkey.c
@@ -0,0 +1,66 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Samba KDB plugin for MIT Kerberos
+
+ Copyright (c) 2010 Simo Sorce <idra@samba.org>.
+ Copyright (c) 2014 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+
+#include "system/kerberos.h"
+
+#include <profile.h>
+#include <kdb.h>
+
+#include "kdc/mit_samba.h"
+#include "kdb_samba.h"
+
+krb5_error_code kdb_samba_fetch_master_key(krb5_context context,
+ krb5_principal name,
+ krb5_keyblock *key,
+ krb5_kvno *kvno,
+ char *db_args)
+{
+ return 0;
+}
+
+krb5_error_code kdb_samba_fetch_master_key_list(krb5_context context,
+ krb5_principal mname,
+ const krb5_keyblock *key,
+ krb5_keylist_node **mkeys_list)
+{
+ krb5_keylist_node *mkey;
+
+ /*
+ * NOTE: samba does not support master keys
+ * so just return a dummy key
+ */
+ mkey = malloc(sizeof(krb5_keylist_node));
+ if (mkey == NULL) {
+ return ENOMEM;
+ }
+
+ mkey->keyblock.magic = KV5M_KEYBLOCK;
+ mkey->keyblock.enctype = ENCTYPE_UNKNOWN;
+ mkey->kvno = 1;
+
+ *mkeys_list = mkey;
+
+ return 0;
+}
diff --git a/source4/kdc/mit-kdb/kdb_samba_pac.c b/source4/kdc/mit-kdb/kdb_samba_pac.c
new file mode 100644
index 00000000000..0ab8c372e0e
--- /dev/null
+++ b/source4/kdc/mit-kdb/kdb_samba_pac.c
@@ -0,0 +1,112 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Samba KDB plugin for MIT Kerberos
+
+ Copyright (c) 2010 Simo Sorce <idra@samba.org>.
+ Copyright (c) 2014 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "system/kerberos.h"
+
+#include <profile.h>
+#include <kdb.h>
+
+#include "kdc/mit_samba.h"
+#include "kdb_samba.h"
+
+krb5_error_code kdb_samba_dbekd_decrypt_key_data(krb5_context context,
+ const krb5_keyblock *mkey,
+ const krb5_key_data *key_data,
+ krb5_keyblock *kkey,
+ krb5_keysalt *keysalt)
+{
+ /*
+ * NOTE: Samba doesn't use a master key, so we will just copy
+ * the contents around untouched.
+ */
+ ZERO_STRUCTP(kkey);
+
+ kkey->magic = KV5M_KEYBLOCK;
+ kkey->enctype = key_data->key_data_type[0];
+ kkey->contents = malloc(key_data->key_data_length[0]);
+ if (kkey->contents == NULL) {
+ return ENOMEM;
+ }
+ memcpy(kkey->contents,
+ key_data->key_data_contents[0],
+ key_data->key_data_length[0]);
+ kkey->length = key_data->key_data_length[0];
+
+ if (keysalt != NULL) {
+ keysalt->type = key_data->key_data_type[1];
+ keysalt->data.data = malloc(key_data->key_data_length[1]);
+ if (keysalt->data.data == NULL) {
+ free(kkey->contents);
+ return ENOMEM;
+ }
+ memcpy(keysalt->data.data,
+ key_data->key_data_contents[1],
+ key_data->key_data_length[1]);
+ keysalt->data.length = key_data->key_data_length[1];
+ }
+
+ return 0;
+}
+
+krb5_error_code kdb_samba_dbekd_encrypt_key_data(krb5_context context,
+ const krb5_keyblock *mkey,
+ const krb5_keyblock *kkey,
+ const krb5_keysalt *keysalt,
+ int keyver,
+ krb5_key_data *key_data)
+{
+ /*
+ * NOTE: samba doesn't use a master key, so we will just copy
+ * the contents around untouched.
+ */
+
+ ZERO_STRUCTP(key_data);
+
+ key_data->key_data_ver = KRB5_KDB_V1_KEY_DATA_ARRAY;
+ key_data->key_data_kvno = keyver;
+ key_data->key_data_type[0] = kkey->enctype;
+ key_data->key_data_contents[0] = malloc(kkey->length);
+ if (key_data->key_data_contents[0]) {
+ return ENOMEM;
+ }
+ memcpy(key_data->key_data_contents[0],
+ kkey->contents,
+ kkey->length);
+ key_data->key_data_length[0] = kkey->length;
+
+ if (keysalt != NULL) {
+ key_data->key_data_type[1] = keysalt->type;
+ key_data->key_data_contents[1] = malloc(keysalt->data.length);
+ if (key_data->key_data_contents[1] == NULL) {
+ free(key_data->key_data_contents[0]);
+ return ENOMEM;
+ }
+ memcpy(key_data->key_data_contents[1],
+ keysalt->data.data,
+ keysalt->data.length);
+ key_data->key_data_length[1] = keysalt->data.length;
+ }
+
+ return 0;
+}
diff --git a/source4/kdc/mit-kdb/kdb_samba_policies.c b/source4/kdc/mit-kdb/kdb_samba_policies.c
new file mode 100644
index 00000000000..75c8c837a27
--- /dev/null
+++ b/source4/kdc/mit-kdb/kdb_samba_policies.c
@@ -0,0 +1,437 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Samba KDB plugin for MIT Kerberos
+
+ Copyright (c) 2010 Simo Sorce <idra@samba.org>.
+ Copyright (c) 2014 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "system/kerberos.h"
+
+#include <profile.h>
+#include <kdb.h>
+
+#include "kdc/mit_samba.h"
+#include "kdb_samba.h"
+
+/* FIXME: This is a krb5 function which is exported, but in no header */
+extern krb5_error_code decode_krb5_padata_sequence(const krb5_data *output,
+ krb5_pa_data ***rep);
+
+static krb5_error_code ks_get_netbios_name(krb5_address **addrs, char **name)
+{
+ char *nb_name = NULL;
+ int len, i;
+
+ for (i = 0; addrs[i]; i++) {
+ if (addrs[i]->addrtype != ADDRTYPE_NETBIOS) {
+ continue;
+ }
+ len = MIN(addrs[i]->length, 15);
+ nb_name = strndup((const char *)addrs[i]->contents, len);
+ if (!nb_name) {
+ return ENOMEM;
+ }
+ break;
+ }
+
+ if (nb_name) {
+ /* Strip space padding */
+ i = strlen(nb_name) - 1;
+ for (i = strlen(nb_name) - 1;
+ i > 0 && nb_name[i] == ' ';
+ i--) {
+ nb_name[i] = '\0';
+ }
+ }
+
+ *name = nb_name;
+
+ return 0;
+}
+
+krb5_error_code kdb_samba_db_check_policy_as(krb5_context context,
+ krb5_kdc_req *kdcreq,
+ krb5_db_entry *client,
+ krb5_db_entry *server,
+ krb5_timestamp kdc_time,
+ const char **status,
+ krb5_pa_data ***e_data_out)
+{
+ struct mit_samba_context *mit_ctx;
+ krb5_error_code code;
+ char *client_name = NULL;
+ char *server_name = NULL;
+ char *netbios_name = NULL;
+ char *realm = NULL;
+ bool password_change = false;
+ DATA_BLOB int_data = { NULL, 0 };
+ krb5_data d;
+ krb5_pa_data **e_data;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ if (krb5_princ_size(context, kdcreq->server) == 2 &&
+ ks_is_kadmin_changepw(context, kdcreq->server)) {
+ code = krb5_get_default_realm(context, &realm);
+ if (code) {
+ goto done;
+ }
+
+ if (ks_data_eq_string(kdcreq->server->realm, realm)) {
+ password_change = true;
+ }
+ }
+
+ code = krb5_unparse_name(context, kdcreq->server, &server_name);
+ if (code) {
+ goto done;
+ }
+
+ code = krb5_unparse_name(context, kdcreq->client, &client_name);
+ if (code) {
+ goto done;
+ }
+
+ if (kdcreq->addresses) {
+ code = ks_get_netbios_name(kdcreq->addresses, &netbios_name);
+ if (code) {
+ goto done;
+ }
+ }
+
+ code = mit_samba_check_client_access(mit_ctx,
+ client,
+ client_name,
+ server,
+ server_name,
+ netbios_name,
+ password_change,
+ &int_data);
+ if (code) {
+ goto done;
+ }
+
+ d = ks_make_data(int_data.data, int_data.length);
+
+ code = decode_krb5_padata_sequence(&d, &e_data);
+ if (code == 0) {
+ *e_data_out = e_data;
+ }
+
+done:
+ free(realm);
+ free(server_name);
+ free(client_name);
+ free(netbios_name);
+
+ return code;
+}
+
+static krb5_error_code ks_get_pac(krb5_context context,
+ krb5_db_entry *client,
+ krb5_pac *pac)
+{
+ struct mit_samba_context *mit_ctx;
+ DATA_BLOB pac_data;
+ krb5_data data;
+ krb5_error_code code;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ code = mit_samba_get_pac_data(mit_ctx,
+ client,
+ &pac_data);
+ if (code != 0) {
+ return code;
+ }
+
+ code = krb5_pac_init(context, pac);
+ if (code != 0) {
+ goto done;
+ }
+
+ data = ks_make_data(pac_data.data, pac_data.length);
+
+ code = krb5_pac_add_buffer(context, *pac, PAC_LOGON_INFO, &data);
+ if (code != 0) {
+ goto done;
+ }
+
+done:
+ free(pac_data.data);
+ return code;
+}
+
+static krb5_error_code ks_verify_pac(krb5_context context,
+ unsigned int flags,
+ krb5_const_principal client_princ,
+ krb5_db_entry *client,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_timestamp authtime,
+ krb5_authdata **tgt_auth_data,
+ krb5_pac *pac)
+{
+ struct mit_samba_context *mit_ctx;
+ krb5_authdata **authdata = NULL;
+ krb5_pac ipac = NULL;
+ DATA_BLOB pac_data = { NULL, 0 };
+ DATA_BLOB logon_data = { NULL, 0 };
+ krb5_data data;
+ krb5_error_code code;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ /* find the existing PAC, if present */
+ code = krb5_find_authdata(context,
+ tgt_auth_data,
+ NULL,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ &authdata);
+ if (code != 0) {
+ return code;
+ }
+
+ /* no pac data */
+ if (authdata == NULL) {
+ return 0;
+ }
+
+ SMB_ASSERT(authdata[0] != NULL);
+
+ if (authdata[1] != NULL) {
+ code = KRB5KDC_ERR_BADOPTION; /* XXX */
+ goto done;
+ }
+
+ code = krb5_pac_parse(context,
+ authdata[0]->contents,
+ authdata[0]->length,
+ &ipac);
+ if (code != 0) {
+ goto done;
+ }
+
+ /* TODO: verify this is correct
+ *
+ * In the constrained delegation case, the PAC is from a service
+ * ticket rather than a TGT; we must verify the server and KDC
+ * signatures to assert that the server did not forge the PAC.
+ */
+ if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
+ code = krb5_pac_verify(context,
+ ipac,
+ authtime,
+ client_princ,
+ server_key,
+ krbtgt_key);
+ } else {
+ code = krb5_pac_verify(context,
+ ipac,
+ authtime,
+ client_princ,
+ krbtgt_key,
+ NULL);
+ }
+ if (code != 0) {
+ goto done;
+ }
+
+ /* check and update PAC */
+ pac_data.data = authdata[0]->contents;
+ pac_data.length = authdata[0]->length;
+
+ code = mit_samba_update_pac_data(mit_ctx,
+ client,
+ &pac_data,
+ &logon_data);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = krb5_pac_init(context, pac);
+ if (code != 0) {
+ goto done;
+ }
+
+ data = ks_make_data(logon_data.data, logon_data.length);
+
+ code = krb5_pac_add_buffer(context, *pac, PAC_LOGON_INFO, &data);
+ if (code != 0) {
+ goto done;
+ }
+
+done:
+ krb5_free_authdata(context, authdata);
+ krb5_pac_free(context, ipac);
+ free(logon_data.data);
+
+ return code;
+}
+
+krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
+ unsigned int flags,
+ krb5_const_principal client_princ,
+ krb5_db_entry *client,
+ krb5_db_entry *server,
+ krb5_db_entry *krbtgt,
+ krb5_keyblock *client_key,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_keyblock *session_key,
+ krb5_timestamp authtime,
+ krb5_authdata **tgt_auth_data,
+ krb5_authdata ***signed_auth_data)
+{
+ krb5_const_principal ks_client_princ;
+ krb5_authdata **authdata = NULL;
+ krb5_boolean is_as_req;
+ krb5_error_code code;
+ krb5_pac pac = NULL;
+ krb5_data pac_data;
+
+ /* Prefer canonicalised name from client entry */
+ if (client != NULL) {
+ ks_client_princ = client->princ;
+ } else {
+ ks_client_princ = client_princ;
+ }
+
+ is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
+
+ if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) {
+
+ code = ks_get_pac(context, client, &pac);
+ if (code != 0) {
+ goto done;
+ }
+ }
+
+ if (!is_as_req) {
+ code = ks_verify_pac(context, flags, ks_client_princ, client,
+ server_key, krbtgt_key, authtime,
+ tgt_auth_data, &pac);
+ if (code != 0) {
+ goto done;
+ }
+ }
+
+ if (pac == NULL && client != NULL) {
+
+ code = ks_get_pac(context, client, &pac);
+ if (code != 0) {
+ goto done;
+ }
+ }
+
+ if (pac == NULL) {
+ code = KRB5_KDB_DBTYPE_NOSUP;
+ goto done;
+ }
+
+ code = krb5_pac_sign(context, pac, authtime, ks_client_princ,
+ server_key, krbtgt_key, &pac_data);
+ if (code != 0) {
+ goto done;
+ }
+
+ authdata = malloc(2 * sizeof(krb5_authdata *));
+ if (authdata == NULL) {
+ goto done;
+ }
+
+ authdata[0] = malloc(sizeof(krb5_authdata));
+ if (authdata[0] == NULL) {
+ goto done;
+ }
+
+ /* put in signed data */
+ authdata[0]->magic = KV5M_AUTHDATA;
+ authdata[0]->ad_type = KRB5_AUTHDATA_WIN2K_PAC;
+ authdata[0]->contents = (krb5_octet *)pac_data.data;
+ authdata[0]->length = pac_data.length;
+
+ code = krb5_encode_authdata_container(context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ authdata,
+ signed_auth_data);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = 0;
+
+done:
+ krb5_pac_free(context, pac);
+ krb5_free_authdata(context, authdata);
+
+ return code;
+}
+
+krb5_error_code kdb_samba_db_check_allowed_to_delegate(krb5_context context,
+ krb5_const_principal client,
+ const krb5_db_entry *server,
+ krb5_const_principal proxy)
+{
+ struct mit_samba_context *mit_ctx;
+
+ /*
+ * Names are quite odd and confusing in the current implementation.
+ * The following mappings should help understanding what is what.
+ * client -> client to impersonate
+ * server; -> delegating service
+ * proxy; -> target principal
+ */
+ krb5_db_entry *delegating_service = discard_const_p(krb5_db_entry, server);
+
+ char *target_name = NULL;
+ bool is_enterprise;
+ krb5_error_code code;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ code = krb5_unparse_name(context, proxy, &target_name);
+ if (code) {
+ goto done;
+ }
+
+ is_enterprise = (proxy->type == KRB5_NT_ENTERPRISE_PRINCIPAL);
+
+ code = mit_samba_check_s4u2proxy(mit_ctx,
+ delegating_service,
+ target_name,
+ is_enterprise);
+
+done:
+ free(target_name);
+ return code;
+}
diff --git a/source4/kdc/mit-kdb/kdb_samba_principals.c b/source4/kdc/mit-kdb/kdb_samba_principals.c
new file mode 100644
index 00000000000..50f17776563
--- /dev/null
+++ b/source4/kdc/mit-kdb/kdb_samba_principals.c
@@ -0,0 +1,227 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Samba KDB plugin for MIT Kerberos
+
+ Copyright (c) 2010 Simo Sorce <idra@samba.org>.
+ Copyright (c) 2014 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "system/kerberos.h"
+
+#include <profile.h>
+#include <kdb.h>
+
+#include "kdc/mit_samba.h"
+#include "kdb_samba.h"
+
+static krb5_error_code ks_get_principal(krb5_context context,
+ krb5_const_principal principal,
+ unsigned int kflags,
+ krb5_db_entry **kentry)
+{
+ struct mit_samba_context *mit_ctx;
+ krb5_error_code code;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ code = mit_samba_get_principal(mit_ctx,
+ principal,
+ kflags,
+ kentry);
+ if (code != 0) {
+ goto cleanup;
+ }
+
+cleanup:
+
+ return code;
+}
+
+static krb5_boolean ks_is_master_key_principal(krb5_context context,
+ krb5_const_principal princ)
+{
+ return krb5_princ_size(context, princ) == 2 &&
+ ks_data_eq_string(princ->data[0], "K") &&
+ ks_data_eq_string(princ->data[1], "M");
+}
+
+static krb5_error_code ks_get_master_key_principal(krb5_context context,
+ krb5_const_principal princ,
+ krb5_db_entry **kentry_ptr)
+{
+ krb5_error_code code;
+ krb5_key_data *key_data;
+ krb5_timestamp now;
+ krb5_db_entry *kentry;
+
+ *kentry_ptr = NULL;
+
+ kentry = malloc(sizeof(krb5_db_entry));
+ if (kentry == NULL) {
+ return ENOMEM;
+ }
+
+ ZERO_STRUCTP(kentry);
+
+ kentry->magic = KRB5_KDB_MAGIC_NUMBER;
+ kentry->len = KRB5_KDB_V1_BASE_LENGTH;
+ kentry->attributes = KRB5_KDB_DISALLOW_ALL_TIX;
+
+ if (princ == NULL) {
+ code = krb5_parse_name(context, KRB5_KDB_M_NAME, &kentry->princ);
+ } else {
+ code = krb5_copy_principal(context, princ, &kentry->princ);
+ }
+ if (code != 0) {
+ ks_free_krb5_db_entry(context, kentry);
+ return code;
+ }
+
+ now = time(NULL);
+
+ code = krb5_dbe_update_mod_princ_data(context, kentry, now, kentry->princ);
+ if (code != 0) {
+ ks_free_krb5_db_entry(context, kentry);
+ return code;
+ }
+
+ /* Return a dummy key */
+ kentry->n_key_data = 1;
+ kentry->key_data = malloc(sizeof(krb5_key_data));
+ if (code != 0) {
+ ks_free_krb5_db_entry(context, kentry);
+ return code;
+ }
+
+ key_data = &kentry->key_data[0];
+
+ key_data->key_data_ver = KRB5_KDB_V1_KEY_DATA_ARRAY;
+ key_data->key_data_kvno = 1;
+ key_data->key_data_type[0] = ENCTYPE_UNKNOWN;
+ if (code != 0) {
+ ks_free_krb5_db_entry(context, kentry);
+ return code;
+ }
+
+ *kentry_ptr = kentry;
+
+ return 0;
+}
+
+static krb5_boolean ks_is_kadmin_history(krb5_context context,
+ krb5_const_principal princ)
+{
+ return krb5_princ_size(context, princ) == 2 &&
+ ks_data_eq_string(princ->data[0], "kadmin") &&
+ ks_data_eq_string(princ->data[1], "history");
+}
+
+krb5_error_code kdb_samba_db_get_principal(krb5_context context,
+ krb5_const_principal princ,
+ unsigned int kflags,
+ krb5_db_entry **kentry)
+{
+ struct mit_samba_context *mit_ctx;
+ krb5_error_code code;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ if (ks_is_master_key_principal(context, princ)) {
+ return ks_get_master_key_principal(context, princ, kentry);
+ }
+
+ /* FIXME: temporarily fake up kadmin history to let kadmin.local work */
+ if (ks_is_kadmin_history(context, princ)) {
+ return ks_get_dummy_principal(context, princ, kentry);
+ }
+
+ code = ks_get_principal(context, princ, kflags, kentry);
+
+ return code;
+}
+
+void kdb_samba_db_free_principal(krb5_context context,
+ krb5_db_entry *entry)
+{
+ struct mit_samba_context *mit_ctx;
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return;
+ }
+
+ ks_free_krb5_db_entry(context, entry);
+}
+
+krb5_error_code kdb_samba_db_put_principal(krb5_context context,
+ krb5_db_entry *entry,
+ char **db_args)
+{
+
+ /* NOTE: deferred, samba does not allow the KDC to store
+ * principals for now */
+ return KRB5_KDB_DB_INUSE;
+}
+
+krb5_error_code kdb_samba_db_delete_principal(krb5_context context,
+ krb5_const_principal princ)
+{
+
+ /* NOTE: deferred, samba does not allow the KDC to delete
+ * principals for now */
+ return KRB5_KDB_DB_INUSE;
+}
+
+krb5_error_code kdb_samba_db_iterate(krb5_context context,
+ char *match_entry,
+ int (*func)(krb5_pointer, krb5_db_entry *),
+ krb5_pointer func_arg)
+{
+ struct mit_samba_context *mit_ctx;
+ krb5_db_entry *kentry = NULL;
+ krb5_error_code code;
+
+
+ mit_ctx = ks_get_context(context);
+ if (mit_ctx == NULL) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ code = mit_samba_get_firstkey(mit_ctx, &kentry);
+ while (code == 0) {
+ code = (*func)(func_arg, kentry);
+ if (code != 0) {
+ break;
+ }
+
+ code = mit_samba_get_nextkey(mit_ctx, &kentry);
+ }
+
+ if (code == KRB5_KDB_NOENTRY) {
+ code = 0;
+ }
+
+ return code;
+}
diff --git a/source4/kdc/mit-kdb/wscript_build b/source4/kdc/mit-kdb/wscript_build
new file mode 100644
index 00000000000..68f086649c2
--- /dev/null
+++ b/source4/kdc/mit-kdb/wscript_build
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('mit-kdb-samba',
+ source='''
+ kdb_samba.c
+ kdb_samba_common.c
+ kdb_samba_masterkey.c
+ kdb_samba_pac.c
+ kdb_samba_policies.c
+ kdb_samba_principals.c
+ ''',
+ private_library=True,
+ realname='samba.so',
+ install_path='${LIBDIR}/krb5/plugins/kdb',
+ deps='''
+ MIT_SAMBA
+ com_err
+ krb5
+ kdb5
+ ''',
+ enabled=bld.CONFIG_SET('HAVE_KDB_H'))