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/>.
27 static krb5_error_code
flush_keytab(krb5_context krbctx
, krb5_keytab keytab
)
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
) {
41 ret
= krb5_kt_next_entry(krbctx
, keytab
, &kt_entry
, &kt_cursor
);
44 /* we need to close and reopen enumeration because we modify
46 ret
= krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
48 DEBUG(1, (__location__
": krb5_kt_end_seq_get() "
49 "failed (%s)\n", error_message(ret
)));
53 /* remove the entry */
54 ret
= krb5_kt_remove_entry(krbctx
, keytab
, &kt_entry
);
56 DEBUG(1, (__location__
": krb5_kt_remove_entry() "
57 "failed (%s)\n", error_message(ret
)));
60 ret
= smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
61 ZERO_STRUCT(kt_entry
);
64 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
66 DEBUG(1, (__location__
": krb5_kt_start_seq() failed "
67 "(%s)\n", error_message(ret
)));
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",
86 static krb5_error_code
get_host_principal(krb5_context krbctx
,
87 krb5_principal
*host_princ
)
90 char *host_princ_s
= NULL
;
93 err
= asprintf(&host_princ_s
, "%s$@%s", lp_netbios_name(), lp_realm());
98 strlower_m(host_princ_s
);
99 ret
= smb_krb5_parse_name(krbctx
, host_princ_s
, host_princ
);
101 DEBUG(1, (__location__
": smb_krb5_parse_name(%s) "
103 host_princ_s
, error_message(ret
)));
106 SAFE_FREE(host_princ_s
);
110 static krb5_error_code
fill_keytab_from_password(krb5_context krbctx
,
112 krb5_principal princ
,
117 krb5_enctype
*enctypes
;
118 krb5_keytab_entry kt_entry
;
121 ret
= get_kerberos_allowed_etypes(krbctx
, &enctypes
);
123 DEBUG(1, (__location__
124 ": Can't determine permitted enctypes!\n"));
128 for (i
= 0; enctypes
[i
]; i
++) {
129 krb5_keyblock
*key
= NULL
;
131 if (!(key
= SMB_MALLOC_P(krb5_keyblock
))) {
136 if (create_kerberos_key_from_string(krbctx
, princ
,
138 enctypes
[i
], false)) {
139 DEBUG(10, ("Failed to create key for enctype %d "
141 enctypes
[i
], error_message(ret
)));
146 kt_entry
.principal
= princ
;
148 *(KRB5_KT_KEY(&kt_entry
)) = *key
;
150 ret
= krb5_kt_add_entry(krbctx
, keytab
, &kt_entry
);
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
);
159 krb5_free_keyblock(krbctx
, key
);
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
,
178 krb5_kt_cursor kt_cursor
;
179 krb5_keytab_entry kt_entry
;
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
);
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
) {
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 "
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
);
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
);
241 DEBUG(1, (__location__
": Failed to flush "
242 "memory keytab!\n"));
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
);
260 DEBUG(1, (__location__
": Failed to get host principal!\n"));
265 password
.length
= pwd_len
;
266 ret
= fill_keytab_from_password(krbctx
, *keytab
,
267 princ
, kvno
, &password
);
269 DEBUG(1, (__location__
": Failed to fill memory keytab!\n"));
273 pwd_old
= secrets_fetch_prev_machine_password(lp_workgroup());
275 DEBUG(10, (__location__
": no prev machine password\n"));
277 password
.data
= pwd_old
;
278 password
.length
= strlen(pwd_old
);
279 ret
= fill_keytab_from_password(krbctx
, *keytab
,
280 princ
, kvno
-1, &password
);
282 DEBUG(1, (__location__
283 ": Failed to fill memory keytab!\n"));
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
;
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
);
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
)));
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
);
321 krb5_free_principal(krbctx
, princ
);
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
;
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());
348 name_to_fqdn(my_fqdn
, lp_netbios_name());
350 err
= asprintf(&valid_princ_formats
[0],
351 "%s$@%s", my_name
, lp_realm());
356 err
= asprintf(&valid_princ_formats
[1],
357 "host/%s@%s", my_name
, lp_realm());
362 err
= asprintf(&valid_princ_formats
[2],
363 "host/%s@%s", my_fqdn
, lp_realm());
368 err
= asprintf(&valid_princ_formats
[3],
369 "host/%s.%s@%s", my_name
, lp_realm(), lp_realm());
374 err
= asprintf(&valid_princ_formats
[4],
375 "cifs/%s@%s", my_name
, lp_realm());
380 err
= asprintf(&valid_princ_formats
[5],
381 "cifs/%s@%s", my_fqdn
, lp_realm());
386 err
= asprintf(&valid_princ_formats
[6],
387 "cifs/%s.%s@%s", my_name
, lp_realm(), lp_realm());
393 ZERO_STRUCT(kt_entry
);
394 ZERO_STRUCT(kt_cursor
);
396 ret
= smb_krb5_open_keytab(krbctx
, NULL
, false, &keytab
);
398 DEBUG(1, (__location__
": smb_krb5_open_keytab failed (%s)\n",
399 error_message(ret
)));
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
);
411 DEBUG(1, (__location__
": krb5_kt_start_seq_get failed (%s)\n",
412 error_message(ret
)));
416 while ((krb5_kt_next_entry(krbctx
, keytab
,
417 &kt_entry
, &kt_cursor
) == 0)) {
418 ret
= smb_krb5_unparse_name(talloc_tos(), krbctx
,
422 DEBUG(1, (__location__
": smb_krb5_unparse_name "
423 "failed (%s)\n", error_message(ret
)));
427 for (i
= 0; i
< ARRAY_SIZE(valid_princ_formats
); i
++) {
429 if (!strequal(entry_princ_s
, valid_princ_formats
[i
])) {
433 ret
= krb5_kt_add_entry(krbctx
, *mkeytab
, &kt_entry
);
435 DEBUG(1, (__location__
": smb_krb5_unparse_name "
436 "failed (%s)\n", error_message(ret
)));
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
);
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
);
479 krb5_kt_close(krbctx
, keytab
);
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(),
499 DEBUG(1, (__location__
": smb_krb5_open_keytab failed (%s)\n",
500 error_message(ret
)));
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
);
512 DEBUG(1, (__location__
": krb5_kt_start_seq_get failed (%s)\n",
513 error_message(ret
)));
517 while ((krb5_kt_next_entry(krbctx
, keytab
,
518 &kt_entry
, &kt_cursor
) == 0)) {
520 ret
= krb5_kt_add_entry(krbctx
, *mkeytab
, &kt_entry
);
522 DEBUG(1, (__location__
": smb_krb5_unparse_name "
523 "failed (%s)\n", error_message(ret
)));
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
);
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
);
556 krb5_kt_close(krbctx
, keytab
);
562 krb5_error_code
gse_krb5_get_server_keytab(krb5_context krbctx
,
565 krb5_error_code ret
= 0;
566 krb5_error_code ret1
= 0;
567 krb5_error_code ret2
= 0;
571 /* create memory keytab */
572 ret
= krb5_kt_resolve(krbctx
, SRV_MEM_KEYTAB_NAME
, keytab
);
574 DEBUG(1, (__location__
": Failed to get memory "
579 switch (lp_kerberos_method()) {
581 case KERBEROS_VERIFY_SECRETS
:
582 ret
= fill_mem_keytab_from_secrets(krbctx
, keytab
);
584 case KERBEROS_VERIFY_SYSTEM_KEYTAB
:
585 ret
= fill_mem_keytab_from_system_keytab(krbctx
, keytab
);
587 case KERBEROS_VERIFY_DEDICATED_KEYTAB
:
588 /* just use whatever keytab is configured */
589 ret
= fill_mem_keytab_from_dedicated_keytab(krbctx
, keytab
);
591 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB
:
592 ret1
= fill_mem_keytab_from_secrets(krbctx
, keytab
);
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
);
600 DEBUG(3, (__location__
": Warning! Unable to set mem "
601 "keytab from system keytab!\n"));
603 if (ret1
== 0 || ret2
== 0) {
612 krb5_kt_close(krbctx
, *keytab
);
614 DEBUG(1,("%s: Error! Unable to set mem keytab - %d\n",
621 #endif /* HAVE_KRB5 */