Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
5 : Copyright (C) Andreas Schneider <asn@samba.org> 2016
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/kerberos.h"
23 : #include "auth/kerberos/kerberos.h"
24 : #include "kdc/samba_kdc.h"
25 : #include "libnet/libnet_export_keytab.h"
26 :
27 : #include "kdc/db-glue.h"
28 : #include "kdc/sdb.h"
29 :
30 11 : static NTSTATUS sdb_kt_copy(TALLOC_CTX *mem_ctx,
31 : krb5_context context,
32 : struct samba_kdc_db_context *db_ctx,
33 : const char *keytab_name,
34 : const char *principal,
35 : const char **error_string)
36 : {
37 11 : struct sdb_entry sentry = {};
38 : krb5_keytab keytab;
39 11 : krb5_error_code code = 0;
40 11 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
41 11 : char *entry_principal = NULL;
42 11 : bool copy_one_principal = (principal != NULL);
43 : krb5_data password;
44 :
45 11 : code = smb_krb5_kt_open_relative(context,
46 : keytab_name,
47 : true, /* write_access */
48 : &keytab);
49 11 : if (code != 0) {
50 0 : *error_string = talloc_asprintf(mem_ctx,
51 : "Failed to open keytab: %s",
52 : keytab_name);
53 0 : status = NT_STATUS_NO_SUCH_FILE;
54 0 : goto done;
55 : }
56 :
57 11 : if (copy_one_principal) {
58 : krb5_principal k5_princ;
59 :
60 9 : code = smb_krb5_parse_name(context, principal, &k5_princ);
61 9 : if (code != 0) {
62 0 : *error_string = smb_get_krb5_error_message(context,
63 : code,
64 : mem_ctx);
65 0 : status = NT_STATUS_UNSUCCESSFUL;
66 0 : goto done;
67 : }
68 :
69 9 : code = samba_kdc_fetch(context, db_ctx, k5_princ,
70 : SDB_F_GET_ANY | SDB_F_ADMIN_DATA,
71 : 0, &sentry);
72 :
73 9 : krb5_free_principal(context, k5_princ);
74 : } else {
75 2 : code = samba_kdc_firstkey(context, db_ctx, &sentry);
76 : }
77 :
78 43 : for (; code == 0; code = samba_kdc_nextkey(context, db_ctx, &sentry)) {
79 : int i;
80 :
81 41 : code = krb5_unparse_name(context,
82 41 : sentry.principal,
83 : &entry_principal);
84 41 : if (code != 0) {
85 0 : *error_string = smb_get_krb5_error_message(context,
86 : code,
87 : mem_ctx);
88 0 : status = NT_STATUS_UNSUCCESSFUL;
89 0 : goto done;
90 : }
91 :
92 41 : if (sentry.keys.len == 0) {
93 8 : SAFE_FREE(entry_principal);
94 8 : sdb_entry_free(&sentry);
95 :
96 8 : continue;
97 : }
98 :
99 124 : for (i = 0; i < sentry.keys.len; i++) {
100 91 : struct sdb_key *s = &(sentry.keys.val[i]);
101 : krb5_enctype enctype;
102 :
103 91 : enctype = KRB5_KEY_TYPE(&(s->key));
104 91 : password.length = KRB5_KEY_LENGTH(&s->key);
105 91 : password.data = (char *)KRB5_KEY_DATA(&s->key);
106 :
107 91 : DBG_INFO("smb_krb5_kt_add_entry for enctype=0x%04x\n",
108 : (int)enctype);
109 178 : code = smb_krb5_kt_add_entry(context,
110 : keytab,
111 87 : sentry.kvno,
112 : entry_principal,
113 : NULL,
114 : enctype,
115 : &password,
116 : true, /* no_salt */
117 : false); /* keeyp_old_entries */
118 91 : if (code != 0) {
119 0 : status = NT_STATUS_UNSUCCESSFUL;
120 0 : *error_string = smb_get_krb5_error_message(context,
121 : code,
122 : mem_ctx);
123 0 : DEBUG(0, ("smb_krb5_kt_add_entry failed code=%d, error = %s\n",
124 : code, *error_string));
125 0 : goto done;
126 : }
127 : }
128 :
129 33 : if (copy_one_principal) {
130 9 : break;
131 : }
132 :
133 24 : SAFE_FREE(entry_principal);
134 24 : sdb_entry_free(&sentry);
135 : }
136 :
137 11 : if (code != 0 && code != SDB_ERR_NOENTRY) {
138 0 : *error_string = smb_get_krb5_error_message(context,
139 : code,
140 : mem_ctx);
141 0 : status = NT_STATUS_NO_SUCH_USER;
142 0 : goto done;
143 : }
144 :
145 11 : status = NT_STATUS_OK;
146 11 : done:
147 11 : SAFE_FREE(entry_principal);
148 11 : sdb_entry_free(&sentry);
149 :
150 11 : return status;
151 : }
152 :
153 11 : NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r)
154 : {
155 : krb5_error_code ret;
156 : struct smb_krb5_context *smb_krb5_context;
157 : struct samba_kdc_base_context *base_ctx;
158 11 : struct samba_kdc_db_context *db_ctx = NULL;
159 11 : const char *error_string = NULL;
160 : NTSTATUS status;
161 :
162 11 : ret = smb_krb5_init_context(ctx, ctx->lp_ctx, &smb_krb5_context);
163 11 : if (ret) {
164 0 : return NT_STATUS_NO_MEMORY;
165 : }
166 :
167 11 : base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context);
168 11 : if (base_ctx == NULL) {
169 0 : return NT_STATUS_NO_MEMORY;
170 : }
171 :
172 11 : base_ctx->ev_ctx = ctx->event_ctx;
173 11 : base_ctx->lp_ctx = ctx->lp_ctx;
174 :
175 11 : status = samba_kdc_setup_db_ctx(mem_ctx, base_ctx, &db_ctx);
176 11 : if (!NT_STATUS_IS_OK(status)) {
177 0 : return status;
178 : }
179 :
180 11 : if (r->in.principal != NULL) {
181 9 : DEBUG(0, ("Export one principal to %s\n", r->in.keytab_name));
182 16 : status = sdb_kt_copy(mem_ctx,
183 9 : smb_krb5_context->krb5_context,
184 : db_ctx,
185 : r->in.keytab_name,
186 : r->in.principal,
187 : &error_string);
188 : } else {
189 2 : unlink(r->in.keytab_name);
190 2 : DEBUG(0, ("Export complete keytab to %s\n", r->in.keytab_name));
191 4 : status = sdb_kt_copy(mem_ctx,
192 2 : smb_krb5_context->krb5_context,
193 : db_ctx,
194 : r->in.keytab_name,
195 : NULL,
196 : &error_string);
197 : }
198 :
199 11 : talloc_free(db_ctx);
200 11 : talloc_free(base_ctx);
201 :
202 11 : if (!NT_STATUS_IS_OK(status)) {
203 0 : r->out.error_string = error_string;
204 : }
205 :
206 11 : return status;
207 : }
|