diff options
Diffstat (limited to 'source4/libnet/libnet_export_keytab.c')
-rw-r--r-- | source4/libnet/libnet_export_keytab.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/source4/libnet/libnet_export_keytab.c b/source4/libnet/libnet_export_keytab.c new file mode 100644 index 0000000..4c96546 --- /dev/null +++ b/source4/libnet/libnet_export_keytab.c @@ -0,0 +1,207 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009 + Copyright (C) Andreas Schneider <asn@samba.org> 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 + 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 "auth/kerberos/kerberos.h" +#include "kdc/samba_kdc.h" +#include "libnet/libnet_export_keytab.h" + +#include "kdc/db-glue.h" +#include "kdc/sdb.h" + +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 sentry = {}; + 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; + + code = smb_krb5_kt_open_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; + } + + if (copy_one_principal) { + krb5_principal k5_princ; + + code = smb_krb5_parse_name(context, principal, &k5_princ); + if (code != 0) { + *error_string = smb_get_krb5_error_message(context, + code, + mem_ctx); + status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + code = samba_kdc_fetch(context, db_ctx, k5_princ, + SDB_F_GET_ANY | SDB_F_ADMIN_DATA, + 0, &sentry); + + krb5_free_principal(context, k5_princ); + } else { + code = samba_kdc_firstkey(context, db_ctx, &sentry); + } + + for (; code == 0; code = samba_kdc_nextkey(context, db_ctx, &sentry)) { + int i; + + code = krb5_unparse_name(context, + sentry.principal, + &entry_principal); + if (code != 0) { + *error_string = smb_get_krb5_error_message(context, + code, + mem_ctx); + status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (sentry.keys.len == 0) { + SAFE_FREE(entry_principal); + sdb_entry_free(&sentry); + + continue; + } + + for (i = 0; i < sentry.keys.len; i++) { + struct sdb_key *s = &(sentry.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.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 (copy_one_principal) { + break; + } + + SAFE_FREE(entry_principal); + sdb_entry_free(&sentry); + } + + 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_entry_free(&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; + } + + base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context); + if (base_ctx == NULL) { + 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 != 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); + 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); + } + + talloc_free(db_ctx); + talloc_free(base_ctx); + + if (!NT_STATUS_IS_OK(status)) { + r->out.error_string = error_string; + } + + return status; +} |