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 if (!strlower_m(host_princ_s
)) {
100 SAFE_FREE(host_princ_s
);
103 ret
= smb_krb5_parse_name(krbctx
, host_princ_s
, host_princ
);
105 DEBUG(1, (__location__
": smb_krb5_parse_name(%s) "
107 host_princ_s
, error_message(ret
)));
110 SAFE_FREE(host_princ_s
);
114 static krb5_error_code
fill_keytab_from_password(krb5_context krbctx
,
116 krb5_principal princ
,
121 krb5_enctype
*enctypes
;
122 krb5_keytab_entry kt_entry
;
125 ret
= get_kerberos_allowed_etypes(krbctx
, &enctypes
);
127 DEBUG(1, (__location__
128 ": Can't determine permitted enctypes!\n"));
132 for (i
= 0; enctypes
[i
]; i
++) {
133 krb5_keyblock
*key
= NULL
;
135 if (!(key
= SMB_MALLOC_P(krb5_keyblock
))) {
140 if (create_kerberos_key_from_string(krbctx
, princ
,
142 enctypes
[i
], false)) {
143 DEBUG(10, ("Failed to create key for enctype %d "
145 enctypes
[i
], error_message(ret
)));
150 kt_entry
.principal
= princ
;
152 *(KRB5_KT_KEY(&kt_entry
)) = *key
;
154 ret
= krb5_kt_add_entry(krbctx
, keytab
, &kt_entry
);
156 DEBUG(1, (__location__
": Failed to add entry to "
157 "keytab for enctype %d (error: %s)\n",
158 enctypes
[i
], error_message(ret
)));
159 krb5_free_keyblock(krbctx
, key
);
163 krb5_free_keyblock(krbctx
, key
);
173 #define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab"
174 #define CLEARTEXT_PRIV_ENCTYPE -99
176 static krb5_error_code
fill_mem_keytab_from_secrets(krb5_context krbctx
,
182 krb5_kt_cursor kt_cursor
;
183 krb5_keytab_entry kt_entry
;
185 krb5_principal princ
= NULL
;
186 krb5_kvno kvno
= 0; /* FIXME: fetch current vno from KDC ? */
187 char *pwd_old
= NULL
;
189 if (!secrets_init()) {
190 DEBUG(1, (__location__
": secrets_init failed\n"));
191 return KRB5_CONFIG_CANTOPEN
;
194 pwd
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
196 DEBUG(2, (__location__
": failed to fetch machine password\n"));
197 return KRB5_LIBOS_CANTREADPWD
;
199 pwd_len
= strlen(pwd
);
201 ZERO_STRUCT(kt_entry
);
202 ZERO_STRUCT(kt_cursor
);
204 /* check if the keytab already has any entry */
205 ret
= krb5_kt_start_seq_get(krbctx
, *keytab
, &kt_cursor
);
206 if (ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
207 /* check if we have our special enctype used to hold
208 * the clear text password. If so, check it out so that
209 * we can verify if the keytab needs to be upgraded */
210 while ((ret
= krb5_kt_next_entry(krbctx
, *keytab
,
211 &kt_entry
, &kt_cursor
)) == 0) {
212 if (smb_get_enctype_from_kt_entry(&kt_entry
) == CLEARTEXT_PRIV_ENCTYPE
) {
215 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
216 ZERO_STRUCT(kt_entry
);
219 if (ret
!= 0 && ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
220 /* Error parsing keytab */
221 DEBUG(1, (__location__
": Failed to parse memory "
227 /* found private entry,
228 * check if keytab is up to date */
230 if ((pwd_len
== KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry
))) &&
231 (memcmp(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry
)),
232 pwd
, pwd_len
) == 0)) {
233 /* keytab is already up to date, return */
234 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
238 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
239 ZERO_STRUCT(kt_entry
);
242 /* flush keytab, we need to regen it */
243 ret
= flush_keytab(krbctx
, *keytab
);
245 DEBUG(1, (__location__
": Failed to flush "
246 "memory keytab!\n"));
253 krb5_kt_cursor zero_csr
;
254 ZERO_STRUCT(zero_csr
);
255 if ((memcmp(&kt_cursor
, &zero_csr
, sizeof(krb5_kt_cursor
)) != 0) && *keytab
) {
256 krb5_kt_end_seq_get(krbctx
, *keytab
, &kt_cursor
);
260 /* keytab is not up to date, fill it up */
262 ret
= get_host_principal(krbctx
, &princ
);
264 DEBUG(1, (__location__
": Failed to get host principal!\n"));
269 password
.length
= pwd_len
;
270 ret
= fill_keytab_from_password(krbctx
, *keytab
,
271 princ
, kvno
, &password
);
273 DEBUG(1, (__location__
": Failed to fill memory keytab!\n"));
277 pwd_old
= secrets_fetch_prev_machine_password(lp_workgroup());
279 DEBUG(10, (__location__
": no prev machine password\n"));
281 password
.data
= pwd_old
;
282 password
.length
= strlen(pwd_old
);
283 ret
= fill_keytab_from_password(krbctx
, *keytab
,
284 princ
, kvno
-1, &password
);
286 DEBUG(1, (__location__
287 ": Failed to fill memory keytab!\n"));
292 /* add our private enctype + cleartext password so that we can
293 * update the keytab if secrets change later on */
294 ZERO_STRUCT(kt_entry
);
295 kt_entry
.principal
= princ
;
298 KRB5_KEY_TYPE(KRB5_KT_KEY(&kt_entry
)) = CLEARTEXT_PRIV_ENCTYPE
;
299 KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry
)) = pwd_len
;
300 KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry
)) = (uint8_t *)pwd
;
302 ret
= krb5_kt_add_entry(krbctx
, *keytab
, &kt_entry
);
304 DEBUG(1, (__location__
": Failed to add entry to "
305 "keytab for private enctype (%d) (error: %s)\n",
306 CLEARTEXT_PRIV_ENCTYPE
, error_message(ret
)));
317 krb5_kt_cursor zero_csr
;
318 ZERO_STRUCT(zero_csr
);
319 if ((memcmp(&kt_cursor
, &zero_csr
, sizeof(krb5_kt_cursor
)) != 0) && *keytab
) {
320 krb5_kt_end_seq_get(krbctx
, *keytab
, &kt_cursor
);
325 krb5_free_principal(krbctx
, princ
);
331 static krb5_error_code
fill_mem_keytab_from_system_keytab(krb5_context krbctx
,
332 krb5_keytab
*mkeytab
)
334 krb5_error_code ret
= 0;
335 krb5_keytab keytab
= NULL
;
336 krb5_kt_cursor kt_cursor
;
337 krb5_keytab_entry kt_entry
;
338 char *valid_princ_formats
[7] = { NULL
, NULL
, NULL
,
339 NULL
, NULL
, NULL
, NULL
};
340 char *entry_princ_s
= NULL
;
341 fstring my_name
, my_fqdn
;
345 /* Generate the list of principal names which we expect
346 * clients might want to use for authenticating to the file
347 * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */
349 fstrcpy(my_name
, lp_netbios_name());
352 name_to_fqdn(my_fqdn
, lp_netbios_name());
354 err
= asprintf(&valid_princ_formats
[0],
355 "%s$@%s", my_name
, lp_realm());
360 err
= asprintf(&valid_princ_formats
[1],
361 "host/%s@%s", my_name
, lp_realm());
366 err
= asprintf(&valid_princ_formats
[2],
367 "host/%s@%s", my_fqdn
, lp_realm());
372 err
= asprintf(&valid_princ_formats
[3],
373 "host/%s.%s@%s", my_name
, lp_realm(), lp_realm());
378 err
= asprintf(&valid_princ_formats
[4],
379 "cifs/%s@%s", my_name
, lp_realm());
384 err
= asprintf(&valid_princ_formats
[5],
385 "cifs/%s@%s", my_fqdn
, lp_realm());
390 err
= asprintf(&valid_princ_formats
[6],
391 "cifs/%s.%s@%s", my_name
, lp_realm(), lp_realm());
397 ZERO_STRUCT(kt_entry
);
398 ZERO_STRUCT(kt_cursor
);
400 ret
= smb_krb5_open_keytab(krbctx
, NULL
, false, &keytab
);
402 DEBUG(1, (__location__
": smb_krb5_open_keytab failed (%s)\n",
403 error_message(ret
)));
408 * Iterate through the keytab. For each key, if the principal
409 * name case-insensitively matches one of the allowed formats,
410 * copy it to the memory keytab.
413 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
415 DEBUG(1, (__location__
": krb5_kt_start_seq_get failed (%s)\n",
416 error_message(ret
)));
420 while ((krb5_kt_next_entry(krbctx
, keytab
,
421 &kt_entry
, &kt_cursor
) == 0)) {
422 ret
= smb_krb5_unparse_name(talloc_tos(), krbctx
,
426 DEBUG(1, (__location__
": smb_krb5_unparse_name "
427 "failed (%s)\n", error_message(ret
)));
431 for (i
= 0; i
< ARRAY_SIZE(valid_princ_formats
); i
++) {
433 if (!strequal(entry_princ_s
, valid_princ_formats
[i
])) {
437 ret
= krb5_kt_add_entry(krbctx
, *mkeytab
, &kt_entry
);
439 DEBUG(1, (__location__
": smb_krb5_unparse_name "
440 "failed (%s)\n", error_message(ret
)));
445 /* Free the name we parsed. */
446 TALLOC_FREE(entry_princ_s
);
448 /* Free the entry we just read. */
449 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
450 ZERO_STRUCT(kt_entry
);
452 krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
454 ZERO_STRUCT(kt_cursor
);
458 for (i
= 0; i
< ARRAY_SIZE(valid_princ_formats
); i
++) {
459 SAFE_FREE(valid_princ_formats
[i
]);
462 TALLOC_FREE(entry_princ_s
);
465 krb5_keytab_entry zero_kt_entry
;
466 ZERO_STRUCT(zero_kt_entry
);
467 if (memcmp(&zero_kt_entry
, &kt_entry
,
468 sizeof(krb5_keytab_entry
))) {
469 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
474 krb5_kt_cursor zero_csr
;
475 ZERO_STRUCT(zero_csr
);
476 if ((memcmp(&kt_cursor
, &zero_csr
,
477 sizeof(krb5_kt_cursor
)) != 0) && keytab
) {
478 krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
483 krb5_kt_close(krbctx
, keytab
);
489 static krb5_error_code
fill_mem_keytab_from_dedicated_keytab(krb5_context krbctx
,
490 krb5_keytab
*mkeytab
)
492 krb5_error_code ret
= 0;
493 krb5_keytab keytab
= NULL
;
494 krb5_kt_cursor kt_cursor
;
495 krb5_keytab_entry kt_entry
;
497 ZERO_STRUCT(kt_entry
);
498 ZERO_STRUCT(kt_cursor
);
500 ret
= smb_krb5_open_keytab(krbctx
, lp_dedicated_keytab_file(),
503 DEBUG(1, (__location__
": smb_krb5_open_keytab failed (%s)\n",
504 error_message(ret
)));
509 * Iterate through the keytab. For each key, if the principal
510 * name case-insensitively matches one of the allowed formats,
511 * copy it to the memory keytab.
514 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
516 DEBUG(1, (__location__
": krb5_kt_start_seq_get failed (%s)\n",
517 error_message(ret
)));
521 while ((krb5_kt_next_entry(krbctx
, keytab
,
522 &kt_entry
, &kt_cursor
) == 0)) {
524 ret
= krb5_kt_add_entry(krbctx
, *mkeytab
, &kt_entry
);
526 DEBUG(1, (__location__
": smb_krb5_unparse_name "
527 "failed (%s)\n", error_message(ret
)));
531 /* Free the entry we just read. */
532 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
533 ZERO_STRUCT(kt_entry
);
535 krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
537 ZERO_STRUCT(kt_cursor
);
542 krb5_keytab_entry zero_kt_entry
;
543 ZERO_STRUCT(zero_kt_entry
);
544 if (memcmp(&zero_kt_entry
, &kt_entry
,
545 sizeof(krb5_keytab_entry
))) {
546 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
551 krb5_kt_cursor zero_csr
;
552 ZERO_STRUCT(zero_csr
);
553 if ((memcmp(&kt_cursor
, &zero_csr
,
554 sizeof(krb5_kt_cursor
)) != 0) && keytab
) {
555 krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
560 krb5_kt_close(krbctx
, keytab
);
566 krb5_error_code
gse_krb5_get_server_keytab(krb5_context krbctx
,
569 krb5_error_code ret
= 0;
570 krb5_error_code ret1
= 0;
571 krb5_error_code ret2
= 0;
575 /* create memory keytab */
576 ret
= krb5_kt_resolve(krbctx
, SRV_MEM_KEYTAB_NAME
, keytab
);
578 DEBUG(1, (__location__
": Failed to get memory "
583 switch (lp_kerberos_method()) {
585 case KERBEROS_VERIFY_SECRETS
:
586 ret
= fill_mem_keytab_from_secrets(krbctx
, keytab
);
588 case KERBEROS_VERIFY_SYSTEM_KEYTAB
:
589 ret
= fill_mem_keytab_from_system_keytab(krbctx
, keytab
);
591 case KERBEROS_VERIFY_DEDICATED_KEYTAB
:
592 /* just use whatever keytab is configured */
593 ret
= fill_mem_keytab_from_dedicated_keytab(krbctx
, keytab
);
595 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB
:
596 ret1
= fill_mem_keytab_from_secrets(krbctx
, keytab
);
598 DEBUG(3, (__location__
": Warning! Unable to set mem "
599 "keytab from secrets!\n"));
601 /* Now append system keytab keys too */
602 ret2
= fill_mem_keytab_from_system_keytab(krbctx
, keytab
);
604 DEBUG(3, (__location__
": Warning! Unable to set mem "
605 "keytab from system keytab!\n"));
607 if (ret1
== 0 || ret2
== 0) {
616 krb5_kt_close(krbctx
, *keytab
);
618 DEBUG(1,("%s: Error! Unable to set mem keytab - %d\n",
625 #endif /* HAVE_KRB5 */