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/>.
26 static krb5_error_code
flush_keytab(krb5_context krbctx
, krb5_keytab keytab
)
29 krb5_kt_cursor kt_cursor
= NULL
;
30 krb5_keytab_entry kt_entry
;
32 ZERO_STRUCT(kt_entry
);
34 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
35 if (ret
== KRB5_KT_END
|| ret
== ENOENT
) {
40 ret
= krb5_kt_next_entry(krbctx
, keytab
, &kt_entry
, &kt_cursor
);
43 /* we need to close and reopen enumeration because we modify
45 ret
= krb5_kt_end_seq_get(krbctx
, keytab
, &kt_cursor
);
47 DEBUG(1, (__location__
": krb5_kt_end_seq_get() "
48 "failed (%s)\n", error_message(ret
)));
52 /* remove the entry */
53 ret
= krb5_kt_remove_entry(krbctx
, keytab
, &kt_entry
);
55 DEBUG(1, (__location__
": krb5_kt_remove_entry() "
56 "failed (%s)\n", error_message(ret
)));
59 ret
= smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
60 ZERO_STRUCT(kt_entry
);
63 ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &kt_cursor
);
65 DEBUG(1, (__location__
": krb5_kt_start_seq() failed "
66 "(%s)\n", error_message(ret
)));
70 ret
= krb5_kt_next_entry(krbctx
, keytab
,
71 &kt_entry
, &kt_cursor
);
74 if (ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
75 DEBUG(1, (__location__
": flushing keytab we got [%s]!\n",
85 static krb5_error_code
get_host_principal(krb5_context krbctx
,
86 krb5_principal
*host_princ
)
89 char *host_princ_s
= NULL
;
92 err
= asprintf(&host_princ_s
, "%s$@%s", global_myname(), lp_realm());
97 strlower_m(host_princ_s
);
98 ret
= smb_krb5_parse_name(krbctx
, host_princ_s
, host_princ
);
100 DEBUG(1, (__location__
": smb_krb5_parse_name(%s) "
102 host_princ_s
, error_message(ret
)));
105 SAFE_FREE(host_princ_s
);
109 static krb5_error_code
fill_keytab_from_password(krb5_context krbctx
,
111 krb5_principal princ
,
116 krb5_enctype
*enctypes
;
117 krb5_keytab_entry kt_entry
;
120 ret
= krb5_get_permitted_enctypes(krbctx
, &enctypes
);
122 DEBUG(1, (__location__
123 ": Can't determine permitted enctypes!\n"));
127 for (i
= 0; enctypes
[i
]; i
++) {
128 krb5_keyblock
*key
= NULL
;
130 if (!(key
= SMB_MALLOC_P(krb5_keyblock
))) {
135 if (create_kerberos_key_from_string(krbctx
, princ
,
137 enctypes
[i
], false)) {
138 DEBUG(10, ("Failed to create key for enctype %d "
140 enctypes
[i
], error_message(ret
)));
145 kt_entry
.principal
= princ
;
149 ret
= krb5_kt_add_entry(krbctx
, keytab
, &kt_entry
);
151 DEBUG(1, (__location__
": Failed to add entry to "
152 "keytab for enctype %d (error: %s)\n",
153 enctypes
[i
], error_message(ret
)));
154 krb5_free_keyblock(krbctx
, key
);
158 krb5_free_keyblock(krbctx
, key
);
168 #define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab"
169 #define CLEARTEXT_PRIV_ENCTYPE -99
171 static krb5_error_code
get_mem_keytab_from_secrets(krb5_context krbctx
,
177 krb5_kt_cursor kt_cursor
= NULL
;
178 krb5_keytab_entry kt_entry
;
180 krb5_principal princ
= NULL
;
181 krb5_kvno kvno
= 0; /* FIXME: fetch current vno from KDC ? */
182 char *pwd_old
= NULL
;
184 if (!secrets_init()) {
185 DEBUG(1, (__location__
": secrets_init failed\n"));
186 return KRB5_CONFIG_CANTOPEN
;
189 pwd
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
191 DEBUG(2, (__location__
": failed to fetch machine password\n"));
192 return KRB5_LIBOS_CANTREADPWD
;
194 pwd_len
= strlen(pwd
);
196 if (*keytab
== NULL
) {
197 /* create memory keytab */
198 ret
= krb5_kt_resolve(krbctx
, SRV_MEM_KEYTAB_NAME
, keytab
);
200 DEBUG(1, (__location__
": Failed to get memory "
206 ZERO_STRUCT(kt_entry
);
208 /* check if the keytab already has any entry */
209 ret
= krb5_kt_start_seq_get(krbctx
, *keytab
, &kt_cursor
);
210 if (ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
211 /* check if we have our special enctype used to hold
212 * the clear text password. If so, check it out so that
213 * we can verify if the keytab needs to be upgraded */
214 while ((ret
= krb5_kt_next_entry(krbctx
, *keytab
,
215 &kt_entry
, &kt_cursor
)) == 0) {
216 if (kt_entry
.key
.enctype
== CLEARTEXT_PRIV_ENCTYPE
) {
219 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
220 ZERO_STRUCT(kt_entry
);
223 if (ret
!= 0 && ret
!= KRB5_KT_END
&& ret
!= ENOENT
) {
224 /* Error parsing keytab */
225 DEBUG(1, (__location__
": Failed to parse memory "
231 /* found private entry,
232 * check if keytab is up to date */
234 if ((pwd_len
== kt_entry
.key
.length
) &&
235 (memcmp(kt_entry
.key
.contents
,
236 pwd
, pwd_len
) == 0)) {
237 /* keytab is already up to date, return */
238 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
242 smb_krb5_kt_free_entry(krbctx
, &kt_entry
);
243 ZERO_STRUCT(kt_entry
);
246 /* flush keytab, we need to regen it */
247 ret
= flush_keytab(krbctx
, *keytab
);
249 DEBUG(1, (__location__
": Failed to flush "
250 "memory keytab!\n"));
257 /* stop enumeration and free cursor */
258 krb5_kt_end_seq_get(krbctx
, *keytab
, &kt_cursor
);
262 /* keytab is not up to date, fill it up */
264 ret
= get_host_principal(krbctx
, &princ
);
266 DEBUG(1, (__location__
": Failed to get host principal!\n"));
271 password
.length
= pwd_len
;
272 ret
= fill_keytab_from_password(krbctx
, *keytab
,
273 princ
, kvno
, &password
);
275 DEBUG(1, (__location__
": Failed to fill memory keytab!\n"));
279 pwd_old
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
281 DEBUG(10, (__location__
": no prev machine password\n"));
283 password
.data
= pwd_old
;
284 password
.length
= strlen(pwd_old
);
285 ret
= fill_keytab_from_password(krbctx
, *keytab
,
286 princ
, kvno
-1, &password
);
288 DEBUG(1, (__location__
289 ": Failed to fill memory keytab!\n"));
294 /* add our private enctype + cleartext password so that we can
295 * update the keytab if secrets change later on */
296 ZERO_STRUCT(kt_entry
);
297 kt_entry
.principal
= princ
;
299 kt_entry
.key
.enctype
= CLEARTEXT_PRIV_ENCTYPE
;
300 kt_entry
.key
.length
= pwd_len
;
301 kt_entry
.key
.contents
= (uint8_t *)pwd
;
303 ret
= krb5_kt_add_entry(krbctx
, *keytab
, &kt_entry
);
305 DEBUG(1, (__location__
": Failed to add entry to "
306 "keytab for private enctype (%d) (error: %s)\n",
307 CLEARTEXT_PRIV_ENCTYPE
, error_message(ret
)));
318 /* stop enumeration and free cursor */
319 krb5_kt_end_seq_get(krbctx
, *keytab
, &kt_cursor
);
324 krb5_free_principal(krbctx
, princ
);
329 krb5_kt_close(krbctx
, *keytab
);
337 static krb5_error_code
get_mem_keytab_from_system_keytab(krb5_context krbctx
,
341 return KRB5_KT_NOTFOUND
;
344 krb5_error_code
smb_krb5_get_server_keytab(krb5_context krbctx
,
351 switch (lp_kerberos_method()) {
353 case KERBEROS_VERIFY_SECRETS
:
354 ret
= get_mem_keytab_from_secrets(krbctx
, keytab
);
356 case KERBEROS_VERIFY_SYSTEM_KEYTAB
:
357 ret
= get_mem_keytab_from_system_keytab(krbctx
, keytab
, true);
359 case KERBEROS_VERIFY_DEDICATED_KEYTAB
:
360 /* just use whatever keytab is configured */
361 ret
= get_mem_keytab_from_system_keytab(krbctx
, keytab
, false);
363 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB
:
364 ret
= get_mem_keytab_from_secrets(krbctx
, keytab
);
366 DEBUG(3, (__location__
": Warning! Unable to set mem "
367 "keytab from secrets!\n"));
369 /* Now append system keytab keys too */
370 ret
= get_mem_keytab_from_system_keytab(krbctx
, keytab
, true);
372 DEBUG(3, (__location__
": Warning! Unable to set mem "
373 "keytab from secrets!\n"));
381 #endif /* HAVE_KRB5 */