mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
990cca36b1
This changed between 1.14 and 1.15. Also the 1.15 change removed the ability that the KDB module can free memory. This caused issues of serveral projects. It got fixed with 1.15.1. Signed-off-by: Andreas Schneider <asn@samba.org> Reviewed-by: Andrew Bartlet <abartlet@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
360 lines
7.5 KiB
C
360 lines
7.5 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
|
|
Database Glue between Samba and the KDC
|
|
|
|
Copyright (C) Guenther Deschner <gd@samba.org> 2014
|
|
Copyright (C) Andreas Schneider <asn@samba.org> 2014
|
|
|
|
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 <kdb.h>
|
|
#include "sdb.h"
|
|
#include "sdb_kdb.h"
|
|
#include "kdc/samba_kdc.h"
|
|
#include "lib/krb5_wrap/krb5_samba.h"
|
|
|
|
static int SDBFlags_to_kflags(const struct SDBFlags *s,
|
|
krb5_flags *k)
|
|
{
|
|
*k = 0;
|
|
|
|
if (s->initial) {
|
|
*k |= KRB5_KDB_DISALLOW_TGT_BASED;
|
|
}
|
|
/*
|
|
* Do not set any disallow rules for forwardable, proxiable,
|
|
* renewable, postdate and server.
|
|
*
|
|
* The KDC will take care setting the flags based on the incoming
|
|
* ticket.
|
|
*/
|
|
if (s->forwardable) {
|
|
;
|
|
}
|
|
if (s->proxiable) {
|
|
;
|
|
}
|
|
if (s->renewable) {
|
|
;
|
|
}
|
|
if (s->postdate) {
|
|
;
|
|
}
|
|
if (s->server) {
|
|
;
|
|
}
|
|
if (s->client) {
|
|
;
|
|
}
|
|
if (s->invalid) {
|
|
*k |= KRB5_KDB_DISALLOW_ALL_TIX;
|
|
}
|
|
if (s->require_preauth) {
|
|
*k |= KRB5_KDB_REQUIRES_PRE_AUTH;
|
|
}
|
|
if (s->change_pw) {
|
|
*k |= KRB5_KDB_PWCHANGE_SERVICE;
|
|
}
|
|
if (s->require_hwauth) {
|
|
*k |= KRB5_KDB_REQUIRES_HW_AUTH;
|
|
}
|
|
if (s->ok_as_delegate) {
|
|
*k |= KRB5_KDB_OK_AS_DELEGATE;
|
|
}
|
|
if (s->user_to_user) {
|
|
;
|
|
}
|
|
if (s->immutable) {
|
|
;
|
|
}
|
|
if (s->trusted_for_delegation) {
|
|
*k |= KRB5_KDB_OK_TO_AUTH_AS_DELEGATE;
|
|
}
|
|
if (s->allow_kerberos4) {
|
|
;
|
|
}
|
|
if (s->allow_digest) {
|
|
;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sdb_event_to_kmod(krb5_context context,
|
|
const struct sdb_event *s,
|
|
krb5_db_entry *k)
|
|
{
|
|
krb5_error_code ret;
|
|
krb5_principal principal = NULL;
|
|
|
|
if (s->principal != NULL) {
|
|
ret = krb5_copy_principal(context,
|
|
s->principal,
|
|
&principal);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ret = krb5_dbe_update_mod_princ_data(context,
|
|
k, s->time,
|
|
principal);
|
|
|
|
krb5_free_principal(context, principal);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* sets up salt on the 2nd array position */
|
|
|
|
static int sdb_salt_to_krb5_key_data(const struct sdb_salt *s,
|
|
krb5_key_data *k)
|
|
{
|
|
switch (s->type) {
|
|
#if 0
|
|
/* for now use the special mechanism where the MIT KDC creates the salt
|
|
* on its own */
|
|
case 3: /* FIXME KRB5_PW_SALT */
|
|
k->key_data_type[1] = KRB5_KDB_SALTTYPE_NORMAL;
|
|
break;
|
|
/*
|
|
case hdb_afs3_salt:
|
|
k->key_data_type[1] = KRB5_KDB_SALTTYPE_AFS3;
|
|
break;
|
|
*/
|
|
#endif
|
|
default:
|
|
k->key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
|
|
break;
|
|
}
|
|
|
|
k->key_data_contents[1] = malloc(s->salt.length);
|
|
if (k->key_data_contents[1] == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
memcpy(k->key_data_contents[1],
|
|
s->salt.data,
|
|
s->salt.length);
|
|
k->key_data_length[1] = s->salt.length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sdb_key_to_krb5_key_data(const struct sdb_key *s,
|
|
int kvno,
|
|
krb5_key_data *k)
|
|
{
|
|
int ret = 0;
|
|
|
|
ZERO_STRUCTP(k);
|
|
|
|
k->key_data_ver = KRB5_KDB_V1_KEY_DATA_ARRAY;
|
|
k->key_data_kvno = kvno;
|
|
|
|
k->key_data_type[0] = KRB5_KEY_TYPE(&s->key);
|
|
k->key_data_length[0] = KRB5_KEY_LENGTH(&s->key);
|
|
k->key_data_contents[0] = malloc(k->key_data_length[0]);
|
|
if (k->key_data_contents[0] == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
memcpy(k->key_data_contents[0],
|
|
KRB5_KEY_DATA(&s->key),
|
|
k->key_data_length[0]);
|
|
|
|
if (s->salt != NULL) {
|
|
ret = sdb_salt_to_krb5_key_data(s->salt, k);
|
|
if (ret) {
|
|
memset(k->key_data_contents[0], 0, k->key_data_length[0]);
|
|
free(k->key_data_contents[0]);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void free_krb5_db_entry(krb5_context context,
|
|
krb5_db_entry *k)
|
|
{
|
|
krb5_tl_data *tl_data_next = NULL;
|
|
krb5_tl_data *tl_data = NULL;
|
|
int i, j;
|
|
|
|
if (k == NULL) {
|
|
return;
|
|
}
|
|
|
|
krb5_free_principal(context, k->princ);
|
|
|
|
for (tl_data = k->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 (k->key_data != NULL) {
|
|
for (i = 0; i < k->n_key_data; i++) {
|
|
for (j = 0; j < k->key_data[i].key_data_ver; j++) {
|
|
if (k->key_data[i].key_data_length[j] != 0) {
|
|
if (k->key_data[i].key_data_contents[j] != NULL) {
|
|
memset(k->key_data[i].key_data_contents[j], 0, k->key_data[i].key_data_length[j]);
|
|
free(k->key_data[i].key_data_contents[j]);
|
|
}
|
|
}
|
|
k->key_data[i].key_data_contents[j] = NULL;
|
|
k->key_data[i].key_data_length[j] = 0;
|
|
k->key_data[i].key_data_type[j] = 0;
|
|
}
|
|
}
|
|
free(k->key_data);
|
|
}
|
|
|
|
ZERO_STRUCTP(k);
|
|
}
|
|
|
|
static int sdb_entry_ex_to_krb5_db_entry(krb5_context context,
|
|
const struct sdb_entry *s,
|
|
krb5_db_entry *k)
|
|
{
|
|
krb5_error_code ret;
|
|
int i;
|
|
|
|
k->magic = KRB5_KDB_MAGIC_NUMBER;
|
|
k->len = KRB5_KDB_V1_BASE_LENGTH;
|
|
|
|
ret = krb5_copy_principal(context,
|
|
s->principal,
|
|
&k->princ);
|
|
if (ret) {
|
|
free_krb5_db_entry(context, k);
|
|
return ret;
|
|
}
|
|
|
|
ret = SDBFlags_to_kflags(&s->flags,
|
|
&k->attributes);
|
|
if (ret) {
|
|
free_krb5_db_entry(context, k);
|
|
return ret;
|
|
}
|
|
|
|
if (s->max_life != NULL) {
|
|
k->max_life = *s->max_life;
|
|
}
|
|
if (s->max_renew != NULL) {
|
|
k->max_renewable_life = *s->max_renew;
|
|
}
|
|
if (s->valid_end != NULL) {
|
|
k->expiration = *s->valid_end;
|
|
}
|
|
if (s->pw_end != NULL) {
|
|
k->pw_expiration = *s->pw_end;
|
|
}
|
|
|
|
/* last_success */
|
|
/* last_failed */
|
|
/* fail_auth_count */
|
|
/* n_tl_data */
|
|
|
|
/*
|
|
* If we leave early when looking up the realm, we do not have all
|
|
* information about a principal. We need to construct a db entry
|
|
* with minimal information, so skip this part.
|
|
*/
|
|
if (s->created_by.time != 0) {
|
|
ret = sdb_event_to_kmod(context,
|
|
s->modified_by ? s->modified_by : &s->created_by,
|
|
k);
|
|
if (ret) {
|
|
free_krb5_db_entry(context, k);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* FIXME: TODO HDB Extensions */
|
|
|
|
if (s->keys.len > 0) {
|
|
k->key_data = malloc(s->keys.len * sizeof(krb5_key_data));
|
|
if (k->key_data == NULL) {
|
|
free_krb5_db_entry(context, k);
|
|
return ret;
|
|
}
|
|
|
|
for (i=0; i < s->keys.len; i++) {
|
|
ret = sdb_key_to_krb5_key_data(&s->keys.val[i],
|
|
s->kvno,
|
|
&k->key_data[i]);
|
|
if (ret) {
|
|
free_krb5_db_entry(context, k);
|
|
return ret;
|
|
}
|
|
|
|
k->n_key_data++;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int samba_kdc_kdb_entry_destructor(struct samba_kdc_entry *p)
|
|
{
|
|
krb5_db_entry *entry_ex = p->entry_ex;
|
|
krb5_error_code ret;
|
|
krb5_context context;
|
|
|
|
if (entry_ex->e_data != NULL) {
|
|
struct samba_kdc_entry *skdc_entry;
|
|
|
|
skdc_entry = talloc_get_type(entry_ex->e_data,
|
|
struct samba_kdc_entry);
|
|
talloc_set_destructor(skdc_entry, NULL);
|
|
entry_ex->e_data = NULL;
|
|
}
|
|
|
|
ret = krb5_init_context(&context);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
krb5_db_free_principal(context, entry_ex);
|
|
krb5_free_context(context);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sdb_entry_ex_to_kdb_entry_ex(krb5_context context,
|
|
const struct sdb_entry_ex *s,
|
|
krb5_db_entry *k)
|
|
{
|
|
ZERO_STRUCTP(k);
|
|
|
|
if (s->ctx != NULL) {
|
|
struct samba_kdc_entry *skdc_entry;
|
|
|
|
skdc_entry = talloc_get_type(s->ctx, struct samba_kdc_entry);
|
|
|
|
k->e_data = (void *)skdc_entry;
|
|
|
|
talloc_set_destructor(skdc_entry,
|
|
samba_kdc_kdb_entry_destructor);
|
|
}
|
|
|
|
return sdb_entry_ex_to_krb5_db_entry(context, &s->entry, k);
|
|
}
|