Revert "s3:smbd: set req->smb2req->compat_chain_fsp in file_fsp()"
[Samba/gebeck_regimport.git] / source3 / librpc / crypto / gse_krb5.c
blobc1eea7fc705265307a9171aa7d28fe7e7fd5fd3d
1 /*
2 * GSSAPI Security Extensions
3 * Krb5 helpers
4 * Copyright (C) Simo Sorce 2010.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smb_krb5.h"
22 #include "secrets.h"
23 #include "gse_krb5.h"
25 #ifdef HAVE_KRB5
27 static krb5_error_code flush_keytab(krb5_context krbctx, krb5_keytab keytab)
29 krb5_error_code ret;
30 krb5_kt_cursor kt_cursor;
31 krb5_keytab_entry kt_entry;
33 ZERO_STRUCT(kt_entry);
35 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
36 if (ret == KRB5_KT_END || ret == ENOENT ) {
37 /* no entries */
38 return 0;
41 ret = krb5_kt_next_entry(krbctx, keytab, &kt_entry, &kt_cursor);
42 while (ret == 0) {
44 /* we need to close and reopen enumeration because we modify
45 * the keytab */
46 ret = krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
47 if (ret) {
48 DEBUG(1, (__location__ ": krb5_kt_end_seq_get() "
49 "failed (%s)\n", error_message(ret)));
50 goto out;
53 /* remove the entry */
54 ret = krb5_kt_remove_entry(krbctx, keytab, &kt_entry);
55 if (ret) {
56 DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
57 "failed (%s)\n", error_message(ret)));
58 goto out;
60 ret = smb_krb5_kt_free_entry(krbctx, &kt_entry);
61 ZERO_STRUCT(kt_entry);
63 /* now reopen */
64 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
65 if (ret) {
66 DEBUG(1, (__location__ ": krb5_kt_start_seq() failed "
67 "(%s)\n", error_message(ret)));
68 goto out;
71 ret = krb5_kt_next_entry(krbctx, keytab,
72 &kt_entry, &kt_cursor);
75 if (ret != KRB5_KT_END && ret != ENOENT) {
76 DEBUG(1, (__location__ ": flushing keytab we got [%s]!\n",
77 error_message(ret)));
80 ret = 0;
82 out:
83 return ret;
86 static krb5_error_code get_host_principal(krb5_context krbctx,
87 krb5_principal *host_princ)
89 krb5_error_code ret;
90 char *host_princ_s = NULL;
91 int err;
93 err = asprintf(&host_princ_s, "%s$@%s", lp_netbios_name(), lp_realm());
94 if (err == -1) {
95 return -1;
98 strlower_m(host_princ_s);
99 ret = smb_krb5_parse_name(krbctx, host_princ_s, host_princ);
100 if (ret) {
101 DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
102 "failed (%s)\n",
103 host_princ_s, error_message(ret)));
106 SAFE_FREE(host_princ_s);
107 return ret;
110 static krb5_error_code fill_keytab_from_password(krb5_context krbctx,
111 krb5_keytab keytab,
112 krb5_principal princ,
113 krb5_kvno vno,
114 krb5_data *password)
116 krb5_error_code ret;
117 krb5_enctype *enctypes;
118 krb5_keytab_entry kt_entry;
119 unsigned int i;
121 ret = get_kerberos_allowed_etypes(krbctx, &enctypes);
122 if (ret) {
123 DEBUG(1, (__location__
124 ": Can't determine permitted enctypes!\n"));
125 return ret;
128 for (i = 0; enctypes[i]; i++) {
129 krb5_keyblock *key = NULL;
131 if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
132 ret = ENOMEM;
133 goto out;
136 if (create_kerberos_key_from_string(krbctx, princ,
137 password, key,
138 enctypes[i], false)) {
139 DEBUG(10, ("Failed to create key for enctype %d "
140 "(error: %s)\n",
141 enctypes[i], error_message(ret)));
142 SAFE_FREE(key);
143 continue;
146 kt_entry.principal = princ;
147 kt_entry.vno = vno;
148 *(KRB5_KT_KEY(&kt_entry)) = *key;
150 ret = krb5_kt_add_entry(krbctx, keytab, &kt_entry);
151 if (ret) {
152 DEBUG(1, (__location__ ": Failed to add entry to "
153 "keytab for enctype %d (error: %s)\n",
154 enctypes[i], error_message(ret)));
155 krb5_free_keyblock(krbctx, key);
156 goto out;
159 krb5_free_keyblock(krbctx, key);
162 ret = 0;
164 out:
165 SAFE_FREE(enctypes);
166 return ret;
169 #define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab"
170 #define CLEARTEXT_PRIV_ENCTYPE -99
172 static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx,
173 krb5_keytab *keytab)
175 krb5_error_code ret;
176 char *pwd = NULL;
177 size_t pwd_len;
178 krb5_kt_cursor kt_cursor;
179 krb5_keytab_entry kt_entry;
180 krb5_data password;
181 krb5_principal princ = NULL;
182 krb5_kvno kvno = 0; /* FIXME: fetch current vno from KDC ? */
183 char *pwd_old = NULL;
185 if (!secrets_init()) {
186 DEBUG(1, (__location__ ": secrets_init failed\n"));
187 return KRB5_CONFIG_CANTOPEN;
190 pwd = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
191 if (!pwd) {
192 DEBUG(2, (__location__ ": failed to fetch machine password\n"));
193 return KRB5_LIBOS_CANTREADPWD;
195 pwd_len = strlen(pwd);
197 ZERO_STRUCT(kt_entry);
198 ZERO_STRUCT(kt_cursor);
200 /* check if the keytab already has any entry */
201 ret = krb5_kt_start_seq_get(krbctx, *keytab, &kt_cursor);
202 if (ret != KRB5_KT_END && ret != ENOENT ) {
203 /* check if we have our special enctype used to hold
204 * the clear text password. If so, check it out so that
205 * we can verify if the keytab needs to be upgraded */
206 while ((ret = krb5_kt_next_entry(krbctx, *keytab,
207 &kt_entry, &kt_cursor)) == 0) {
208 if (smb_get_enctype_from_kt_entry(&kt_entry) == CLEARTEXT_PRIV_ENCTYPE) {
209 break;
211 smb_krb5_kt_free_entry(krbctx, &kt_entry);
212 ZERO_STRUCT(kt_entry);
215 if (ret != 0 && ret != KRB5_KT_END && ret != ENOENT ) {
216 /* Error parsing keytab */
217 DEBUG(1, (__location__ ": Failed to parse memory "
218 "keytab!\n"));
219 goto out;
222 if (ret == 0) {
223 /* found private entry,
224 * check if keytab is up to date */
226 if ((pwd_len == KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry))) &&
227 (memcmp(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)),
228 pwd, pwd_len) == 0)) {
229 /* keytab is already up to date, return */
230 smb_krb5_kt_free_entry(krbctx, &kt_entry);
231 goto out;
234 smb_krb5_kt_free_entry(krbctx, &kt_entry);
235 ZERO_STRUCT(kt_entry);
238 /* flush keytab, we need to regen it */
239 ret = flush_keytab(krbctx, *keytab);
240 if (ret) {
241 DEBUG(1, (__location__ ": Failed to flush "
242 "memory keytab!\n"));
243 goto out;
249 krb5_kt_cursor zero_csr;
250 ZERO_STRUCT(zero_csr);
251 if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && *keytab) {
252 krb5_kt_end_seq_get(krbctx, *keytab, &kt_cursor);
256 /* keytab is not up to date, fill it up */
258 ret = get_host_principal(krbctx, &princ);
259 if (ret) {
260 DEBUG(1, (__location__ ": Failed to get host principal!\n"));
261 goto out;
264 password.data = pwd;
265 password.length = pwd_len;
266 ret = fill_keytab_from_password(krbctx, *keytab,
267 princ, kvno, &password);
268 if (ret) {
269 DEBUG(1, (__location__ ": Failed to fill memory keytab!\n"));
270 goto out;
273 pwd_old = secrets_fetch_prev_machine_password(lp_workgroup());
274 if (!pwd_old) {
275 DEBUG(10, (__location__ ": no prev machine password\n"));
276 } else {
277 password.data = pwd_old;
278 password.length = strlen(pwd_old);
279 ret = fill_keytab_from_password(krbctx, *keytab,
280 princ, kvno -1, &password);
281 if (ret) {
282 DEBUG(1, (__location__
283 ": Failed to fill memory keytab!\n"));
284 goto out;
288 /* add our private enctype + cleartext password so that we can
289 * update the keytab if secrets change later on */
290 ZERO_STRUCT(kt_entry);
291 kt_entry.principal = princ;
292 kt_entry.vno = 0;
294 KRB5_KEY_TYPE(KRB5_KT_KEY(&kt_entry)) = CLEARTEXT_PRIV_ENCTYPE;
295 KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry)) = pwd_len;
296 KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)) = (uint8_t *)pwd;
298 ret = krb5_kt_add_entry(krbctx, *keytab, &kt_entry);
299 if (ret) {
300 DEBUG(1, (__location__ ": Failed to add entry to "
301 "keytab for private enctype (%d) (error: %s)\n",
302 CLEARTEXT_PRIV_ENCTYPE, error_message(ret)));
303 goto out;
306 ret = 0;
308 out:
309 SAFE_FREE(pwd);
310 SAFE_FREE(pwd_old);
313 krb5_kt_cursor zero_csr;
314 ZERO_STRUCT(zero_csr);
315 if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && *keytab) {
316 krb5_kt_end_seq_get(krbctx, *keytab, &kt_cursor);
320 if (princ) {
321 krb5_free_principal(krbctx, princ);
324 return ret;
327 static krb5_error_code fill_mem_keytab_from_system_keytab(krb5_context krbctx,
328 krb5_keytab *mkeytab)
330 krb5_error_code ret = 0;
331 krb5_keytab keytab = NULL;
332 krb5_kt_cursor kt_cursor;
333 krb5_keytab_entry kt_entry;
334 char *valid_princ_formats[7] = { NULL, NULL, NULL,
335 NULL, NULL, NULL, NULL };
336 char *entry_princ_s = NULL;
337 fstring my_name, my_fqdn;
338 int i;
339 int err;
341 /* Generate the list of principal names which we expect
342 * clients might want to use for authenticating to the file
343 * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */
345 fstrcpy(my_name, lp_netbios_name());
347 my_fqdn[0] = '\0';
348 name_to_fqdn(my_fqdn, lp_netbios_name());
350 err = asprintf(&valid_princ_formats[0],
351 "%s$@%s", my_name, lp_realm());
352 if (err == -1) {
353 ret = ENOMEM;
354 goto out;
356 err = asprintf(&valid_princ_formats[1],
357 "host/%s@%s", my_name, lp_realm());
358 if (err == -1) {
359 ret = ENOMEM;
360 goto out;
362 err = asprintf(&valid_princ_formats[2],
363 "host/%s@%s", my_fqdn, lp_realm());
364 if (err == -1) {
365 ret = ENOMEM;
366 goto out;
368 err = asprintf(&valid_princ_formats[3],
369 "host/%s.%s@%s", my_name, lp_realm(), lp_realm());
370 if (err == -1) {
371 ret = ENOMEM;
372 goto out;
374 err = asprintf(&valid_princ_formats[4],
375 "cifs/%s@%s", my_name, lp_realm());
376 if (err == -1) {
377 ret = ENOMEM;
378 goto out;
380 err = asprintf(&valid_princ_formats[5],
381 "cifs/%s@%s", my_fqdn, lp_realm());
382 if (err == -1) {
383 ret = ENOMEM;
384 goto out;
386 err = asprintf(&valid_princ_formats[6],
387 "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm());
388 if (err == -1) {
389 ret = ENOMEM;
390 goto out;
393 ZERO_STRUCT(kt_entry);
394 ZERO_STRUCT(kt_cursor);
396 ret = smb_krb5_open_keytab(krbctx, NULL, false, &keytab);
397 if (ret) {
398 DEBUG(1, (__location__ ": smb_krb5_open_keytab failed (%s)\n",
399 error_message(ret)));
400 goto out;
404 * Iterate through the keytab. For each key, if the principal
405 * name case-insensitively matches one of the allowed formats,
406 * copy it to the memory keytab.
409 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
410 if (ret) {
411 DEBUG(1, (__location__ ": krb5_kt_start_seq_get failed (%s)\n",
412 error_message(ret)));
413 goto out;
416 while ((krb5_kt_next_entry(krbctx, keytab,
417 &kt_entry, &kt_cursor) == 0)) {
418 ret = smb_krb5_unparse_name(talloc_tos(), krbctx,
419 kt_entry.principal,
420 &entry_princ_s);
421 if (ret) {
422 DEBUG(1, (__location__ ": smb_krb5_unparse_name "
423 "failed (%s)\n", error_message(ret)));
424 goto out;
427 for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
429 if (!strequal(entry_princ_s, valid_princ_formats[i])) {
430 continue;
433 ret = krb5_kt_add_entry(krbctx, *mkeytab, &kt_entry);
434 if (ret) {
435 DEBUG(1, (__location__ ": smb_krb5_unparse_name "
436 "failed (%s)\n", error_message(ret)));
437 goto out;
441 /* Free the name we parsed. */
442 TALLOC_FREE(entry_princ_s);
444 /* Free the entry we just read. */
445 smb_krb5_kt_free_entry(krbctx, &kt_entry);
446 ZERO_STRUCT(kt_entry);
448 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
450 ZERO_STRUCT(kt_cursor);
452 out:
454 for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
455 SAFE_FREE(valid_princ_formats[i]);
458 TALLOC_FREE(entry_princ_s);
461 krb5_keytab_entry zero_kt_entry;
462 ZERO_STRUCT(zero_kt_entry);
463 if (memcmp(&zero_kt_entry, &kt_entry,
464 sizeof(krb5_keytab_entry))) {
465 smb_krb5_kt_free_entry(krbctx, &kt_entry);
470 krb5_kt_cursor zero_csr;
471 ZERO_STRUCT(zero_csr);
472 if ((memcmp(&kt_cursor, &zero_csr,
473 sizeof(krb5_kt_cursor)) != 0) && keytab) {
474 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
478 if (keytab) {
479 krb5_kt_close(krbctx, keytab);
482 return ret;
485 static krb5_error_code fill_mem_keytab_from_dedicated_keytab(krb5_context krbctx,
486 krb5_keytab *mkeytab)
488 krb5_error_code ret = 0;
489 krb5_keytab keytab = NULL;
490 krb5_kt_cursor kt_cursor;
491 krb5_keytab_entry kt_entry;
493 ZERO_STRUCT(kt_entry);
494 ZERO_STRUCT(kt_cursor);
496 ret = smb_krb5_open_keytab(krbctx, lp_dedicated_keytab_file(),
497 false, &keytab);
498 if (ret) {
499 DEBUG(1, (__location__ ": smb_krb5_open_keytab failed (%s)\n",
500 error_message(ret)));
501 goto out;
505 * Iterate through the keytab. For each key, if the principal
506 * name case-insensitively matches one of the allowed formats,
507 * copy it to the memory keytab.
510 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
511 if (ret) {
512 DEBUG(1, (__location__ ": krb5_kt_start_seq_get failed (%s)\n",
513 error_message(ret)));
514 goto out;
517 while ((krb5_kt_next_entry(krbctx, keytab,
518 &kt_entry, &kt_cursor) == 0)) {
520 ret = krb5_kt_add_entry(krbctx, *mkeytab, &kt_entry);
521 if (ret) {
522 DEBUG(1, (__location__ ": smb_krb5_unparse_name "
523 "failed (%s)\n", error_message(ret)));
524 goto out;
527 /* Free the entry we just read. */
528 smb_krb5_kt_free_entry(krbctx, &kt_entry);
529 ZERO_STRUCT(kt_entry);
531 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
533 ZERO_STRUCT(kt_cursor);
535 out:
538 krb5_keytab_entry zero_kt_entry;
539 ZERO_STRUCT(zero_kt_entry);
540 if (memcmp(&zero_kt_entry, &kt_entry,
541 sizeof(krb5_keytab_entry))) {
542 smb_krb5_kt_free_entry(krbctx, &kt_entry);
547 krb5_kt_cursor zero_csr;
548 ZERO_STRUCT(zero_csr);
549 if ((memcmp(&kt_cursor, &zero_csr,
550 sizeof(krb5_kt_cursor)) != 0) && keytab) {
551 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
555 if (keytab) {
556 krb5_kt_close(krbctx, keytab);
559 return ret;
562 krb5_error_code gse_krb5_get_server_keytab(krb5_context krbctx,
563 krb5_keytab *keytab)
565 krb5_error_code ret = 0;
566 krb5_error_code ret1 = 0;
567 krb5_error_code ret2 = 0;
569 *keytab = NULL;
571 /* create memory keytab */
572 ret = krb5_kt_resolve(krbctx, SRV_MEM_KEYTAB_NAME, keytab);
573 if (ret) {
574 DEBUG(1, (__location__ ": Failed to get memory "
575 "keytab!\n"));
576 return ret;
579 switch (lp_kerberos_method()) {
580 default:
581 case KERBEROS_VERIFY_SECRETS:
582 ret = fill_mem_keytab_from_secrets(krbctx, keytab);
583 break;
584 case KERBEROS_VERIFY_SYSTEM_KEYTAB:
585 ret = fill_mem_keytab_from_system_keytab(krbctx, keytab);
586 break;
587 case KERBEROS_VERIFY_DEDICATED_KEYTAB:
588 /* just use whatever keytab is configured */
589 ret = fill_mem_keytab_from_dedicated_keytab(krbctx, keytab);
590 break;
591 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
592 ret1 = fill_mem_keytab_from_secrets(krbctx, keytab);
593 if (ret1) {
594 DEBUG(3, (__location__ ": Warning! Unable to set mem "
595 "keytab from secrets!\n"));
597 /* Now append system keytab keys too */
598 ret2 = fill_mem_keytab_from_system_keytab(krbctx, keytab);
599 if (ret2) {
600 DEBUG(3, (__location__ ": Warning! Unable to set mem "
601 "keytab from system keytab!\n"));
603 if (ret1 == 0 || ret2 == 0) {
604 ret = 0;
605 } else {
606 ret = ret1;
608 break;
611 if (ret) {
612 krb5_kt_close(krbctx, *keytab);
613 *keytab = NULL;
614 DEBUG(1,("%s: Error! Unable to set mem keytab - %d\n",
615 __location__, ret));
618 return ret;
621 #endif /* HAVE_KRB5 */