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"
25 #include "libads/kerberos_proto.h"
29 static krb5_error_code
flush_keytab(krb5_context krbctx
, krb5_keytab keytab
)
32 krb5_kt_cursor kt_cursor
;
33 krb5_keytab_entry kt_entry
;
35 ZERO_STRUCT(kt_entry
);
37 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
38 if (ret
== KRB5_KT_END
|| ret
== ENOENT
) {
43 ret
= krb5_kt_next_entry(krbctx
, keytab
, &kt_entry
, &kt_cursor
);
46 /* we need to close and reopen enumeration because we modify
48 ret
= krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
50 DEBUG(1, (__location__
": krb5_kt_end_seq_get() "
51 "failed (%s)\n", error_message(ret
)));
55 /* remove the entry */
56 ret
= krb5_kt_remove_entry(krbctx
, keytab
, &kt_entry
);
58 DEBUG(1, (__location__
": krb5_kt_remove_entry() "
59 "failed (%s)\n", error_message(ret
)));
62 ret
= smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
63 ZERO_STRUCT(kt_entry
);
66 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
68 DEBUG(1, (__location__
": krb5_kt_start_seq() failed "
69 "(%s)\n", error_message(ret
)));
73 ret
= krb5_kt_next_entry(krbctx
, keytab
,
74 &kt_entry
, &kt_cursor
);
77 if (ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
78 DEBUG(1, (__location__
": flushing keytab we got [%s]!\n",
88 static krb5_error_code
get_host_principal(krb5_context krbctx
,
89 krb5_principal
*host_princ
)
92 char *host_princ_s
= NULL
;
95 err
= asprintf(&host_princ_s
, "%s$@%s", lp_netbios_name(), lp_realm());
100 if (!strlower_m(host_princ_s
)) {
101 SAFE_FREE(host_princ_s
);
104 ret
= smb_krb5_parse_name(krbctx
, host_princ_s
, host_princ
);
106 DEBUG(1, (__location__
": smb_krb5_parse_name(%s) "
108 host_princ_s
, error_message(ret
)));
111 SAFE_FREE(host_princ_s
);
115 static krb5_error_code
fill_keytab_from_password(krb5_context krbctx
,
117 krb5_principal princ
,
122 krb5_enctype
*enctypes
;
123 krb5_keytab_entry kt_entry
;
126 ret
= smb_krb5_get_allowed_etypes(krbctx
, &enctypes
);
128 DEBUG(1, (__location__
129 ": Can't determine permitted enctypes!\n"));
133 for (i
= 0; enctypes
[i
]; i
++) {
134 krb5_keyblock
*key
= NULL
;
135 krb5_principal salt_princ
= NULL
;
140 if (!(key
= SMB_MALLOC_P(krb5_keyblock
))) {
145 ret
= krb5_unparse_name(krbctx
, princ
, &princ_s
);
151 salt_princ_s
= kerberos_fetch_salt_princ_for_host_princ(krbctx
,
155 if (salt_princ_s
== NULL
) {
160 ret
= krb5_parse_name(krbctx
, salt_princ_s
, &salt_princ
);
161 SAFE_FREE(salt_princ_s
);
167 rc
= create_kerberos_key_from_string(krbctx
,
174 krb5_free_principal(krbctx
, salt_princ
);
176 DEBUG(10, ("Failed to create key for enctype %d "
178 enctypes
[i
], error_message(ret
)));
183 kt_entry
.principal
= princ
;
185 *(KRB5_KT_KEY(&kt_entry
)) = *key
;
187 ret
= krb5_kt_add_entry(krbctx
, keytab
, &kt_entry
);
189 DEBUG(1, (__location__
": Failed to add entry to "
190 "keytab for enctype %d (error: %s)\n",
191 enctypes
[i
], error_message(ret
)));
192 krb5_free_keyblock(krbctx
, key
);
196 krb5_free_keyblock(krbctx
, key
);
206 #define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab"
207 #define CLEARTEXT_PRIV_ENCTYPE -99
209 static krb5_error_code
fill_mem_keytab_from_secrets(krb5_context krbctx
,
215 krb5_kt_cursor kt_cursor
;
216 krb5_keytab_entry kt_entry
;
218 krb5_principal princ
= NULL
;
219 krb5_kvno kvno
= 0; /* FIXME: fetch current vno from KDC ? */
220 char *pwd_old
= NULL
;
222 if (!secrets_init()) {
223 DEBUG(1, (__location__
": secrets_init failed\n"));
224 return KRB5_CONFIG_CANTOPEN
;
227 pwd
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
229 DEBUG(2, (__location__
": failed to fetch machine password\n"));
230 return KRB5_LIBOS_CANTREADPWD
;
232 pwd_len
= strlen(pwd
);
234 ZERO_STRUCT(kt_entry
);
235 ZERO_STRUCT(kt_cursor
);
237 /* check if the keytab already has any entry */
238 ret
= krb5_kt_start_seq_get(krbctx
, *keytab
, &kt_cursor
);
239 if (ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
240 /* check if we have our special enctype used to hold
241 * the clear text password. If so, check it out so that
242 * we can verify if the keytab needs to be upgraded */
243 while ((ret
= krb5_kt_next_entry(krbctx
, *keytab
,
244 &kt_entry
, &kt_cursor
)) == 0) {
245 if (smb_krb5_kt_get_enctype_from_entry(&kt_entry
) ==
246 CLEARTEXT_PRIV_ENCTYPE
) {
249 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
250 ZERO_STRUCT(kt_entry
);
253 if (ret
!= 0 && ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
254 /* Error parsing keytab */
255 DEBUG(1, (__location__
": Failed to parse memory "
261 /* found private entry,
262 * check if keytab is up to date */
264 if ((pwd_len
== KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry
))) &&
265 (memcmp(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry
)),
266 pwd
, pwd_len
) == 0)) {
267 /* keytab is already up to date, return */
268 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
272 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
273 ZERO_STRUCT(kt_entry
);
276 /* flush keytab, we need to regen it */
277 ret
= flush_keytab(krbctx
, *keytab
);
279 DEBUG(1, (__location__
": Failed to flush "
280 "memory keytab!\n"));
287 krb5_kt_cursor zero_csr
;
288 ZERO_STRUCT(zero_csr
);
289 if ((memcmp(&kt_cursor
, &zero_csr
, sizeof(krb5_kt_cursor
)) != 0) && *keytab
) {
290 krb5_kt_end_seq_get(krbctx
, *keytab
, &kt_cursor
);
294 /* keytab is not up to date, fill it up */
296 ret
= get_host_principal(krbctx
, &princ
);
298 DEBUG(1, (__location__
": Failed to get host principal!\n"));
303 password
.length
= pwd_len
;
304 ret
= fill_keytab_from_password(krbctx
, *keytab
,
305 princ
, kvno
, &password
);
307 DEBUG(1, (__location__
": Failed to fill memory keytab!\n"));
311 pwd_old
= secrets_fetch_prev_machine_password(lp_workgroup());
313 DEBUG(10, (__location__
": no prev machine password\n"));
315 password
.data
= pwd_old
;
316 password
.length
= strlen(pwd_old
);
317 ret
= fill_keytab_from_password(krbctx
, *keytab
,
318 princ
, kvno
-1, &password
);
320 DEBUG(1, (__location__
321 ": Failed to fill memory keytab!\n"));
326 /* add our private enctype + cleartext password so that we can
327 * update the keytab if secrets change later on */
328 ZERO_STRUCT(kt_entry
);
329 kt_entry
.principal
= princ
;
332 KRB5_KEY_TYPE(KRB5_KT_KEY(&kt_entry
)) = CLEARTEXT_PRIV_ENCTYPE
;
333 KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry
)) = pwd_len
;
334 KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry
)) = (uint8_t *)pwd
;
336 ret
= krb5_kt_add_entry(krbctx
, *keytab
, &kt_entry
);
338 DEBUG(1, (__location__
": Failed to add entry to "
339 "keytab for private enctype (%d) (error: %s)\n",
340 CLEARTEXT_PRIV_ENCTYPE
, error_message(ret
)));
351 krb5_kt_cursor zero_csr
;
352 ZERO_STRUCT(zero_csr
);
353 if ((memcmp(&kt_cursor
, &zero_csr
, sizeof(krb5_kt_cursor
)) != 0) && *keytab
) {
354 krb5_kt_end_seq_get(krbctx
, *keytab
, &kt_cursor
);
359 krb5_free_principal(krbctx
, princ
);
365 static krb5_error_code
fill_mem_keytab_from_system_keytab(krb5_context krbctx
,
366 krb5_keytab
*mkeytab
)
368 krb5_error_code ret
= 0;
369 krb5_keytab keytab
= NULL
;
370 krb5_kt_cursor kt_cursor
;
371 krb5_keytab_entry kt_entry
;
372 char *valid_princ_formats
[7] = { NULL
, NULL
, NULL
,
373 NULL
, NULL
, NULL
, NULL
};
374 char *entry_princ_s
= NULL
;
375 fstring my_name
, my_fqdn
;
379 /* Generate the list of principal names which we expect
380 * clients might want to use for authenticating to the file
381 * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */
383 fstrcpy(my_name
, lp_netbios_name());
386 name_to_fqdn(my_fqdn
, lp_netbios_name());
388 err
= asprintf(&valid_princ_formats
[0],
389 "%s$@%s", my_name
, lp_realm());
394 err
= asprintf(&valid_princ_formats
[1],
395 "host/%s@%s", my_name
, lp_realm());
400 err
= asprintf(&valid_princ_formats
[2],
401 "host/%s@%s", my_fqdn
, lp_realm());
406 err
= asprintf(&valid_princ_formats
[3],
407 "host/%s.%s@%s", my_name
, lp_realm(), lp_realm());
412 err
= asprintf(&valid_princ_formats
[4],
413 "cifs/%s@%s", my_name
, lp_realm());
418 err
= asprintf(&valid_princ_formats
[5],
419 "cifs/%s@%s", my_fqdn
, lp_realm());
424 err
= asprintf(&valid_princ_formats
[6],
425 "cifs/%s.%s@%s", my_name
, lp_realm(), lp_realm());
431 ZERO_STRUCT(kt_entry
);
432 ZERO_STRUCT(kt_cursor
);
434 ret
= smb_krb5_open_keytab(krbctx
, NULL
, false, &keytab
);
436 DEBUG(1, (__location__
": smb_krb5_open_keytab failed (%s)\n",
437 error_message(ret
)));
442 * Iterate through the keytab. For each key, if the principal
443 * name case-insensitively matches one of the allowed formats,
444 * copy it to the memory keytab.
447 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
449 DEBUG(1, (__location__
": krb5_kt_start_seq_get failed (%s)\n",
450 error_message(ret
)));
454 while ((krb5_kt_next_entry(krbctx
, keytab
,
455 &kt_entry
, &kt_cursor
) == 0)) {
456 ret
= smb_krb5_unparse_name(talloc_tos(), krbctx
,
460 DEBUG(1, (__location__
": smb_krb5_unparse_name "
461 "failed (%s)\n", error_message(ret
)));
465 for (i
= 0; i
< ARRAY_SIZE(valid_princ_formats
); i
++) {
467 if (!strequal(entry_princ_s
, valid_princ_formats
[i
])) {
471 ret
= krb5_kt_add_entry(krbctx
, *mkeytab
, &kt_entry
);
473 DEBUG(1, (__location__
": smb_krb5_unparse_name "
474 "failed (%s)\n", error_message(ret
)));
479 /* Free the name we parsed. */
480 TALLOC_FREE(entry_princ_s
);
482 /* Free the entry we just read. */
483 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
484 ZERO_STRUCT(kt_entry
);
486 krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
488 ZERO_STRUCT(kt_cursor
);
492 for (i
= 0; i
< ARRAY_SIZE(valid_princ_formats
); i
++) {
493 SAFE_FREE(valid_princ_formats
[i
]);
496 TALLOC_FREE(entry_princ_s
);
499 krb5_keytab_entry zero_kt_entry
;
500 ZERO_STRUCT(zero_kt_entry
);
501 if (memcmp(&zero_kt_entry
, &kt_entry
,
502 sizeof(krb5_keytab_entry
))) {
503 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
508 krb5_kt_cursor zero_csr
;
509 ZERO_STRUCT(zero_csr
);
510 if ((memcmp(&kt_cursor
, &zero_csr
,
511 sizeof(krb5_kt_cursor
)) != 0) && keytab
) {
512 krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
517 krb5_kt_close(krbctx
, keytab
);
523 static krb5_error_code
fill_mem_keytab_from_dedicated_keytab(krb5_context krbctx
,
524 krb5_keytab
*mkeytab
)
526 krb5_error_code ret
= 0;
527 krb5_keytab keytab
= NULL
;
528 krb5_kt_cursor kt_cursor
;
529 krb5_keytab_entry kt_entry
;
531 ret
= smb_krb5_open_keytab(krbctx
, lp_dedicated_keytab_file(),
534 DEBUG(1, (__location__
": smb_krb5_open_keytab failed (%s)\n",
535 error_message(ret
)));
540 * Iterate through the keytab. For each key, if the principal
541 * name case-insensitively matches one of the allowed formats,
542 * copy it to the memory keytab.
545 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
547 DEBUG(1, (__location__
": krb5_kt_start_seq_get failed (%s)\n",
548 error_message(ret
)));
552 while ((krb5_kt_next_entry(krbctx
, keytab
,
553 &kt_entry
, &kt_cursor
) == 0)) {
555 ret
= krb5_kt_add_entry(krbctx
, *mkeytab
, &kt_entry
);
557 /* Free the entry we just read. */
558 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
561 DEBUG(1, (__location__
": smb_krb5_unparse_name "
562 "failed (%s)\n", error_message(ret
)));
566 krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
570 krb5_kt_close(krbctx
, keytab
);
575 krb5_error_code
gse_krb5_get_server_keytab(krb5_context krbctx
,
578 krb5_error_code ret
= 0;
579 krb5_error_code ret1
= 0;
580 krb5_error_code ret2
= 0;
584 /* create memory keytab */
585 ret
= krb5_kt_resolve(krbctx
, SRV_MEM_KEYTAB_NAME
, keytab
);
587 DEBUG(1, (__location__
": Failed to get memory "
592 switch (lp_kerberos_method()) {
594 case KERBEROS_VERIFY_SECRETS
:
595 ret
= fill_mem_keytab_from_secrets(krbctx
, keytab
);
597 case KERBEROS_VERIFY_SYSTEM_KEYTAB
:
598 ret
= fill_mem_keytab_from_system_keytab(krbctx
, keytab
);
600 case KERBEROS_VERIFY_DEDICATED_KEYTAB
:
601 /* just use whatever keytab is configured */
602 ret
= fill_mem_keytab_from_dedicated_keytab(krbctx
, keytab
);
604 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB
:
605 ret1
= fill_mem_keytab_from_secrets(krbctx
, keytab
);
607 DEBUG(3, (__location__
": Warning! Unable to set mem "
608 "keytab from secrets!\n"));
610 /* Now append system keytab keys too */
611 ret2
= fill_mem_keytab_from_system_keytab(krbctx
, keytab
);
613 DEBUG(3, (__location__
": Warning! Unable to set mem "
614 "keytab from system keytab!\n"));
616 if (ret1
== 0 || ret2
== 0) {
625 krb5_kt_close(krbctx
, *keytab
);
627 DEBUG(1,("%s: Error! Unable to set mem keytab - %d\n",
634 #endif /* HAVE_KRB5 */