Line data Source code
1 : /*
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
13 :
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.
18 :
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.
23 :
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/>.
26 : */
27 :
28 : #include "includes.h"
29 : #include "smb_krb5.h"
30 : #include "ads.h"
31 : #include "secrets.h"
32 :
33 : #ifdef HAVE_KRB5
34 :
35 : #ifdef HAVE_ADS
36 :
37 : /* This MAX_NAME_LEN is a constant defined in krb5.h */
38 : #ifndef MAX_KEYTAB_NAME_LEN
39 : #define MAX_KEYTAB_NAME_LEN 1100
40 : #endif
41 :
42 0 : static krb5_error_code ads_keytab_open(krb5_context context,
43 : krb5_keytab *keytab)
44 : {
45 0 : char keytab_str[MAX_KEYTAB_NAME_LEN] = {0};
46 0 : const char *keytab_name = NULL;
47 0 : krb5_error_code ret = 0;
48 :
49 0 : switch (lp_kerberos_method()) {
50 0 : case KERBEROS_VERIFY_SYSTEM_KEYTAB:
51 : case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
52 0 : ret = krb5_kt_default_name(context,
53 : keytab_str,
54 : sizeof(keytab_str) - 2);
55 0 : if (ret != 0) {
56 0 : DBG_WARNING("Failed to get default keytab name");
57 0 : goto out;
58 : }
59 0 : keytab_name = keytab_str;
60 0 : break;
61 0 : case KERBEROS_VERIFY_DEDICATED_KEYTAB:
62 0 : keytab_name = lp_dedicated_keytab_file();
63 0 : break;
64 0 : default:
65 0 : DBG_ERR("Invalid kerberos method set (%d)\n",
66 : lp_kerberos_method());
67 0 : ret = KRB5_KT_BADNAME;
68 0 : goto out;
69 : }
70 :
71 0 : if (keytab_name == NULL || keytab_name[0] == '\0') {
72 0 : DBG_ERR("Invalid keytab name\n");
73 0 : ret = KRB5_KT_BADNAME;
74 0 : goto out;
75 : }
76 :
77 0 : ret = smb_krb5_kt_open(context, keytab_name, true, keytab);
78 0 : if (ret != 0) {
79 0 : DBG_WARNING("smb_krb5_kt_open failed (%s)\n",
80 : error_message(ret));
81 0 : goto out;
82 : }
83 :
84 0 : out:
85 0 : return ret;
86 : }
87 :
88 0 : static bool fill_default_spns(TALLOC_CTX *ctx, const char *machine_name,
89 : const char *my_fqdn, const char *spn,
90 : const char ***spns)
91 : {
92 : char *psp1, *psp2;
93 :
94 0 : if (*spns == NULL) {
95 0 : *spns = talloc_zero_array(ctx, const char*, 3);
96 0 : if (*spns == NULL) {
97 0 : return false;
98 : }
99 : }
100 :
101 0 : psp1 = talloc_asprintf(ctx,
102 : "%s/%s",
103 : spn,
104 : machine_name);
105 0 : if (psp1 == NULL) {
106 0 : return false;
107 : }
108 :
109 0 : if (!strlower_m(&psp1[strlen(spn) + 1])) {
110 0 : return false;
111 : }
112 0 : (*spns)[0] = psp1;
113 :
114 0 : psp2 = talloc_asprintf(ctx,
115 : "%s/%s",
116 : spn,
117 : my_fqdn);
118 0 : if (psp2 == NULL) {
119 0 : return false;
120 : }
121 :
122 0 : if (!strlower_m(&psp2[strlen(spn) + 1])) {
123 0 : return false;
124 : }
125 :
126 0 : (*spns)[1] = psp2;
127 :
128 0 : return true;
129 : }
130 :
131 0 : static bool ads_set_machine_account_spns(TALLOC_CTX *ctx,
132 : ADS_STRUCT *ads,
133 : const char *service_or_spn,
134 : const char *my_fqdn)
135 : {
136 0 : const char **spn_names = NULL;
137 : ADS_STATUS aderr;
138 0 : struct spn_struct* spn_struct = NULL;
139 0 : char *tmp = NULL;
140 :
141 : /* SPN should have '/' */
142 0 : tmp = strchr_m(service_or_spn, '/');
143 0 : if (tmp != NULL) {
144 0 : spn_struct = parse_spn(ctx, service_or_spn);
145 0 : if (spn_struct == NULL) {
146 0 : return false;
147 : }
148 : }
149 :
150 0 : DBG_INFO("Attempting to add/update '%s'\n", service_or_spn);
151 :
152 0 : if (spn_struct != NULL) {
153 0 : spn_names = talloc_zero_array(ctx, const char*, 2);
154 0 : spn_names[0] = service_or_spn;
155 : } else {
156 : bool ok;
157 :
158 0 : ok = fill_default_spns(ctx,
159 : lp_netbios_name(),
160 : my_fqdn,
161 : service_or_spn,
162 : &spn_names);
163 0 : if (!ok) {
164 0 : return false;
165 : }
166 : }
167 0 : aderr = ads_add_service_principal_names(ads,
168 : lp_netbios_name(),
169 : spn_names);
170 0 : if (!ADS_ERR_OK(aderr)) {
171 0 : DBG_WARNING("Failed to add service principal name.\n");
172 0 : return false;
173 : }
174 :
175 0 : return true;
176 : }
177 :
178 : /*
179 : * Create kerberos principal(s) from SPN or service name.
180 : */
181 0 : static bool service_or_spn_to_kerberos_princ(TALLOC_CTX *ctx,
182 : const char *service_or_spn,
183 : const char *my_fqdn,
184 : char **p_princ_s,
185 : char **p_short_princ_s)
186 : {
187 0 : char *princ_s = NULL;
188 0 : char *short_princ_s = NULL;
189 0 : const char *service = service_or_spn;
190 0 : const char *host = my_fqdn;
191 0 : struct spn_struct* spn_struct = NULL;
192 0 : char *tmp = NULL;
193 0 : bool ok = true;
194 :
195 : /* SPN should have '/' */
196 0 : tmp = strchr_m(service_or_spn, '/');
197 0 : if (tmp != NULL) {
198 0 : spn_struct = parse_spn(ctx, service_or_spn);
199 0 : if (spn_struct == NULL) {
200 0 : ok = false;
201 0 : goto out;
202 : }
203 : }
204 0 : if (spn_struct != NULL) {
205 0 : service = spn_struct->serviceclass;
206 0 : host = spn_struct->host;
207 : }
208 0 : princ_s = talloc_asprintf(ctx, "%s/%s@%s",
209 : service,
210 : host, lp_realm());
211 0 : if (princ_s == NULL) {
212 0 : ok = false;
213 0 : goto out;
214 : }
215 :
216 0 : if (spn_struct == NULL) {
217 0 : short_princ_s = talloc_asprintf(ctx, "%s/%s@%s",
218 : service, lp_netbios_name(),
219 : lp_realm());
220 0 : if (short_princ_s == NULL) {
221 0 : ok = false;
222 0 : goto out;
223 : }
224 : }
225 0 : *p_princ_s = princ_s;
226 0 : *p_short_princ_s = short_princ_s;
227 0 : out:
228 0 : return ok;
229 : }
230 :
231 0 : static int add_kt_entry_etypes(krb5_context context, TALLOC_CTX *tmpctx,
232 : ADS_STRUCT *ads, const char *salt_princ_s,
233 : krb5_keytab keytab, krb5_kvno kvno,
234 : const char *srvPrinc, const char *my_fqdn,
235 : krb5_data *password, bool update_ads)
236 : {
237 0 : krb5_error_code ret = 0;
238 0 : char *princ_s = NULL;
239 0 : char *short_princ_s = NULL;
240 0 : krb5_enctype enctypes[4] = {
241 : ENCTYPE_AES256_CTS_HMAC_SHA1_96,
242 : ENCTYPE_AES128_CTS_HMAC_SHA1_96,
243 : ENCTYPE_ARCFOUR_HMAC,
244 : 0
245 : };
246 : size_t i;
247 :
248 : /* Construct our principal */
249 0 : if (strchr_m(srvPrinc, '@')) {
250 : /* It's a fully-named principal. */
251 0 : princ_s = talloc_asprintf(tmpctx, "%s", srvPrinc);
252 0 : if (!princ_s) {
253 0 : ret = -1;
254 0 : goto out;
255 : }
256 0 : } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
257 : /* It's the machine account, as used by smbclient clients. */
258 0 : princ_s = talloc_asprintf(tmpctx, "%s@%s",
259 : srvPrinc, lp_realm());
260 0 : if (!princ_s) {
261 0 : ret = -1;
262 0 : goto out;
263 : }
264 : } else {
265 : /* It's a normal service principal. Add the SPN now so that we
266 : * can obtain credentials for it and double-check the salt value
267 : * used to generate the service's keys. */
268 :
269 0 : if (!service_or_spn_to_kerberos_princ(tmpctx,
270 : srvPrinc,
271 : my_fqdn,
272 : &princ_s,
273 : &short_princ_s)) {
274 0 : ret = -1;
275 0 : goto out;
276 : }
277 :
278 : /* According to http://support.microsoft.com/kb/326985/en-us,
279 : certain principal names are automatically mapped to the
280 : host/... principal in the AD account.
281 : So only create these in the keytab, not in AD. --jerry */
282 :
283 0 : if (update_ads && !strequal(srvPrinc, "cifs") &&
284 0 : !strequal(srvPrinc, "host")) {
285 0 : if (!ads_set_machine_account_spns(tmpctx,
286 : ads,
287 : srvPrinc,
288 : my_fqdn)) {
289 0 : ret = -1;
290 0 : goto out;
291 : }
292 : }
293 : }
294 :
295 0 : for (i = 0; enctypes[i]; i++) {
296 :
297 : /* add the fqdn principal to the keytab */
298 0 : ret = smb_krb5_kt_add_entry(context,
299 : keytab,
300 : kvno,
301 : princ_s,
302 : salt_princ_s,
303 : enctypes[i],
304 : password,
305 : false,
306 : false);
307 0 : if (ret) {
308 0 : DBG_WARNING("Failed to add entry to keytab\n");
309 0 : goto out;
310 : }
311 :
312 : /* add the short principal name if we have one */
313 0 : if (short_princ_s) {
314 0 : ret = smb_krb5_kt_add_entry(context,
315 : keytab,
316 : kvno,
317 : short_princ_s,
318 : salt_princ_s,
319 : enctypes[i],
320 : password,
321 : false,
322 : false);
323 0 : if (ret) {
324 0 : DBG_WARNING("Failed to add short entry to keytab\n");
325 0 : goto out;
326 : }
327 : }
328 : }
329 0 : out:
330 0 : return ret;
331 : }
332 :
333 : /**********************************************************************
334 : Adds a single service principal, i.e. 'host' to the system keytab
335 : ***********************************************************************/
336 :
337 0 : int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
338 : {
339 0 : krb5_error_code ret = 0;
340 0 : krb5_context context = NULL;
341 0 : krb5_keytab keytab = NULL;
342 : krb5_data password;
343 : krb5_kvno kvno;
344 0 : char *salt_princ_s = NULL;
345 0 : char *password_s = NULL;
346 : char *my_fqdn;
347 0 : TALLOC_CTX *tmpctx = NULL;
348 0 : char **hostnames_array = NULL;
349 0 : size_t num_hostnames = 0;
350 :
351 0 : ret = smb_krb5_init_context_common(&context);
352 0 : if (ret) {
353 0 : DBG_ERR("kerberos init context failed (%s)\n",
354 : error_message(ret));
355 0 : return -1;
356 : }
357 :
358 0 : ret = ads_keytab_open(context, &keytab);
359 0 : if (ret != 0) {
360 0 : goto out;
361 : }
362 :
363 : /* retrieve the password */
364 0 : if (!secrets_init()) {
365 0 : DBG_WARNING("secrets_init failed\n");
366 0 : ret = -1;
367 0 : goto out;
368 : }
369 0 : password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
370 0 : if (!password_s) {
371 0 : DBG_WARNING("failed to fetch machine password\n");
372 0 : ret = -1;
373 0 : goto out;
374 : }
375 0 : ZERO_STRUCT(password);
376 0 : password.data = password_s;
377 0 : password.length = strlen(password_s);
378 :
379 : /* we need the dNSHostName value here */
380 0 : tmpctx = talloc_init(__location__);
381 0 : if (!tmpctx) {
382 0 : DBG_ERR("talloc_init() failed!\n");
383 0 : ret = -1;
384 0 : goto out;
385 : }
386 :
387 0 : my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
388 0 : if (!my_fqdn) {
389 0 : DBG_ERR("unable to determine machine account's dns name in "
390 : "AD!\n");
391 0 : ret = -1;
392 0 : goto out;
393 : }
394 :
395 : /* make sure we have a single instance of a the computer account */
396 0 : if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) {
397 0 : DBG_ERR("unable to determine machine account's short name in "
398 : "AD!\n");
399 0 : ret = -1;
400 0 : goto out;
401 : }
402 :
403 0 : kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
404 0 : if (kvno == -1) {
405 : /* -1 indicates failure, everything else is OK */
406 0 : DBG_WARNING("ads_get_machine_kvno failed to determine the "
407 : "system's kvno.\n");
408 0 : ret = -1;
409 0 : goto out;
410 : }
411 :
412 0 : salt_princ_s = kerberos_secrets_fetch_salt_princ();
413 0 : if (salt_princ_s == NULL) {
414 0 : DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
415 0 : ret = -1;
416 0 : goto out;
417 : }
418 :
419 0 : ret = add_kt_entry_etypes(context, tmpctx, ads, salt_princ_s, keytab,
420 : kvno, srvPrinc, my_fqdn, &password,
421 : update_ads);
422 0 : if (ret != 0) {
423 0 : goto out;
424 : }
425 :
426 0 : if (ADS_ERR_OK(ads_get_additional_dns_hostnames(tmpctx, ads,
427 : lp_netbios_name(),
428 : &hostnames_array,
429 : &num_hostnames))) {
430 : size_t i;
431 :
432 0 : for (i = 0; i < num_hostnames; i++) {
433 :
434 0 : ret = add_kt_entry_etypes(context, tmpctx, ads,
435 : salt_princ_s, keytab,
436 : kvno, srvPrinc,
437 0 : hostnames_array[i],
438 : &password, update_ads);
439 0 : if (ret != 0) {
440 0 : goto out;
441 : }
442 : }
443 : }
444 :
445 0 : out:
446 0 : SAFE_FREE(salt_princ_s);
447 0 : TALLOC_FREE(tmpctx);
448 :
449 0 : if (keytab) {
450 0 : krb5_kt_close(context, keytab);
451 : }
452 0 : if (context) {
453 0 : krb5_free_context(context);
454 : }
455 0 : return (int)ret;
456 : }
457 :
458 : /**********************************************************************
459 : Flushes all entries from the system keytab.
460 : ***********************************************************************/
461 :
462 0 : int ads_keytab_flush(ADS_STRUCT *ads)
463 : {
464 0 : krb5_error_code ret = 0;
465 0 : krb5_context context = NULL;
466 0 : krb5_keytab keytab = NULL;
467 : krb5_kvno kvno;
468 : ADS_STATUS aderr;
469 :
470 0 : ret = smb_krb5_init_context_common(&context);
471 0 : if (ret) {
472 0 : DBG_ERR("kerberos init context failed (%s)\n",
473 : error_message(ret));
474 0 : return ret;
475 : }
476 :
477 0 : ret = ads_keytab_open(context, &keytab);
478 0 : if (ret != 0) {
479 0 : goto out;
480 : }
481 :
482 0 : kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
483 0 : if (kvno == -1) {
484 : /* -1 indicates a failure */
485 0 : DEBUG(1, (__location__ ": Error determining the kvno.\n"));
486 0 : ret = -1;
487 0 : goto out;
488 : }
489 :
490 : /* Seek and delete old keytab entries */
491 0 : ret = smb_krb5_kt_seek_and_delete_old_entries(context,
492 : keytab,
493 : kvno,
494 : ENCTYPE_NULL,
495 : NULL,
496 : NULL,
497 : true,
498 : false);
499 0 : if (ret) {
500 0 : goto out;
501 : }
502 :
503 0 : aderr = ads_clear_service_principal_names(ads, lp_netbios_name());
504 0 : if (!ADS_ERR_OK(aderr)) {
505 0 : DEBUG(1, (__location__ ": Error while clearing service "
506 : "principal listings in LDAP.\n"));
507 0 : ret = -1;
508 0 : goto out;
509 : }
510 :
511 0 : out:
512 0 : if (keytab) {
513 0 : krb5_kt_close(context, keytab);
514 : }
515 0 : if (context) {
516 0 : krb5_free_context(context);
517 : }
518 0 : return ret;
519 : }
520 :
521 : /**********************************************************************
522 : Adds all the required service principals to the system keytab.
523 : ***********************************************************************/
524 :
525 0 : int ads_keytab_create_default(ADS_STRUCT *ads)
526 : {
527 0 : krb5_error_code ret = 0;
528 0 : krb5_context context = NULL;
529 0 : krb5_keytab keytab = NULL;
530 0 : krb5_kt_cursor cursor = {0};
531 0 : krb5_keytab_entry kt_entry = {0};
532 : krb5_kvno kvno;
533 0 : size_t found = 0;
534 : char *sam_account_name, *upn;
535 0 : char **oldEntries = NULL, *princ_s[26];
536 : TALLOC_CTX *frame;
537 : char *machine_name;
538 : char **spn_array;
539 : size_t num_spns;
540 : size_t i;
541 0 : bool ok = false;
542 : ADS_STATUS status;
543 :
544 0 : ZERO_STRUCT(kt_entry);
545 0 : ZERO_STRUCT(cursor);
546 :
547 0 : frame = talloc_stackframe();
548 0 : if (frame == NULL) {
549 0 : ret = -1;
550 0 : goto done;
551 : }
552 :
553 0 : status = ads_get_service_principal_names(frame,
554 : ads,
555 : lp_netbios_name(),
556 : &spn_array,
557 : &num_spns);
558 0 : if (!ADS_ERR_OK(status)) {
559 0 : ret = -1;
560 0 : goto done;
561 : }
562 :
563 0 : for (i = 0; i < num_spns; i++) {
564 : char *srv_princ;
565 : char *p;
566 :
567 0 : srv_princ = strlower_talloc(frame, spn_array[i]);
568 0 : if (srv_princ == NULL) {
569 0 : ret = -1;
570 0 : goto done;
571 : }
572 :
573 0 : p = strchr_m(srv_princ, '/');
574 0 : if (p == NULL) {
575 0 : continue;
576 : }
577 0 : p[0] = '\0';
578 :
579 : /* Add the SPNs found on the DC */
580 0 : ret = ads_keytab_add_entry(ads, srv_princ, false);
581 0 : if (ret != 0) {
582 0 : DEBUG(1, ("ads_keytab_add_entry failed while "
583 : "adding '%s' principal.\n",
584 : spn_array[i]));
585 0 : goto done;
586 : }
587 : }
588 :
589 : #if 0 /* don't create the CIFS/... keytab entries since no one except smbd
590 : really needs them and we will fall back to verifying against
591 : secrets.tdb */
592 :
593 : ret = ads_keytab_add_entry(ads, "cifs", false));
594 : if (ret != 0 ) {
595 : DEBUG(1, (__location__ ": ads_keytab_add_entry failed while "
596 : "adding 'cifs'.\n"));
597 : return ret;
598 : }
599 : #endif
600 :
601 0 : memset(princ_s, '\0', sizeof(princ_s));
602 :
603 0 : ret = smb_krb5_init_context_common(&context);
604 0 : if (ret) {
605 0 : DBG_ERR("kerberos init context failed (%s)\n",
606 : error_message(ret));
607 0 : goto done;
608 : }
609 :
610 0 : machine_name = talloc_strdup(frame, lp_netbios_name());
611 0 : if (!machine_name) {
612 0 : ret = -1;
613 0 : goto done;
614 : }
615 :
616 : /* now add the userPrincipalName and sAMAccountName entries */
617 0 : ok = ads_has_samaccountname(ads, frame, machine_name);
618 0 : if (!ok) {
619 0 : DEBUG(0, (__location__ ": unable to determine machine "
620 : "account's name in AD!\n"));
621 0 : ret = -1;
622 0 : goto done;
623 : }
624 :
625 : /*
626 : * append '$' to netbios name so 'ads_keytab_add_entry' recognises
627 : * it as a machine account rather than a service or Windows SPN.
628 : */
629 0 : sam_account_name = talloc_asprintf(frame, "%s$",machine_name);
630 0 : if (sam_account_name == NULL) {
631 0 : ret = -1;
632 0 : goto done;
633 : }
634 : /* upper case the sAMAccountName to make it easier for apps to
635 : know what case to use in the keytab file */
636 0 : if (!strupper_m(sam_account_name)) {
637 0 : ret = -1;
638 0 : goto done;
639 : }
640 :
641 0 : ret = ads_keytab_add_entry(ads, sam_account_name, false);
642 0 : if (ret != 0) {
643 0 : DEBUG(1, (__location__ ": ads_keytab_add_entry() failed "
644 : "while adding sAMAccountName (%s)\n",
645 : sam_account_name));
646 0 : goto done;
647 : }
648 :
649 : /* remember that not every machine account will have a upn */
650 0 : upn = ads_get_upn(ads, frame, machine_name);
651 0 : if (upn) {
652 0 : ret = ads_keytab_add_entry(ads, upn, false);
653 0 : if (ret != 0) {
654 0 : DEBUG(1, (__location__ ": ads_keytab_add_entry() "
655 : "failed while adding UPN (%s)\n", upn));
656 0 : goto done;
657 : }
658 : }
659 :
660 : /* Now loop through the keytab and update any other existing entries */
661 0 : kvno = (krb5_kvno)ads_get_machine_kvno(ads, machine_name);
662 0 : if (kvno == (krb5_kvno)-1) {
663 0 : DEBUG(1, (__location__ ": ads_get_machine_kvno() failed to "
664 : "determine the system's kvno.\n"));
665 0 : goto done;
666 : }
667 :
668 0 : DEBUG(3, (__location__ ": Searching for keytab entries to preserve "
669 : "and update.\n"));
670 :
671 0 : ret = ads_keytab_open(context, &keytab);
672 0 : if (ret != 0) {
673 0 : goto done;
674 : }
675 :
676 0 : ret = krb5_kt_start_seq_get(context, keytab, &cursor);
677 0 : if (ret != KRB5_KT_END && ret != ENOENT ) {
678 0 : while ((ret = krb5_kt_next_entry(context, keytab,
679 0 : &kt_entry, &cursor)) == 0) {
680 0 : smb_krb5_kt_free_entry(context, &kt_entry);
681 0 : ZERO_STRUCT(kt_entry);
682 0 : found++;
683 : }
684 : }
685 0 : krb5_kt_end_seq_get(context, keytab, &cursor);
686 0 : ZERO_STRUCT(cursor);
687 :
688 : /*
689 : * Hmmm. There is no "rewind" function for the keytab. This means we
690 : * have a race condition where someone else could add entries after
691 : * we've counted them. Re-open asap to minimise the race. JRA.
692 : */
693 0 : DEBUG(3, (__location__ ": Found %zd entries in the keytab.\n", found));
694 0 : if (!found) {
695 0 : goto done;
696 : }
697 :
698 0 : oldEntries = talloc_zero_array(frame, char *, found + 1);
699 0 : if (!oldEntries) {
700 0 : DEBUG(1, (__location__ ": Failed to allocate space to store "
701 : "the old keytab entries (talloc failed?).\n"));
702 0 : ret = -1;
703 0 : goto done;
704 : }
705 :
706 0 : ret = krb5_kt_start_seq_get(context, keytab, &cursor);
707 0 : if (ret == KRB5_KT_END || ret == ENOENT) {
708 0 : krb5_kt_end_seq_get(context, keytab, &cursor);
709 0 : ZERO_STRUCT(cursor);
710 0 : goto done;
711 : }
712 :
713 0 : while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
714 0 : if (kt_entry.vno != kvno) {
715 0 : char *ktprinc = NULL;
716 : char *p;
717 :
718 : /* This returns a malloc'ed string in ktprinc. */
719 0 : ret = smb_krb5_unparse_name(oldEntries, context,
720 0 : kt_entry.principal,
721 : &ktprinc);
722 0 : if (ret) {
723 0 : DEBUG(1, (__location__
724 : ": smb_krb5_unparse_name failed "
725 : "(%s)\n", error_message(ret)));
726 0 : goto done;
727 : }
728 : /*
729 : * From looking at the krb5 source they don't seem to
730 : * take locale or mb strings into account.
731 : * Maybe this is because they assume utf8 ?
732 : * In this case we may need to convert from utf8 to
733 : * mb charset here ? JRA.
734 : */
735 0 : p = strchr_m(ktprinc, '@');
736 0 : if (p) {
737 0 : *p = '\0';
738 : }
739 :
740 0 : p = strchr_m(ktprinc, '/');
741 0 : if (p) {
742 0 : *p = '\0';
743 : }
744 0 : for (i = 0; i < found; i++) {
745 0 : if (!oldEntries[i]) {
746 0 : oldEntries[i] = ktprinc;
747 0 : break;
748 : }
749 0 : if (!strcmp(oldEntries[i], ktprinc)) {
750 0 : TALLOC_FREE(ktprinc);
751 0 : break;
752 : }
753 : }
754 0 : if (i == found) {
755 0 : TALLOC_FREE(ktprinc);
756 : }
757 : }
758 0 : smb_krb5_kt_free_entry(context, &kt_entry);
759 0 : ZERO_STRUCT(kt_entry);
760 : }
761 0 : krb5_kt_end_seq_get(context, keytab, &cursor);
762 0 : ZERO_STRUCT(cursor);
763 :
764 0 : ret = 0;
765 0 : for (i = 0; oldEntries[i]; i++) {
766 0 : ret |= ads_keytab_add_entry(ads, oldEntries[i], false);
767 0 : TALLOC_FREE(oldEntries[i]);
768 : }
769 :
770 0 : done:
771 0 : TALLOC_FREE(oldEntries);
772 0 : TALLOC_FREE(frame);
773 :
774 0 : if (context) {
775 0 : if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
776 0 : smb_krb5_kt_free_entry(context, &kt_entry);
777 : }
778 0 : if (!all_zero((uint8_t *)&cursor, sizeof(cursor)) && keytab) {
779 0 : krb5_kt_end_seq_get(context, keytab, &cursor);
780 : }
781 0 : if (keytab) {
782 0 : krb5_kt_close(context, keytab);
783 : }
784 0 : krb5_free_context(context);
785 : }
786 0 : return ret;
787 : }
788 :
789 : #endif /* HAVE_ADS */
790 :
791 : /**********************************************************************
792 : List system keytab.
793 : ***********************************************************************/
794 :
795 0 : int ads_keytab_list(const char *keytab_name)
796 : {
797 0 : krb5_error_code ret = 0;
798 0 : krb5_context context = NULL;
799 0 : krb5_keytab keytab = NULL;
800 : krb5_kt_cursor cursor;
801 : krb5_keytab_entry kt_entry;
802 :
803 0 : ZERO_STRUCT(kt_entry);
804 0 : ZERO_STRUCT(cursor);
805 :
806 0 : ret = smb_krb5_init_context_common(&context);
807 0 : if (ret) {
808 0 : DBG_ERR("kerberos init context failed (%s)\n",
809 : error_message(ret));
810 0 : return ret;
811 : }
812 :
813 0 : if (keytab_name == NULL) {
814 : #ifdef HAVE_ADS
815 0 : ret = ads_keytab_open(context, &keytab);
816 : #else
817 : ret = ENOENT;
818 : #endif
819 : } else {
820 0 : ret = smb_krb5_kt_open(context, keytab_name, False, &keytab);
821 : }
822 0 : if (ret) {
823 0 : DEBUG(1, ("smb_krb5_kt_open failed (%s)\n",
824 : error_message(ret)));
825 0 : goto out;
826 : }
827 :
828 0 : ret = krb5_kt_start_seq_get(context, keytab, &cursor);
829 0 : if (ret) {
830 0 : ZERO_STRUCT(cursor);
831 0 : goto out;
832 : }
833 :
834 0 : printf("Vno Type Principal\n");
835 :
836 0 : while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
837 :
838 0 : char *princ_s = NULL;
839 0 : char *etype_s = NULL;
840 0 : krb5_enctype enctype = 0;
841 :
842 0 : ret = smb_krb5_unparse_name(talloc_tos(), context,
843 0 : kt_entry.principal, &princ_s);
844 0 : if (ret) {
845 0 : goto out;
846 : }
847 :
848 0 : enctype = smb_krb5_kt_get_enctype_from_entry(&kt_entry);
849 :
850 0 : ret = smb_krb5_enctype_to_string(context, enctype, &etype_s);
851 0 : if (ret &&
852 0 : (asprintf(&etype_s, "UNKNOWN: %d", enctype) == -1)) {
853 0 : TALLOC_FREE(princ_s);
854 0 : goto out;
855 : }
856 :
857 0 : printf("%3d %-43s %s\n", kt_entry.vno, etype_s, princ_s);
858 :
859 0 : TALLOC_FREE(princ_s);
860 0 : SAFE_FREE(etype_s);
861 :
862 0 : ret = smb_krb5_kt_free_entry(context, &kt_entry);
863 0 : if (ret) {
864 0 : goto out;
865 : }
866 : }
867 :
868 0 : ret = krb5_kt_end_seq_get(context, keytab, &cursor);
869 0 : if (ret) {
870 0 : goto out;
871 : }
872 :
873 : /* Ensure we don't double free. */
874 0 : ZERO_STRUCT(kt_entry);
875 0 : ZERO_STRUCT(cursor);
876 0 : out:
877 :
878 0 : if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
879 0 : smb_krb5_kt_free_entry(context, &kt_entry);
880 : }
881 0 : if (!all_zero((uint8_t *)&cursor, sizeof(cursor)) && keytab) {
882 0 : krb5_kt_end_seq_get(context, keytab, &cursor);
883 : }
884 :
885 0 : if (keytab) {
886 0 : krb5_kt_close(context, keytab);
887 : }
888 0 : if (context) {
889 0 : krb5_free_context(context);
890 : }
891 0 : return ret;
892 : }
893 :
894 : #endif /* HAVE_KRB5 */
|