2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
5 Copyright (C) Andreas Schneider <asn@samba.org> 2016
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/kerberos.h"
23 #include "auth/kerberos/kerberos.h"
24 #include "kdc/samba_kdc.h"
25 #include "libnet/libnet_export_keytab.h"
27 #include "kdc/db-glue.h"
30 static NTSTATUS sdb_kt_copy(TALLOC_CTX *mem_ctx,
32 struct samba_kdc_db_context *db_ctx,
33 const char *keytab_name,
34 const char *principal,
35 const char **error_string)
37 struct sdb_entry_ex sentry = {
41 krb5_error_code code = 0;
42 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
43 char *entry_principal = NULL;
44 bool copy_one_principal = (principal != NULL);
47 code = smb_krb5_open_keytab_relative(context,
49 true, /* write_access */
52 *error_string = talloc_asprintf(mem_ctx,
53 "Failed to open keytab: %s",
55 status = NT_STATUS_NO_SUCH_FILE;
59 for (code = samba_kdc_firstkey(context, db_ctx, &sentry);
61 code = samba_kdc_nextkey(context, db_ctx, &sentry)) {
62 bool principal_found = false;
65 code = krb5_unparse_name(context,
66 sentry.entry.principal,
69 *error_string = smb_get_krb5_error_message(context,
72 status = NT_STATUS_UNSUCCESSFUL;
76 if (principal != NULL) {
79 cmp = strcmp(principal, entry_principal);
81 principal_found = true;
85 if (sentry.entry.keys.len == 0 ||
86 (copy_one_principal && !principal_found)) {
87 SAFE_FREE(entry_principal);
88 sdb_free_entry(&sentry);
89 sentry = (struct sdb_entry_ex) {
96 for (i = 0; i < sentry.entry.keys.len; i++) {
97 struct sdb_key *s = &(sentry.entry.keys.val[i]);
100 enctype = KRB5_KEY_TYPE(&(s->key));
101 password.length = KRB5_KEY_LENGTH(&s->key);
102 password.data = (char *)KRB5_KEY_DATA(&s->key);
104 DBG_INFO("smb_krb5_kt_add_entry for enctype=0x%04x\n",
106 code = smb_krb5_kt_add_entry(context,
114 false); /* keeyp_old_entries */
116 status = NT_STATUS_UNSUCCESSFUL;
117 *error_string = smb_get_krb5_error_message(context,
120 DEBUG(0, ("smb_krb5_kt_add_entry failed code=%d, error = %s\n",
121 code, *error_string));
126 if (principal_found) {
130 SAFE_FREE(entry_principal);
131 sdb_free_entry(&sentry);
132 sentry = (struct sdb_entry_ex) {
137 if (code != 0 && code != SDB_ERR_NOENTRY) {
138 *error_string = smb_get_krb5_error_message(context,
141 status = NT_STATUS_NO_SUCH_USER;
145 status = NT_STATUS_OK;
147 SAFE_FREE(entry_principal);
148 sdb_free_entry(&sentry);
153 NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r)
156 struct smb_krb5_context *smb_krb5_context;
157 struct samba_kdc_base_context *base_ctx;
158 struct samba_kdc_db_context *db_ctx = NULL;
159 const char *error_string = NULL;
162 ret = smb_krb5_init_context(ctx, ctx->lp_ctx, &smb_krb5_context);
164 return NT_STATUS_NO_MEMORY;
167 base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context);
168 if (base_ctx == NULL) {
169 return NT_STATUS_NO_MEMORY;
172 base_ctx->ev_ctx = ctx->event_ctx;
173 base_ctx->lp_ctx = ctx->lp_ctx;
175 status = samba_kdc_setup_db_ctx(mem_ctx, base_ctx, &db_ctx);
176 if (!NT_STATUS_IS_OK(status)) {
180 if (r->in.principal != NULL) {
181 DEBUG(0, ("Export one principal to %s\n", r->in.keytab_name));
182 status = sdb_kt_copy(mem_ctx,
183 smb_krb5_context->krb5_context,
189 unlink(r->in.keytab_name);
190 DEBUG(0, ("Export complete keytab to %s\n", r->in.keytab_name));
191 status = sdb_kt_copy(mem_ctx,
192 smb_krb5_context->krb5_context,
200 talloc_free(base_ctx);
202 if (!NT_STATUS_IS_OK(status)) {
203 r->out.error_string = error_string;