2 Unix SMB/CIFS implementation.
3 kerberos keytab utility library
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Remus Koos 2001
6 Copyright (C) Luke Howard 2003
7 Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
8 Copyright (C) Guenther Deschner 2003
9 Copyright (C) Rakesh Patel 2004
10 Copyright (C) Dan Perry 2004
11 Copyright (C) Jeremy Allison 2004
12 Copyright (C) Gerald Carter 2006
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 3 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 #include "librpc/gen_ndr/ndr_secrets.h"
38 /* This MAX_NAME_LEN is a constant defined in krb5.h */
39 #ifndef MAX_KEYTAB_NAME_LEN
40 #define MAX_KEYTAB_NAME_LEN 1100
50 /* pw2kt_conf contains 1 parsed line from "sync machine password to keytab" */
52 enum spn_spec_type spn_spec
;
56 bool additional_dns_hostnames
;
58 bool machine_password
;
59 char **spn_spec_array
;
63 /* State used by pw2kt */
65 /* Array of parsed lines from "sync machine password to keytab" */
66 struct pw2kt_conf
*keytabs
;
71 /* These are from DC */
76 /* This is from secrets.db */
77 struct secrets_domain_info1
*info
;
80 /* State used by pw2kt_process_keytab */
81 struct pw2kt_process_state
{
84 krb5_keytab_entry
*array1
;
85 krb5_keytab_entry
*array2
;
86 krb5_principal
*princ_array
;
87 krb5_enctype
*enctypes
;
88 krb5_enctype preferred_etype
;
91 static ADS_STATUS
pw2kt_scan_add_spn(TALLOC_CTX
*ctx
,
93 struct pw2kt_conf
*conf
)
95 conf
->spn_spec_array
= talloc_realloc(ctx
,
98 conf
->num_spn_spec
+ 1);
99 if (conf
->spn_spec_array
== NULL
) {
100 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
102 conf
->spn_spec_array
[conf
->num_spn_spec
] = talloc_strdup(
103 conf
->spn_spec_array
, spn
);
104 if (conf
->spn_spec_array
[conf
->num_spn_spec
] == NULL
) {
105 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
107 conf
->num_spn_spec
++;
113 * Parse the smb.conf and find out if it is needed to read from DC:
114 * - servicePrincipalNames
115 * - msDs-KeyVersionNumber
117 static ADS_STATUS
pw2kt_scan_line(const char *line
, struct pw2kt_state
*state
)
119 char *keytabname
= NULL
;
120 char *spn_spec
= NULL
;
121 char *spn_val
= NULL
;
123 struct pw2kt_conf
*conf
= NULL
;
126 state
->keytabs
= talloc_realloc(state
,
129 state
->num_keytabs
+ 1);
130 if (state
->keytabs
== NULL
) {
131 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
133 conf
= &state
->keytabs
[state
->num_keytabs
];
134 state
->num_keytabs
++;
136 keytabname
= talloc_strdup(state
->keytabs
, line
);
137 if (keytabname
== NULL
) {
138 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
142 conf
->keytab
= keytabname
;
143 spn_spec
= strchr_m(keytabname
, ':');
144 if (spn_spec
== NULL
) {
145 DBG_ERR("Invalid format! ':' expected in '%s'\n", keytabname
);
146 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
150 /* reverse match with strrchr_m() */
151 while ((option
= strrchr_m(spn_spec
, ':')) != NULL
) {
153 if (strequal(option
, "sync_kvno")) {
154 conf
->sync_kvno
= state
->sync_kvno
= true;
155 } else if (strequal(option
, "sync_etypes")) {
156 conf
->sync_etypes
= state
->sync_etypes
= true;
157 } else if (strequal(option
, "additional_dns_hostnames")) {
158 conf
->additional_dns_hostnames
= true;
159 } else if (strequal(option
, "netbios_aliases")) {
160 conf
->netbios_aliases
= true;
161 } else if (strequal(option
, "machine_password")) {
162 conf
->machine_password
= true;
164 DBG_WARNING("Unknown option '%s'!\n", option
);
165 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
169 spn_val
= strchr_m(spn_spec
, '=');
170 if (spn_val
!= NULL
) {
174 if (strcmp(spn_spec
, "account_name") == 0) {
175 conf
->spn_spec
= SPN_SPEC_DEFAULT
;
176 } else if (strcmp(spn_spec
, "sync_spns") == 0) {
177 conf
->spn_spec
= SPN_SPEC_SYNC
;
178 state
->sync_spns
= true;
179 } else if (strcmp(spn_spec
, "spns") == 0 ||
180 strcmp(spn_spec
, "spn_prefixes") == 0)
182 char *spn
= NULL
, *tmp
= NULL
;
184 conf
->spn_spec
= strcmp(spn_spec
, "spns") == 0
187 conf
->num_spn_spec
= 0;
189 while ((tmp
= strchr_m(spn
, ',')) != NULL
) {
191 status
= pw2kt_scan_add_spn(state
->keytabs
, spn
, conf
);
192 if (!ADS_ERR_OK(status
)) {
197 /* Do not forget the last entry */
198 return pw2kt_scan_add_spn(state
->keytabs
, spn
, conf
);
200 DBG_WARNING("Invalid SPN specifier: %s\n", spn_spec
);
201 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
208 * Fill struct pw2kt_state with defaults if "sync machine password to keytab"
209 * is missing in smb.conf
211 static ADS_STATUS
pw2kt_default_cfg(const char *name
, struct pw2kt_state
*state
)
213 char *keytabname
= NULL
;
214 struct pw2kt_conf
*conf
= NULL
;
216 state
->keytabs
= talloc_zero_array(state
->keytabs
,
219 if (state
->keytabs
== NULL
) {
220 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
222 conf
= &state
->keytabs
[0];
223 state
->num_keytabs
= 1;
225 keytabname
= talloc_strdup(state
->keytabs
, name
);
226 if (keytabname
== NULL
) {
227 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
230 conf
->spn_spec
= SPN_SPEC_SYNC
;
231 conf
->keytab
= keytabname
;
232 conf
->machine_password
= true;
233 conf
->sync_kvno
= state
->sync_kvno
= true;
234 state
->sync_spns
= true;
240 * For the given principal add to the array entries created from all pw->keys[]
242 static krb5_error_code
pw2kt_process_add_pw(
243 struct pw2kt_process_state
*state2
,
244 krb5_principal princ
,
246 struct secrets_domain_info1_password
*pw
)
249 size_t len
= talloc_array_length(state2
->array1
);
251 for (i
= 0; i
< pw
->num_keys
; i
++) {
252 krb5_keytab_entry
*kt_entry
= NULL
;
253 krb5_keyblock
*key
= NULL
;
254 krb5_keytab_entry
*tmp_a
= NULL
;
256 if (state2
->preferred_etype
!= -1 &&
257 state2
->preferred_etype
!= pw
->keys
[i
].keytype
)
259 DBG_DEBUG("Skip enc type '%d'.\n", pw
->keys
[i
].keytype
);
264 tmp_a
= talloc_realloc(state2
,
271 state2
->array1
= tmp_a
;
272 kt_entry
= &state2
->array1
[len
- 1];
273 ZERO_STRUCT(*kt_entry
);
274 kt_entry
->principal
= princ
;
277 key
= KRB5_KT_KEY(kt_entry
);
278 KRB5_KEY_TYPE(key
) = pw
->keys
[i
].keytype
;
279 KRB5_KEY_DATA(key
) = pw
->keys
[i
].value
.data
;
280 KRB5_KEY_LENGTH(key
) = pw
->keys
[i
].value
.length
;
287 * For the given principal add to the array entries based on password,
288 * old_password, older_password and next_change->password.
290 static krb5_error_code
pw2kt_process_add_info(
291 struct pw2kt_process_state
*state2
,
294 struct secrets_domain_info1
*info
)
297 krb5_principal princ
= NULL
;
298 krb5_principal
*a
= NULL
;
301 ret
= smb_krb5_parse_name(state2
->context
, princs
, &princ
);
303 DBG_ERR("Failed to parse principal: %s\n", princs
);
306 len
= talloc_array_length(state2
->princ_array
);
307 a
= talloc_realloc(state2
,
312 (void)krb5_free_principal(state2
->context
, princ
);
316 state2
->princ_array
= a
;
318 #define ADD_PW(K, P) \
319 if (info->P != NULL) { \
320 ret = pw2kt_process_add_pw(state2, princ, (K), info->P); \
322 DBG_ERR("Failed adding %s keys for %s.\n", \
329 ADD_PW(kvno
, password
);
330 ADD_PW(kvno
- 1, old_password
);
331 ADD_PW(kvno
- 2, older_password
);
332 if (info
->next_change
) {
333 ADD_PW(kvno
== -1 ? -4 : kvno
+ 1, next_change
->password
);
339 static int pw2kt_process_state_destructor(struct pw2kt_process_state
*state2
)
342 size_t len2
= talloc_array_length(state2
->array2
);
343 size_t len_p
= talloc_array_length(state2
->princ_array
);
345 for (i
= 0; i
< len2
; i
++) {
346 (void)smb_krb5_kt_free_entry(state2
->context
,
349 for (i
= 0; i
< len_p
; i
++) {
350 (void)krb5_free_principal(state2
->context
,
351 state2
->princ_array
[i
]);
353 (void)krb5_free_enctypes(state2
->context
, state2
->enctypes
);
358 /* Read the whole keytab to krb5_keytab_entry array */
359 static krb5_error_code
pw2kt_process_kt2ar(struct pw2kt_process_state
*state2
)
361 krb5_error_code ret
= 0, ret2
= 0;
362 krb5_kt_cursor cursor
;
363 krb5_keytab_entry
*a
= NULL
;
369 ret
= krb5_kt_start_seq_get(state2
->context
, state2
->keytab
, &cursor
);
371 if (ret
== KRB5_KT_END
|| ret
== ENOENT
) {
378 ret
= samba_krb5_kt_next_entry(state2
->context
,
385 a
= talloc_realloc(state2
,
390 smb_krb5_kt_free_entry(state2
->context
, &e
);
397 if (ret
== KRB5_KT_END
|| ret
== ENOENT
) {
400 ret2
= krb5_kt_end_seq_get(state2
->context
, state2
->keytab
, &cursor
);
402 return ret
!= 0 ? ret
: ret2
;
405 static ADS_STATUS
pw2kt_process_keytab(struct pw2kt_state
*state
,
406 struct pw2kt_conf
*keytabptr
)
408 krb5_error_code ret
= 0;
410 size_t i
, j
, len1
= 0, len2
= 0;
411 char *princ_s
= NULL
;
412 const char **netbios_alias
= NULL
;
413 const char **addl_hostnames
= NULL
;
414 size_t *index_array1
= NULL
;
415 size_t *index_array2
= NULL
;
416 struct pw2kt_process_state
*state2
= NULL
;
418 if (!keytabptr
->machine_password
) {
419 DBG_ERR("No 'machine_password' option for '%s'. Skip it.\n",
424 state2
= talloc_zero(state
, struct pw2kt_process_state
);
425 if (state2
== NULL
) {
426 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
428 talloc_set_destructor(state2
, pw2kt_process_state_destructor
);
430 ret
= smb_krb5_init_context_common(&state2
->context
);
432 DBG_ERR("Krb init context failed (%s)\n", error_message(ret
));
433 return ADS_ERROR_KRB5(ret
);
436 #define MATCH_ENCTYPE(TYPES, TYPE) \
438 int ei, result = 0; \
439 for (ei = 0; (TYPES)[ei] != 0; ei++) { \
440 if ((uint32_t)(TYPES)[ei] != (TYPE)) { \
449 #define COMMON_ENCTYPE(ETYPE) \
450 MATCH_ENCTYPE((state2->enctypes), (ETYPE)) && \
451 ((state->ad_etypes) & (ETYPE))
454 * -1 means there is no information about supported encryption types
455 * from DC and all encoding types will be added to the keytab.
457 state2
->preferred_etype
= -1;
459 /* Find the highest common enc type for AD and KRB5 lib */
460 if (keytabptr
->sync_etypes
) {
461 ret
= smb_krb5_get_allowed_etypes(state2
->context
,
464 DBG_ERR("Failed to get allowed enc types.\n");
465 return ADS_ERROR_KRB5(ret
);
468 if (COMMON_ENCTYPE(ENCTYPE_AES256_CTS_HMAC_SHA1_96
)) {
469 state2
->preferred_etype
=
470 ENCTYPE_AES256_CTS_HMAC_SHA1_96
;
471 } else if (COMMON_ENCTYPE(ENCTYPE_AES128_CTS_HMAC_SHA1_96
)) {
472 state2
->preferred_etype
=
473 ENCTYPE_AES128_CTS_HMAC_SHA1_96
;
474 } else if (COMMON_ENCTYPE(ENCTYPE_ARCFOUR_HMAC
)) {
475 state2
->preferred_etype
= ENCTYPE_ARCFOUR_HMAC
;
477 DBG_ERR("No common enctype for AD and KRB5 lib.\n");
478 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
482 if (keytabptr
->sync_kvno
) {
483 kvno
= state
->ad_kvno
;
486 #define ADD_INFO(P) \
487 ret = pw2kt_process_add_info(state2, kvno, (P), state->info); \
489 return ADS_ERROR_KRB5(ret); \
492 /* Add ACCOUNTNAME$ entries */
493 switch (keytabptr
->spn_spec
) {
494 case SPN_SPEC_DEFAULT
:
495 ADD_INFO(state
->info
->account_name
);
498 for (i
= 0; i
< state
->ad_num_spns
; i
++) {
499 ADD_INFO(state
->ad_spn_array
[i
]);
503 for (i
= 0; i
< keytabptr
->num_spn_spec
; i
++) {
504 ADD_INFO(keytabptr
->spn_spec_array
[i
]);
507 case SPN_SPEC_PREFIX
:
508 for (i
= 0; i
< keytabptr
->num_spn_spec
; i
++) {
509 princ_s
= talloc_asprintf(talloc_tos(),
511 keytabptr
->spn_spec_array
[i
],
514 if (princ_s
== NULL
) {
515 return ADS_ERROR_KRB5(ENOMEM
);
519 if (!keytabptr
->netbios_aliases
) {
520 goto additional_dns_hostnames
;
522 for (netbios_alias
= lp_netbios_aliases();
523 netbios_alias
!= NULL
&& *netbios_alias
!= NULL
;
526 /* Add PREFIX/netbiosname@REALM */
527 princ_s
= talloc_asprintf(
530 keytabptr
->spn_spec_array
[i
],
533 if (princ_s
== NULL
) {
534 return ADS_ERROR_KRB5(ENOMEM
);
538 /* Add PREFIX/netbiosname.domainname@REALM */
539 princ_s
= talloc_asprintf(
542 keytabptr
->spn_spec_array
[i
],
546 if (princ_s
== NULL
) {
547 return ADS_ERROR_KRB5(ENOMEM
);
552 additional_dns_hostnames
:
553 if (!keytabptr
->additional_dns_hostnames
) {
556 for (addl_hostnames
= lp_additional_dns_hostnames();
557 addl_hostnames
!= NULL
&& *addl_hostnames
!= NULL
;
560 /* Add PREFIX/netbiosname@REALM */
561 princ_s
= talloc_asprintf(
564 keytabptr
->spn_spec_array
[i
],
567 if (princ_s
== NULL
) {
568 return ADS_ERROR_KRB5(ENOMEM
);
575 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
578 ret
= smb_krb5_kt_open(state2
->context
,
583 return ADS_ERROR_KRB5(ret
);
586 /* The new entries are in array1. Read existing entries to array2. */
587 ret
= pw2kt_process_kt2ar(state2
);
589 return ADS_ERROR_KRB5(ret
);
592 len1
= talloc_array_length(state2
->array1
);
593 len2
= talloc_array_length(state2
->array2
);
595 if (keytabptr
->sync_kvno
) {
599 /* copy existing entries VNO -1, -2, -3, -4 to VNO -11, -12, -13, -14 */
600 for (j
= 0; j
< len2
; j
++) {
601 krb5_keytab_entry e
= state2
->array2
[j
];
602 /* vno type is 'krb5_kvno' which is 'unsigned int' */
603 if (e
.vno
!= -1 && e
.vno
!= -2 && e
.vno
!= -3 && e
.vno
!= -4) {
604 DBG_WARNING("Unexpected keytab entry with VNO = %d (it "
605 "should be -1, -2, -3, -4) in %s\n",
610 e
.vno
= state2
->array2
[j
].vno
- 10;
611 ret
= samba_krb5_kt_add_entry(state2
->context
,
615 return ADS_ERROR_KRB5(ret
);
618 /* remove all old entries (they should have VNO -1, -2, -3, -4) */
619 for (j
= 0; j
< len2
; j
++) {
620 krb5_keytab_entry e
= state2
->array2
[j
];
621 if (e
.vno
!= -1 && e
.vno
!= -2 && e
.vno
!= -3 && e
.vno
!= -4) {
622 DBG_WARNING("Unexpected keytab entry with VNO = %d (it "
623 "should be -1, -2, -3, -4) in %s\n",
627 ret
= samba_krb5_kt_remove_entry(state2
->context
,
631 D_WARNING("Failed to remove keytab entry from %s\n",
633 ret
= 0; /* Be fault tolerant */
636 /* add new entries with VNO -1, -2, -3, -4 */
637 for (i
= 0; i
< len1
; i
++) {
638 ret
= samba_krb5_kt_add_entry(state2
->context
,
642 return ADS_ERROR_KRB5(ret
);
645 /* remove entries with VNO -11, -12, -13, -14 */
646 for (j
= 0; j
< len2
; j
++) {
647 krb5_keytab_entry e
= state2
->array2
[j
];
648 e
.vno
= state2
->array2
[j
].vno
- 10;
649 ret
= samba_krb5_kt_remove_entry(state2
->context
,
653 D_WARNING("Failed to remove keytab entry from %s\n",
655 ret
= 0; /* Be fault tolerant */
659 ret
= krb5_kt_close(state2
->context
, state2
->keytab
);
660 return ADS_ERROR_KRB5(ret
);
664 index_array1
= talloc_zero_array(state2
, size_t, len1
);
665 index_array2
= talloc_zero_array(state2
, size_t, len2
);
666 if (index_array1
== NULL
|| index_array2
== NULL
) {
667 return ADS_ERROR_KRB5(ENOMEM
);
670 * Mark entries that are present in both arrays.
671 * These will not be added or removed.
673 for (i
= 0; i
< len1
; i
++) {
674 for (j
= 0; j
< len2
; j
++) {
675 krb5_keytab_entry e2
= state2
->array2
[j
];
676 if (smb_krb5_kt_compare(
681 KRB5_KEY_TYPE(KRB5_KT_KEY(&e2
))
690 /* First add the new entries to the keytab.*/
691 for (i
= 0; i
< len1
; i
++) {
692 if (index_array1
[i
] == 0) {
693 ret
= samba_krb5_kt_add_entry(state2
->context
,
697 return ADS_ERROR_KRB5(ret
);
702 /* Now, remove the old entries from the keytab. */
703 for (j
= 0; j
< len2
; j
++) {
704 if (index_array2
[j
] == 0) {
705 ret
= samba_krb5_kt_remove_entry(state2
->context
,
709 D_WARNING("Failed to remove keytab entry from "
712 ret
= 0; /* Be fault tolerant */
717 ret
= krb5_kt_close(state2
->context
, state2
->keytab
);
718 return ADS_ERROR_KRB5(ret
);
721 static ADS_STATUS
pw2kt_get_dc_info(struct pw2kt_state
*state
)
724 LDAPMessage
*res
= NULL
;
727 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
728 ADS_STRUCT
*ads
= ads_init(
729 tmp_ctx
, lp_realm(), lp_workgroup(), NULL
, ADS_SASL_SIGN
);
732 DBG_ERR("ads_init() failed\n");
733 TALLOC_FREE(tmp_ctx
);
734 return ADS_ERROR(LDAP_NO_MEMORY
);
737 status
= ads_connect_machine(ads
);
738 if (!ADS_ERR_OK(status
)) {
739 DBG_ERR("Failed to refresh keytab, ads_connect() returned %s\n",
741 TALLOC_FREE(tmp_ctx
);
745 status
= ads_find_machine_acct(ads
, &res
, lp_netbios_name());
746 if (!ADS_ERR_OK(status
)) {
747 TALLOC_FREE(tmp_ctx
);
751 count
= ads_count_replies(ads
, res
);
753 status
= ADS_ERROR(LDAP_NO_SUCH_OBJECT
);
754 ads_msgfree(ads
, res
);
755 TALLOC_FREE(tmp_ctx
);
759 if (state
->sync_etypes
) {
760 ok
= ads_pull_uint32(ads
,
762 "msDS-SupportedEncryptionTypes",
765 DBG_WARNING("Failed to determine encryption types.\n");
766 ads_msgfree(ads
, res
);
767 TALLOC_FREE(tmp_ctx
);
768 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
772 if (state
->sync_kvno
) {
774 ok
= ads_pull_uint32(ads
, res
, "msDS-KeyVersionNumber", &kvno
);
776 DBG_WARNING("Failed to determine the system's kvno.\n");
777 ads_msgfree(ads
, res
);
778 TALLOC_FREE(tmp_ctx
);
779 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
781 state
->ad_kvno
= (krb5_kvno
) kvno
;
784 if (state
->sync_spns
) {
785 state
->ad_spn_array
= ads_pull_strings(ads
,
788 "servicePrincipalName",
789 &state
->ad_num_spns
);
790 if (state
->ad_spn_array
== NULL
) {
791 DBG_WARNING("Failed to determine SPNs.\n");
792 ads_msgfree(ads
, res
);
793 TALLOC_FREE(tmp_ctx
);
794 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
798 ads_msgfree(ads
, res
);
799 TALLOC_FREE(tmp_ctx
);
803 static bool pw2kt_default_keytab_name(char *name_str
, size_t name_size
)
805 char keytab_str
[MAX_KEYTAB_NAME_LEN
] = {0};
806 const char *keytab_name
= NULL
;
807 krb5_context context
= 0;
810 switch (lp_kerberos_method()) {
811 case KERBEROS_VERIFY_SYSTEM_KEYTAB
:
812 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB
:
813 ret
= smb_krb5_init_context_common(&context
);
815 DBG_ERR("kerberos init context failed (%s)\n",
819 ret
= krb5_kt_default_name(context
,
821 sizeof(keytab_str
) - 2);
822 krb5_free_context(context
);
824 DBG_WARNING("Failed to get default keytab name\n");
827 if (strncmp(keytab_str
, "WRFILE:", 7) == 0) {
828 keytab_name
= keytab_str
+ 7;
829 } else if (strncmp(keytab_str
, "FILE:", 5) == 0) {
830 keytab_name
= keytab_str
+ 5;
832 keytab_name
= keytab_str
;
836 case KERBEROS_VERIFY_DEDICATED_KEYTAB
:
837 keytab_name
= lp_dedicated_keytab_file();
841 DBG_NOTICE("'kerberos method' is 'secrets only' but "
842 "'sync machine password to keytab' is not set "
843 "==> no keytab will be generated.\n");
847 if (keytab_name
== NULL
|| keytab_name
[0] == '\0') {
848 DBG_ERR("Invalid keytab name\n");
852 if (strlen(keytab_name
) + 1 > name_size
) {
853 DBG_ERR("Too long keytab name\n");
857 (void)strncpy(name_str
, keytab_name
, name_size
);
862 NTSTATUS
sync_pw2keytabs(void)
864 TALLOC_CTX
*frame
= talloc_stackframe();
865 const struct loadparm_substitution
*lp_sub
=
866 loadparm_s3_global_substitution();
867 struct pw2kt_state
*state
= NULL
;
868 const char **line
= NULL
;
869 const char **lp_ptr
= NULL
;
870 const char *pwsync_script
= NULL
;
872 ADS_STATUS status_ads
;
875 DBG_DEBUG("Syncing machine password from secrets to keytabs.\n");
877 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
879 return NT_STATUS_OK
; /* nothing todo */
882 state
= talloc_zero(frame
, struct pw2kt_state
);
885 return NT_STATUS_NO_MEMORY
;
888 lp_ptr
= lp_sync_machine_password_to_keytab();
889 if (lp_ptr
== NULL
) {
890 char name
[MAX_KEYTAB_NAME_LEN
] = {0};
891 bool ok
= pw2kt_default_keytab_name(name
, sizeof(name
));
895 DBG_WARNING("No default keytab name.\n");
896 return NT_STATUS_OK
; /* nothing todo */
898 status_ads
= pw2kt_default_cfg(name
, state
);
899 if (!ADS_ERR_OK(status_ads
)) {
900 DBG_WARNING("Cannot create default configuration.\n");
902 return NT_STATUS_INTERNAL_ERROR
;
907 if ((*lp_ptr
!= NULL
) && strequal_m(*lp_ptr
, "disabled")) {
908 DBG_DEBUG("'sync machine password to keytab' is explicitly disabled.\n");
914 DBG_DEBUG("Scanning line: %s\n", *line
);
915 status_ads
= pw2kt_scan_line(*line
, state
);
916 if (!ADS_ERR_OK(status_ads
)) {
918 return NT_STATUS_INTERNAL_ERROR
;
924 if (state
->sync_etypes
|| state
->sync_kvno
|| state
->sync_spns
) {
925 status_ads
= pw2kt_get_dc_info(state
);
926 if (!ADS_ERR_OK(status_ads
)) {
927 DBG_WARNING("cannot read from DC\n");
929 return NT_STATUS_INTERNAL_ERROR
;
932 DBG_DEBUG("No 'sync_etypes', 'sync_kvno' and 'sync_spns' in "
933 "parameter 'sync machine password to keytab' => "
934 "no need to talk to DC.\n");
937 if (!secrets_init()) {
938 DBG_WARNING("secrets_init failed\n");
940 return NT_STATUS_INTERNAL_ERROR
;
943 status_nt
= secrets_fetch_or_upgrade_domain_info(lp_workgroup(),
946 if (!NT_STATUS_IS_OK(status_nt
)) {
947 DBG_WARNING("secrets_fetch_or_upgrade_domain_info(%s) - %s\n",
949 nt_errstr(status_nt
));
954 for (i
= 0; i
< state
->num_keytabs
; i
++) {
955 status_ads
= pw2kt_process_keytab(state
, &state
->keytabs
[i
]);
956 if (!ADS_ERR_OK(status_ads
)) {
958 return NT_STATUS_INTERNAL_ERROR
;
962 pwsync_script
= lp_sync_machine_password_script(frame
, lp_sub
);
963 if (pwsync_script
!= NULL
&& pwsync_script
[0] != '\0') {
966 DBG_DEBUG("Running script: '%s'\n.", pwsync_script
);
967 ret
= smbrun(pwsync_script
, NULL
, NULL
);
969 DBG_ERR("Script '%s' failed with: %d.\n",
973 return NT_STATUS_INTERNAL_ERROR
;
981 static krb5_error_code
ads_keytab_open(krb5_context context
,
984 char keytab_str
[MAX_KEYTAB_NAME_LEN
] = {0};
985 const char *keytab_name
= NULL
;
986 krb5_error_code ret
= 0;
988 switch (lp_kerberos_method()) {
989 case KERBEROS_VERIFY_SYSTEM_KEYTAB
:
990 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB
:
991 ret
= krb5_kt_default_name(context
,
993 sizeof(keytab_str
) - 2);
995 DBG_WARNING("Failed to get default keytab name\n");
998 keytab_name
= keytab_str
;
1000 case KERBEROS_VERIFY_DEDICATED_KEYTAB
:
1001 keytab_name
= lp_dedicated_keytab_file();
1004 DBG_ERR("Invalid kerberos method set (%d)\n",
1005 lp_kerberos_method());
1006 ret
= KRB5_KT_BADNAME
;
1010 if (keytab_name
== NULL
|| keytab_name
[0] == '\0') {
1011 DBG_ERR("Invalid keytab name\n");
1012 ret
= KRB5_KT_BADNAME
;
1016 ret
= smb_krb5_kt_open(context
, keytab_name
, true, keytab
);
1018 DBG_WARNING("smb_krb5_kt_open failed (%s)\n",
1019 error_message(ret
));
1027 /**********************************************************************
1028 Flushes all entries from the system keytab.
1029 ***********************************************************************/
1031 int ads_keytab_flush(ADS_STRUCT
*ads
)
1033 krb5_error_code ret
= 0;
1034 krb5_context context
= NULL
;
1035 krb5_keytab keytab
= NULL
;
1038 ret
= smb_krb5_init_context_common(&context
);
1040 DBG_ERR("kerberos init context failed (%s)\n",
1041 error_message(ret
));
1045 ret
= ads_keytab_open(context
, &keytab
);
1050 /* Seek and delete all old keytab entries */
1051 ret
= smb_krb5_kt_seek_and_delete_old_entries(context
,
1053 false, /* keep_old_kvno */
1055 false, /* enctype_only */
1064 aderr
= ads_clear_service_principal_names(ads
, lp_netbios_name());
1065 if (!ADS_ERR_OK(aderr
)) {
1066 DEBUG(1, (__location__
": Error while clearing service "
1067 "principal listings in LDAP.\n"));
1074 krb5_kt_close(context
, keytab
);
1077 krb5_free_context(context
);
1082 #endif /* HAVE_ADS */
1084 /**********************************************************************
1086 ***********************************************************************/
1088 int ads_keytab_list(const char *keytab_name
)
1090 krb5_error_code ret
= 0;
1091 krb5_context context
= NULL
;
1092 krb5_keytab keytab
= NULL
;
1093 krb5_kt_cursor cursor
;
1094 krb5_keytab_entry kt_entry
;
1096 ZERO_STRUCT(kt_entry
);
1097 ZERO_STRUCT(cursor
);
1099 ret
= smb_krb5_init_context_common(&context
);
1101 DBG_ERR("kerberos init context failed (%s)\n",
1102 error_message(ret
));
1106 if (keytab_name
== NULL
) {
1108 ret
= ads_keytab_open(context
, &keytab
);
1113 ret
= smb_krb5_kt_open(context
, keytab_name
, False
, &keytab
);
1116 DEBUG(1, ("smb_krb5_kt_open failed (%s)\n",
1117 error_message(ret
)));
1121 ret
= krb5_kt_start_seq_get(context
, keytab
, &cursor
);
1123 ZERO_STRUCT(cursor
);
1127 printf("Vno Type Principal\n");
1129 while (samba_krb5_kt_next_entry(context
, keytab
, &kt_entry
, &cursor
) ==
1133 char *princ_s
= NULL
;
1134 char *etype_s
= NULL
;
1135 krb5_enctype enctype
= 0;
1137 ret
= smb_krb5_unparse_name(talloc_tos(), context
,
1138 kt_entry
.principal
, &princ_s
);
1143 enctype
= smb_krb5_kt_get_enctype_from_entry(&kt_entry
);
1145 ret
= smb_krb5_enctype_to_string(context
, enctype
, &etype_s
);
1147 (asprintf(&etype_s
, "UNKNOWN: %d", enctype
) == -1)) {
1148 TALLOC_FREE(princ_s
);
1152 printf("%3d %-43s %s\n", kt_entry
.vno
, etype_s
, princ_s
);
1154 TALLOC_FREE(princ_s
);
1157 ret
= smb_krb5_kt_free_entry(context
, &kt_entry
);
1163 ret
= krb5_kt_end_seq_get(context
, keytab
, &cursor
);
1168 /* Ensure we don't double free. */
1169 ZERO_STRUCT(kt_entry
);
1170 ZERO_STRUCT(cursor
);
1173 if (!all_zero((uint8_t *)&kt_entry
, sizeof(kt_entry
))) {
1174 smb_krb5_kt_free_entry(context
, &kt_entry
);
1176 if (!all_zero((uint8_t *)&cursor
, sizeof(cursor
)) && keytab
) {
1177 krb5_kt_end_seq_get(context
, keytab
, &cursor
);
1181 krb5_kt_close(context
, keytab
);
1184 krb5_free_context(context
);
1189 #endif /* HAVE_KRB5 */