2 * GSSAPI Security Extensions
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/>.
24 #include "lib/param/loadparm.h"
28 static krb5_error_code flush_keytab(krb5_context krbctx, krb5_keytab keytab)
31 krb5_kt_cursor kt_cursor;
32 krb5_keytab_entry kt_entry;
34 ZERO_STRUCT(kt_entry);
36 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
37 if (ret == KRB5_KT_END || ret == ENOENT ) {
42 ret = krb5_kt_next_entry(krbctx, keytab, &kt_entry, &kt_cursor);
45 /* we need to close and reopen enumeration because we modify
47 ret = krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
49 DEBUG(1, (__location__ ": krb5_kt_end_seq_get() "
50 "failed (%s)\n", error_message(ret)));
54 /* remove the entry */
55 ret = krb5_kt_remove_entry(krbctx, keytab, &kt_entry);
57 DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
58 "failed (%s)\n", error_message(ret)));
61 ret = smb_krb5_kt_free_entry(krbctx, &kt_entry);
62 ZERO_STRUCT(kt_entry);
65 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
67 DEBUG(1, (__location__ ": krb5_kt_start_seq() failed "
68 "(%s)\n", error_message(ret)));
72 ret = krb5_kt_next_entry(krbctx, keytab,
73 &kt_entry, &kt_cursor);
76 if (ret != KRB5_KT_END && ret != ENOENT) {
77 DEBUG(1, (__location__ ": flushing keytab we got [%s]!\n",
87 static krb5_error_code get_host_principal(krb5_context krbctx,
88 krb5_principal *host_princ)
91 char *host_princ_s = NULL;
94 err = asprintf(&host_princ_s, "%s$@%s", lp_netbios_name(), lp_realm());
99 strlower_m(host_princ_s);
100 ret = smb_krb5_parse_name(krbctx, host_princ_s, host_princ);
102 DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
104 host_princ_s, error_message(ret)));
107 SAFE_FREE(host_princ_s);
111 static krb5_error_code fill_keytab_from_password(krb5_context krbctx,
113 krb5_principal princ,
118 krb5_enctype *enctypes;
119 krb5_keytab_entry kt_entry;
122 ret = get_kerberos_allowed_etypes(krbctx, &enctypes);
124 DEBUG(1, (__location__
125 ": Can't determine permitted enctypes!\n"));
129 for (i = 0; enctypes[i]; i++) {
130 krb5_keyblock *key = NULL;
132 if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
137 if (create_kerberos_key_from_string(krbctx, princ,
139 enctypes[i], false)) {
140 DEBUG(10, ("Failed to create key for enctype %d "
142 enctypes[i], error_message(ret)));
147 kt_entry.principal = princ;
149 *(KRB5_KT_KEY(&kt_entry)) = *key;
151 ret = krb5_kt_add_entry(krbctx, keytab, &kt_entry);
153 DEBUG(1, (__location__ ": Failed to add entry to "
154 "keytab for enctype %d (error: %s)\n",
155 enctypes[i], error_message(ret)));
156 krb5_free_keyblock(krbctx, key);
160 krb5_free_keyblock(krbctx, key);
170 #define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab"
171 #define CLEARTEXT_PRIV_ENCTYPE -99
173 static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx,
179 krb5_kt_cursor kt_cursor;
180 krb5_keytab_entry kt_entry;
182 krb5_principal princ = NULL;
183 krb5_kvno kvno = 0; /* FIXME: fetch current vno from KDC ? */
184 char *pwd_old = NULL;
186 if (!secrets_init()) {
187 DEBUG(1, (__location__ ": secrets_init failed\n"));
188 return KRB5_CONFIG_CANTOPEN;
191 pwd = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
193 DEBUG(2, (__location__ ": failed to fetch machine password\n"));
194 return KRB5_LIBOS_CANTREADPWD;
196 pwd_len = strlen(pwd);
198 ZERO_STRUCT(kt_entry);
199 ZERO_STRUCT(kt_cursor);
201 /* check if the keytab already has any entry */
202 ret = krb5_kt_start_seq_get(krbctx, *keytab, &kt_cursor);
203 if (ret != KRB5_KT_END && ret != ENOENT ) {
204 /* check if we have our special enctype used to hold
205 * the clear text password. If so, check it out so that
206 * we can verify if the keytab needs to be upgraded */
207 while ((ret = krb5_kt_next_entry(krbctx, *keytab,
208 &kt_entry, &kt_cursor)) == 0) {
209 if (smb_get_enctype_from_kt_entry(&kt_entry) == CLEARTEXT_PRIV_ENCTYPE) {
212 smb_krb5_kt_free_entry(krbctx, &kt_entry);
213 ZERO_STRUCT(kt_entry);
216 if (ret != 0 && ret != KRB5_KT_END && ret != ENOENT ) {
217 /* Error parsing keytab */
218 DEBUG(1, (__location__ ": Failed to parse memory "
224 /* found private entry,
225 * check if keytab is up to date */
227 if ((pwd_len == KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry))) &&
228 (memcmp(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)),
229 pwd, pwd_len) == 0)) {
230 /* keytab is already up to date, return */
231 smb_krb5_kt_free_entry(krbctx, &kt_entry);
235 smb_krb5_kt_free_entry(krbctx, &kt_entry);
236 ZERO_STRUCT(kt_entry);
239 /* flush keytab, we need to regen it */
240 ret = flush_keytab(krbctx, *keytab);
242 DEBUG(1, (__location__ ": Failed to flush "
243 "memory keytab!\n"));
250 krb5_kt_cursor zero_csr;
251 ZERO_STRUCT(zero_csr);
252 if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && *keytab) {
253 krb5_kt_end_seq_get(krbctx, *keytab, &kt_cursor);
257 /* keytab is not up to date, fill it up */
259 ret = get_host_principal(krbctx, &princ);
261 DEBUG(1, (__location__ ": Failed to get host principal!\n"));
266 password.length = pwd_len;
267 ret = fill_keytab_from_password(krbctx, *keytab,
268 princ, kvno, &password);
270 DEBUG(1, (__location__ ": Failed to fill memory keytab!\n"));
274 pwd_old = secrets_fetch_prev_machine_password(lp_workgroup());
276 DEBUG(10, (__location__ ": no prev machine password\n"));
278 password.data = pwd_old;
279 password.length = strlen(pwd_old);
280 ret = fill_keytab_from_password(krbctx, *keytab,
281 princ, kvno -1, &password);
283 DEBUG(1, (__location__
284 ": Failed to fill memory keytab!\n"));
289 /* add our private enctype + cleartext password so that we can
290 * update the keytab if secrets change later on */
291 ZERO_STRUCT(kt_entry);
292 kt_entry.principal = princ;
295 KRB5_KEY_TYPE(KRB5_KT_KEY(&kt_entry)) = CLEARTEXT_PRIV_ENCTYPE;
296 KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry)) = pwd_len;
297 KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)) = (uint8_t *)pwd;
299 ret = krb5_kt_add_entry(krbctx, *keytab, &kt_entry);
301 DEBUG(1, (__location__ ": Failed to add entry to "
302 "keytab for private enctype (%d) (error: %s)\n",
303 CLEARTEXT_PRIV_ENCTYPE, error_message(ret)));
314 krb5_kt_cursor zero_csr;
315 ZERO_STRUCT(zero_csr);
316 if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && *keytab) {
317 krb5_kt_end_seq_get(krbctx, *keytab, &kt_cursor);
322 krb5_free_principal(krbctx, princ);
328 static krb5_error_code fill_mem_keytab_from_system_keytab(krb5_context krbctx,
329 krb5_keytab *mkeytab)
331 krb5_error_code ret = 0;
332 krb5_keytab keytab = NULL;
333 krb5_kt_cursor kt_cursor;
334 krb5_keytab_entry kt_entry;
335 char *valid_princ_formats[7] = { NULL, NULL, NULL,
336 NULL, NULL, NULL, NULL };
337 char *entry_princ_s = NULL;
338 fstring my_name, my_fqdn;
342 /* Generate the list of principal names which we expect
343 * clients might want to use for authenticating to the file
344 * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */
346 fstrcpy(my_name, lp_netbios_name());
349 name_to_fqdn(my_fqdn, lp_netbios_name());
351 err = asprintf(&valid_princ_formats[0],
352 "%s$@%s", my_name, lp_realm());
357 err = asprintf(&valid_princ_formats[1],
358 "host/%s@%s", my_name, lp_realm());
363 err = asprintf(&valid_princ_formats[2],
364 "host/%s@%s", my_fqdn, lp_realm());
369 err = asprintf(&valid_princ_formats[3],
370 "host/%s.%s@%s", my_name, lp_realm(), lp_realm());
375 err = asprintf(&valid_princ_formats[4],
376 "cifs/%s@%s", my_name, lp_realm());
381 err = asprintf(&valid_princ_formats[5],
382 "cifs/%s@%s", my_fqdn, lp_realm());
387 err = asprintf(&valid_princ_formats[6],
388 "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm());
394 ZERO_STRUCT(kt_entry);
395 ZERO_STRUCT(kt_cursor);
397 ret = smb_krb5_open_keytab(krbctx, NULL, false, &keytab);
399 DEBUG(1, (__location__ ": smb_krb5_open_keytab failed (%s)\n",
400 error_message(ret)));
405 * Iterate through the keytab. For each key, if the principal
406 * name case-insensitively matches one of the allowed formats,
407 * copy it to the memory keytab.
410 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
412 DEBUG(1, (__location__ ": krb5_kt_start_seq_get failed (%s)\n",
413 error_message(ret)));
417 while ((krb5_kt_next_entry(krbctx, keytab,
418 &kt_entry, &kt_cursor) == 0)) {
419 ret = smb_krb5_unparse_name(talloc_tos(), krbctx,
423 DEBUG(1, (__location__ ": smb_krb5_unparse_name "
424 "failed (%s)\n", error_message(ret)));
428 for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
430 if (!strequal(entry_princ_s, valid_princ_formats[i])) {
434 ret = krb5_kt_add_entry(krbctx, *mkeytab, &kt_entry);
436 DEBUG(1, (__location__ ": smb_krb5_unparse_name "
437 "failed (%s)\n", error_message(ret)));
442 /* Free the name we parsed. */
443 TALLOC_FREE(entry_princ_s);
445 /* Free the entry we just read. */
446 smb_krb5_kt_free_entry(krbctx, &kt_entry);
447 ZERO_STRUCT(kt_entry);
449 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
451 ZERO_STRUCT(kt_cursor);
455 for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
456 SAFE_FREE(valid_princ_formats[i]);
459 TALLOC_FREE(entry_princ_s);
462 krb5_keytab_entry zero_kt_entry;
463 ZERO_STRUCT(zero_kt_entry);
464 if (memcmp(&zero_kt_entry, &kt_entry,
465 sizeof(krb5_keytab_entry))) {
466 smb_krb5_kt_free_entry(krbctx, &kt_entry);
471 krb5_kt_cursor zero_csr;
472 ZERO_STRUCT(zero_csr);
473 if ((memcmp(&kt_cursor, &zero_csr,
474 sizeof(krb5_kt_cursor)) != 0) && keytab) {
475 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
480 krb5_kt_close(krbctx, keytab);
486 static krb5_error_code fill_mem_keytab_from_dedicated_keytab(krb5_context krbctx,
487 krb5_keytab *mkeytab)
489 krb5_error_code ret = 0;
490 krb5_keytab keytab = NULL;
491 krb5_kt_cursor kt_cursor;
492 krb5_keytab_entry kt_entry;
494 ZERO_STRUCT(kt_entry);
495 ZERO_STRUCT(kt_cursor);
497 ret = smb_krb5_open_keytab(krbctx, lp_dedicated_keytab_file(),
500 DEBUG(1, (__location__ ": smb_krb5_open_keytab failed (%s)\n",
501 error_message(ret)));
506 * Iterate through the keytab. For each key, if the principal
507 * name case-insensitively matches one of the allowed formats,
508 * copy it to the memory keytab.
511 ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor);
513 DEBUG(1, (__location__ ": krb5_kt_start_seq_get failed (%s)\n",
514 error_message(ret)));
518 while ((krb5_kt_next_entry(krbctx, keytab,
519 &kt_entry, &kt_cursor) == 0)) {
521 ret = krb5_kt_add_entry(krbctx, *mkeytab, &kt_entry);
523 DEBUG(1, (__location__ ": smb_krb5_unparse_name "
524 "failed (%s)\n", error_message(ret)));
528 /* Free the entry we just read. */
529 smb_krb5_kt_free_entry(krbctx, &kt_entry);
530 ZERO_STRUCT(kt_entry);
532 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
534 ZERO_STRUCT(kt_cursor);
539 krb5_keytab_entry zero_kt_entry;
540 ZERO_STRUCT(zero_kt_entry);
541 if (memcmp(&zero_kt_entry, &kt_entry,
542 sizeof(krb5_keytab_entry))) {
543 smb_krb5_kt_free_entry(krbctx, &kt_entry);
548 krb5_kt_cursor zero_csr;
549 ZERO_STRUCT(zero_csr);
550 if ((memcmp(&kt_cursor, &zero_csr,
551 sizeof(krb5_kt_cursor)) != 0) && keytab) {
552 krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor);
557 krb5_kt_close(krbctx, keytab);
563 krb5_error_code gse_krb5_get_server_keytab(krb5_context krbctx,
566 krb5_error_code ret = 0;
567 krb5_error_code ret1 = 0;
568 krb5_error_code ret2 = 0;
572 /* create memory keytab */
573 ret = krb5_kt_resolve(krbctx, SRV_MEM_KEYTAB_NAME, keytab);
575 DEBUG(1, (__location__ ": Failed to get memory "
580 switch (lp_kerberos_method()) {
582 case KERBEROS_VERIFY_SECRETS:
583 ret = fill_mem_keytab_from_secrets(krbctx, keytab);
585 case KERBEROS_VERIFY_SYSTEM_KEYTAB:
586 ret = fill_mem_keytab_from_system_keytab(krbctx, keytab);
588 case KERBEROS_VERIFY_DEDICATED_KEYTAB:
589 /* just use whatever keytab is configured */
590 ret = fill_mem_keytab_from_dedicated_keytab(krbctx, keytab);
592 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
593 ret1 = fill_mem_keytab_from_secrets(krbctx, keytab);
595 DEBUG(3, (__location__ ": Warning! Unable to set mem "
596 "keytab from secrets!\n"));
598 /* Now append system keytab keys too */
599 ret2 = fill_mem_keytab_from_system_keytab(krbctx, keytab);
601 DEBUG(3, (__location__ ": Warning! Unable to set mem "
602 "keytab from system keytab!\n"));
604 if (ret1 == 0 || ret2 == 0) {
613 krb5_kt_close(krbctx, *keytab);
615 DEBUG(1,("%s: Error! Unable to set mem keytab - %d\n",
622 #endif /* HAVE_KRB5 */