From: Andreas Schneider Date: Mon, 29 Feb 2016 14:12:02 +0000 (+0100) Subject: s4-libnet: Implement export_keytab without HDB X-Git-Tag: tdb-1.3.9~404 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5c5d586d3ebd40;p=thirdparty%2Fsamba.git s4-libnet: Implement export_keytab without HDB This is used by 'samba-tool domain exportkeytab'. This loads the HDB Samba backend thus needs access to samdb. To avoid using heimdal specific code here, we could talk to samdb directly and write a keytab file. Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher --- diff --git a/source4/libnet/libnet_export_keytab.c b/source4/libnet/libnet_export_keytab.c index 295624e9f71..bdd77c0d1c6 100644 --- a/source4/libnet/libnet_export_keytab.c +++ b/source4/libnet/libnet_export_keytab.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. Copyright (C) Andrew Bartlett 2009 + Copyright (C) Andreas Schneider 2016 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 @@ -24,59 +25,184 @@ #include "kdc/samba_kdc.h" #include "libnet/libnet_export_keytab.h" -NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r) -{ - krb5_error_code ret; - struct smb_krb5_context *smb_krb5_context; - const char *from_keytab; +#include "kdc/db-glue.h" +#include "kdc/sdb.h" - /* Register hdb-samba4 hooks for use as a keytab */ +static NTSTATUS sdb_kt_copy(TALLOC_CTX *mem_ctx, + krb5_context context, + struct samba_kdc_db_context *db_ctx, + const char *keytab_name, + const char *principal, + const char **error_string) +{ + struct sdb_entry_ex sentry = { + .free_entry = NULL, + }; + krb5_keytab keytab; + krb5_error_code code = 0; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + char *entry_principal = NULL; + bool copy_one_principal = (principal != NULL); + krb5_data password; - struct samba_kdc_base_context *base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context); - if (!base_ctx) { - return NT_STATUS_NO_MEMORY; + code = smb_krb5_open_keytab_relative(context, + keytab_name, + true, /* write_access */ + &keytab); + if (code != 0) { + *error_string = talloc_asprintf(mem_ctx, + "Failed to open keytab: %s", + keytab_name); + status = NT_STATUS_NO_SUCH_FILE; + goto done; } - base_ctx->ev_ctx = ctx->event_ctx; - base_ctx->lp_ctx = ctx->lp_ctx; + for (code = samba_kdc_firstkey(context, db_ctx, &sentry); + code == 0; + code = samba_kdc_nextkey(context, db_ctx, &sentry)) { + bool principal_found = false; + int i; - from_keytab = talloc_asprintf(base_ctx, "HDB:samba4&%p", base_ctx); - if (!from_keytab) { - return NT_STATUS_NO_MEMORY; + code = krb5_unparse_name(context, + sentry.entry.principal, + &entry_principal); + if (code != 0) { + *error_string = smb_get_krb5_error_message(context, + code, + mem_ctx); + status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (principal != NULL) { + int cmp; + + cmp = strcmp(principal, entry_principal); + if (cmp == 0) { + principal_found = true; + } + } + + if (sentry.entry.keys.len == 0 || + (copy_one_principal && !principal_found)) { + SAFE_FREE(entry_principal); + sdb_free_entry(&sentry); + sentry = (struct sdb_entry_ex) { + .free_entry = NULL, + }; + + continue; + } + + for (i = 0; i < sentry.entry.keys.len; i++) { + struct sdb_key *s = &(sentry.entry.keys.val[i]); + krb5_enctype enctype; + + enctype = KRB5_KEY_TYPE(&(s->key)); + password.length = KRB5_KEY_LENGTH(&s->key); + password.data = (char *)KRB5_KEY_DATA(&s->key); + + DBG_INFO("smb_krb5_kt_add_entry for enctype=0x%04x\n", + (int)enctype); + code = smb_krb5_kt_add_entry(context, + keytab, + sentry.entry.kvno, + entry_principal, + NULL, + enctype, + &password, + true, /* no_salt */ + false); /* keeyp_old_entries */ + if (code != 0) { + status = NT_STATUS_UNSUCCESSFUL; + *error_string = smb_get_krb5_error_message(context, + code, + mem_ctx); + DEBUG(0, ("smb_krb5_kt_add_entry failed code=%d, error = %s\n", + code, *error_string)); + goto done; + } + } + + if (principal_found) { + break; + } + + SAFE_FREE(entry_principal); + sdb_free_entry(&sentry); + sentry = (struct sdb_entry_ex) { + .free_entry = NULL, + }; + } + + if (code != 0 && code != SDB_ERR_NOENTRY) { + *error_string = smb_get_krb5_error_message(context, + code, + mem_ctx); + status = NT_STATUS_NO_SUCH_USER; + goto done; } + status = NT_STATUS_OK; +done: + SAFE_FREE(entry_principal); + sdb_free_entry(&sentry); + + return status; +} + +NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r) +{ + krb5_error_code ret; + struct smb_krb5_context *smb_krb5_context; + struct samba_kdc_base_context *base_ctx; + struct samba_kdc_db_context *db_ctx = NULL; + const char *error_string = NULL; + NTSTATUS status; + ret = smb_krb5_init_context(ctx, ctx->lp_ctx, &smb_krb5_context); if (ret) { return NT_STATUS_NO_MEMORY; } - ret = krb5_plugin_register(smb_krb5_context->krb5_context, - PLUGIN_TYPE_DATA, "hdb", - &hdb_samba4_interface); - if(ret) { + base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context); + if (base_ctx == NULL) { return NT_STATUS_NO_MEMORY; } - ret = krb5_kt_register(smb_krb5_context->krb5_context, &hdb_kt_ops); - if(ret) { - return NT_STATUS_NO_MEMORY; + base_ctx->ev_ctx = ctx->event_ctx; + base_ctx->lp_ctx = ctx->lp_ctx; + + status = samba_kdc_setup_db_ctx(mem_ctx, base_ctx, &db_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; } - if (r->in.principal) { - ret = kt_copy_one_principal(smb_krb5_context->krb5_context, from_keytab, r->in.keytab_name, r->in.principal, 0, samba_all_enctypes()); + if (r->in.principal != NULL) { + DEBUG(0, ("Export one principal to %s\n", r->in.keytab_name)); + status = sdb_kt_copy(mem_ctx, + smb_krb5_context->krb5_context, + db_ctx, + r->in.keytab_name, + r->in.principal, + &error_string); } else { unlink(r->in.keytab_name); - ret = kt_copy(smb_krb5_context->krb5_context, from_keytab, r->in.keytab_name); + DEBUG(0, ("Export complete keytab to %s\n", r->in.keytab_name)); + status = sdb_kt_copy(mem_ctx, + smb_krb5_context->krb5_context, + db_ctx, + r->in.keytab_name, + NULL, + &error_string); } - if(ret) { - r->out.error_string = smb_get_krb5_error_message(smb_krb5_context->krb5_context, - ret, mem_ctx); - if (ret == KRB5_KT_NOTFOUND) { - return NT_STATUS_NO_SUCH_USER; - } else { - return NT_STATUS_UNSUCCESSFUL; - } + talloc_free(db_ctx); + talloc_free(base_ctx); + + if (!NT_STATUS_IS_OK(status)) { + r->out.error_string = error_string; } - return NT_STATUS_OK; + + return status; }