Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : dump the remote SAM using rpc samsync operations
4 :
5 : Copyright (C) Guenther Deschner 2008.
6 : Copyright (C) Michael Adam 2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "smb_krb5.h"
24 : #include "ads.h"
25 : #include "secrets.h"
26 : #include "libnet/libnet_keytab.h"
27 :
28 : #ifdef HAVE_KRB5
29 :
30 : /****************************************************************
31 : ****************************************************************/
32 :
33 0 : static int keytab_close(struct libnet_keytab_context *ctx)
34 : {
35 0 : if (!ctx) {
36 0 : return 0;
37 : }
38 :
39 0 : if (ctx->keytab && ctx->context) {
40 0 : krb5_kt_close(ctx->context, ctx->keytab);
41 : }
42 :
43 0 : if (ctx->context) {
44 0 : krb5_free_context(ctx->context);
45 : }
46 :
47 0 : TALLOC_FREE(ctx->ads);
48 :
49 0 : TALLOC_FREE(ctx);
50 :
51 0 : return 0;
52 : }
53 :
54 : /****************************************************************
55 : ****************************************************************/
56 :
57 0 : krb5_error_code libnet_keytab_init(TALLOC_CTX *mem_ctx,
58 : const char *keytab_name,
59 : struct libnet_keytab_context **ctx)
60 : {
61 0 : krb5_error_code ret = 0;
62 0 : krb5_context context = NULL;
63 0 : krb5_keytab keytab = NULL;
64 0 : const char *keytab_string = NULL;
65 :
66 0 : struct libnet_keytab_context *r;
67 :
68 0 : r = talloc_zero(mem_ctx, struct libnet_keytab_context);
69 0 : if (!r) {
70 0 : return ENOMEM;
71 : }
72 :
73 0 : talloc_set_destructor(r, keytab_close);
74 :
75 0 : ret = smb_krb5_init_context_common(&context);
76 0 : if (ret) {
77 0 : DBG_ERR("kerberos init context failed (%s)\n",
78 : error_message(ret));
79 0 : return ret;
80 : }
81 :
82 0 : ret = smb_krb5_kt_open_relative(context,
83 : keytab_name,
84 : true, /* write_access */
85 : &keytab);
86 0 : if (ret) {
87 0 : DBG_WARNING("smb_krb5_kt_open_relative failed (%s)\n",
88 : error_message(ret));
89 0 : krb5_free_context(context);
90 0 : return ret;
91 : }
92 :
93 0 : ret = smb_krb5_kt_get_name(mem_ctx, context, keytab, &keytab_string);
94 0 : if (ret) {
95 0 : krb5_kt_close(context, keytab);
96 0 : krb5_free_context(context);
97 0 : return ret;
98 : }
99 :
100 0 : r->context = context;
101 0 : r->keytab = keytab;
102 0 : r->keytab_name = keytab_string;
103 0 : r->clean_old_entries = false;
104 :
105 0 : *ctx = r;
106 :
107 0 : return 0;
108 : }
109 :
110 : /****************************************************************
111 : ****************************************************************/
112 :
113 : /**
114 : * Remove all entries that have the given principal, kvno and enctype.
115 : */
116 0 : static krb5_error_code libnet_keytab_remove_entries(krb5_context context,
117 : krb5_keytab keytab,
118 : const char *principal,
119 : int kvno,
120 : const krb5_enctype enctype,
121 : bool ignore_kvno)
122 : {
123 0 : krb5_error_code ret;
124 0 : krb5_kt_cursor cursor;
125 0 : krb5_keytab_entry kt_entry;
126 :
127 0 : ZERO_STRUCT(kt_entry);
128 0 : ZERO_STRUCT(cursor);
129 :
130 0 : ret = krb5_kt_start_seq_get(context, keytab, &cursor);
131 0 : if (ret) {
132 0 : return 0;
133 : }
134 :
135 0 : while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0)
136 : {
137 0 : krb5_keyblock *keyp;
138 0 : char *princ_s = NULL;
139 :
140 0 : if (kt_entry.vno != kvno && !ignore_kvno) {
141 0 : goto cont;
142 : }
143 :
144 0 : keyp = KRB5_KT_KEY(&kt_entry);
145 :
146 0 : if (KRB5_KEY_TYPE(keyp) != enctype) {
147 0 : goto cont;
148 : }
149 :
150 0 : ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal,
151 : &princ_s);
152 0 : if (ret) {
153 0 : DEBUG(5, ("smb_krb5_unparse_name failed (%s)\n",
154 : error_message(ret)));
155 0 : goto cont;
156 : }
157 :
158 0 : if (strcmp(principal, princ_s) != 0) {
159 0 : goto cont;
160 : }
161 :
162 : /* match found - remove */
163 :
164 0 : DEBUG(10, ("found entry for principal %s, kvno %d, "
165 : "enctype %d - trying to remove it\n",
166 : princ_s, kt_entry.vno, KRB5_KEY_TYPE(keyp)));
167 :
168 0 : ret = krb5_kt_end_seq_get(context, keytab, &cursor);
169 0 : ZERO_STRUCT(cursor);
170 0 : if (ret) {
171 0 : DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n",
172 : error_message(ret)));
173 0 : goto cont;
174 : }
175 :
176 0 : ret = krb5_kt_remove_entry(context, keytab,
177 : &kt_entry);
178 0 : if (ret) {
179 0 : DEBUG(5, ("krb5_kt_remove_entry failed (%s)\n",
180 : error_message(ret)));
181 0 : goto cont;
182 : }
183 0 : DEBUG(10, ("removed entry for principal %s, kvno %d, "
184 : "enctype %d\n", princ_s, kt_entry.vno,
185 : KRB5_KEY_TYPE(keyp)));
186 :
187 0 : ret = krb5_kt_start_seq_get(context, keytab, &cursor);
188 0 : if (ret) {
189 0 : DEBUG(5, ("krb5_kt_start_seq_get failed (%s)\n",
190 : error_message(ret)));
191 0 : goto cont;
192 : }
193 :
194 0 : cont:
195 0 : smb_krb5_kt_free_entry(context, &kt_entry);
196 0 : TALLOC_FREE(princ_s);
197 : }
198 :
199 0 : ret = krb5_kt_end_seq_get(context, keytab, &cursor);
200 0 : if (ret) {
201 0 : DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n",
202 : error_message(ret)));
203 : }
204 :
205 0 : return ret;
206 : }
207 :
208 0 : static krb5_error_code libnet_keytab_add_entry(krb5_context context,
209 : krb5_keytab keytab,
210 : krb5_kvno kvno,
211 : const char *princ_s,
212 : krb5_enctype enctype,
213 : krb5_data password)
214 : {
215 0 : krb5_keyblock *keyp;
216 0 : krb5_keytab_entry kt_entry;
217 0 : krb5_error_code ret;
218 0 : krb5_principal salt_princ = NULL;
219 0 : char *salt_princ_s;
220 :
221 : /* remove duplicates first ... */
222 0 : ret = libnet_keytab_remove_entries(context, keytab, princ_s, kvno,
223 : enctype, false);
224 0 : if (ret) {
225 0 : DEBUG(1, ("libnet_keytab_remove_entries failed: %s\n",
226 : error_message(ret)));
227 : }
228 :
229 0 : ZERO_STRUCT(kt_entry);
230 :
231 0 : kt_entry.vno = kvno;
232 :
233 0 : ret = smb_krb5_parse_name(context, princ_s, &kt_entry.principal);
234 0 : if (ret) {
235 0 : DEBUG(1, ("smb_krb5_parse_name(%s) failed (%s)\n",
236 : princ_s, error_message(ret)));
237 0 : return ret;
238 : }
239 :
240 0 : keyp = KRB5_KT_KEY(&kt_entry);
241 :
242 0 : salt_princ_s = kerberos_secrets_fetch_salt_princ();
243 0 : if (salt_princ_s == NULL) {
244 0 : ret = KRB5KRB_ERR_GENERIC;
245 0 : goto done;
246 : }
247 :
248 0 : ret = krb5_parse_name(context, salt_princ_s, &salt_princ);
249 0 : SAFE_FREE(salt_princ_s);
250 0 : if (ret != 0) {
251 0 : ret = KRB5KRB_ERR_GENERIC;
252 0 : goto done;
253 : }
254 :
255 0 : ret = create_kerberos_key_from_string(context,
256 : kt_entry.principal,
257 : salt_princ,
258 : &password,
259 : keyp,
260 : enctype,
261 : true);
262 0 : krb5_free_principal(context, salt_princ);
263 0 : if (ret != 0) {
264 0 : ret = KRB5KRB_ERR_GENERIC;
265 0 : goto done;
266 : }
267 :
268 0 : ret = krb5_kt_add_entry(context, keytab, &kt_entry);
269 0 : if (ret) {
270 0 : DEBUG(1, ("adding entry to keytab failed (%s)\n",
271 : error_message(ret)));
272 : }
273 :
274 0 : done:
275 0 : krb5_free_keyblock_contents(context, keyp);
276 0 : krb5_free_principal(context, kt_entry.principal);
277 0 : ZERO_STRUCT(kt_entry);
278 0 : smb_krb5_kt_free_entry(context, &kt_entry);
279 :
280 0 : return ret;
281 : }
282 :
283 0 : krb5_error_code libnet_keytab_add(struct libnet_keytab_context *ctx)
284 : {
285 0 : krb5_error_code ret = 0;
286 0 : uint32_t i;
287 :
288 :
289 0 : if (ctx->clean_old_entries) {
290 0 : DEBUG(0, ("cleaning old entries...\n"));
291 0 : for (i=0; i < ctx->count; i++) {
292 0 : struct libnet_keytab_entry *entry = &ctx->entries[i];
293 :
294 0 : ret = libnet_keytab_remove_entries(ctx->context,
295 : ctx->keytab,
296 : entry->principal,
297 : 0,
298 : entry->enctype,
299 : true);
300 0 : if (ret) {
301 0 : DEBUG(1,("libnet_keytab_add: Failed to remove "
302 : "old entries for %s (enctype %u): %s\n",
303 : entry->principal, entry->enctype,
304 : error_message(ret)));
305 0 : return ret;
306 : }
307 : }
308 : }
309 :
310 0 : for (i=0; i<ctx->count; i++) {
311 :
312 0 : struct libnet_keytab_entry *entry = &ctx->entries[i];
313 0 : krb5_data password;
314 :
315 0 : ZERO_STRUCT(password);
316 0 : password.data = (char *)entry->password.data;
317 0 : password.length = entry->password.length;
318 :
319 0 : ret = libnet_keytab_add_entry(ctx->context,
320 : ctx->keytab,
321 0 : entry->kvno,
322 : entry->principal,
323 : entry->enctype,
324 : password);
325 0 : if (ret) {
326 0 : DEBUG(1,("libnet_keytab_add: "
327 : "Failed to add entry to keytab file\n"));
328 0 : return ret;
329 : }
330 : }
331 :
332 0 : return ret;
333 : }
334 :
335 0 : struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *ctx,
336 : const char *principal,
337 : int kvno,
338 : const krb5_enctype enctype,
339 : TALLOC_CTX *mem_ctx)
340 : {
341 0 : krb5_error_code ret = 0;
342 0 : krb5_kt_cursor cursor;
343 0 : krb5_keytab_entry kt_entry;
344 0 : struct libnet_keytab_entry *entry = NULL;
345 :
346 0 : ZERO_STRUCT(kt_entry);
347 0 : ZERO_STRUCT(cursor);
348 :
349 0 : ret = krb5_kt_start_seq_get(ctx->context, ctx->keytab, &cursor);
350 0 : if (ret) {
351 0 : DEBUG(10, ("krb5_kt_start_seq_get failed: %s\n",
352 : error_message(ret)));
353 0 : return NULL;
354 : }
355 :
356 0 : while (krb5_kt_next_entry(ctx->context, ctx->keytab, &kt_entry, &cursor) == 0)
357 0 : {
358 0 : krb5_keyblock *keyp;
359 0 : char *princ_s = NULL;
360 :
361 0 : entry = NULL;
362 :
363 0 : if (kt_entry.vno != kvno) {
364 0 : goto cont;
365 : }
366 :
367 0 : keyp = KRB5_KT_KEY(&kt_entry);
368 :
369 0 : if (KRB5_KEY_TYPE(keyp) != enctype) {
370 0 : goto cont;
371 : }
372 :
373 0 : entry = talloc_zero(mem_ctx, struct libnet_keytab_entry);
374 0 : if (!entry) {
375 0 : DEBUG(3, ("talloc failed\n"));
376 0 : goto fail;
377 : }
378 :
379 0 : ret = smb_krb5_unparse_name(entry, ctx->context, kt_entry.principal,
380 : &princ_s);
381 0 : if (ret) {
382 0 : goto cont;
383 : }
384 :
385 0 : if (strcmp(principal, princ_s) != 0) {
386 0 : goto cont;
387 : }
388 :
389 0 : entry->principal = talloc_strdup(entry, princ_s);
390 0 : if (!entry->principal) {
391 0 : DEBUG(3, ("talloc_strdup_failed\n"));
392 0 : goto fail;
393 : }
394 :
395 0 : entry->name = talloc_move(entry, &princ_s);
396 :
397 0 : entry->password = data_blob_talloc(entry, KRB5_KEY_DATA(keyp),
398 : KRB5_KEY_LENGTH(keyp));
399 0 : if (!entry->password.data) {
400 0 : DEBUG(3, ("data_blob_talloc failed\n"));
401 0 : goto fail;
402 : }
403 :
404 0 : DEBUG(10, ("found entry\n"));
405 :
406 0 : smb_krb5_kt_free_entry(ctx->context, &kt_entry);
407 0 : break;
408 :
409 0 : fail:
410 0 : smb_krb5_kt_free_entry(ctx->context, &kt_entry);
411 0 : TALLOC_FREE(entry);
412 0 : break;
413 :
414 0 : cont:
415 0 : smb_krb5_kt_free_entry(ctx->context, &kt_entry);
416 0 : TALLOC_FREE(entry);
417 0 : continue;
418 : }
419 :
420 0 : krb5_kt_end_seq_get(ctx->context, ctx->keytab, &cursor);
421 0 : return entry;
422 : }
423 :
424 : /**
425 : * Helper function to add data to the list
426 : * of keytab entries. It builds the prefix from the input.
427 : */
428 0 : NTSTATUS libnet_keytab_add_to_keytab_entries(TALLOC_CTX *mem_ctx,
429 : struct libnet_keytab_context *ctx,
430 : uint32_t kvno,
431 : const char *name,
432 : const char *prefix,
433 : const krb5_enctype enctype,
434 : DATA_BLOB blob)
435 : {
436 0 : struct libnet_keytab_entry entry;
437 :
438 0 : entry.kvno = kvno;
439 0 : entry.name = talloc_strdup(mem_ctx, name);
440 0 : entry.principal = talloc_asprintf(mem_ctx, "%s%s%s@%s",
441 : prefix ? prefix : "",
442 : prefix ? "/" : "",
443 : name, ctx->dns_domain_name);
444 0 : entry.enctype = enctype;
445 0 : entry.password = blob;
446 0 : NT_STATUS_HAVE_NO_MEMORY(entry.name);
447 0 : NT_STATUS_HAVE_NO_MEMORY(entry.principal);
448 0 : NT_STATUS_HAVE_NO_MEMORY(entry.password.data);
449 :
450 0 : ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry,
451 : &ctx->entries, &ctx->count);
452 0 : NT_STATUS_HAVE_NO_MEMORY(ctx->entries);
453 :
454 0 : return NT_STATUS_OK;
455 : }
456 :
457 : #endif /* HAVE_KRB5 */
|