packaging: Add missing quotes in smbprint
[Samba.git] / source3 / libads / kerberos_keytab.c
blob8dac25a0ef9d9c9a3a5293610585642de38cde55
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
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/>.
28 #include "includes.h"
29 #include "smb_krb5.h"
30 #include "ads.h"
31 #include "secrets.h"
33 #ifdef HAVE_KRB5
35 #ifdef HAVE_ADS
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
42 static krb5_error_code ads_keytab_open(krb5_context context,
43 krb5_keytab *keytab)
45 char keytab_str[MAX_KEYTAB_NAME_LEN] = {0};
46 const char *keytab_name = NULL;
47 krb5_error_code ret = 0;
49 switch (lp_kerberos_method()) {
50 case KERBEROS_VERIFY_SYSTEM_KEYTAB:
51 case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
52 ret = krb5_kt_default_name(context,
53 keytab_str,
54 sizeof(keytab_str) - 2);
55 if (ret != 0) {
56 DBG_WARNING("Failed to get default keytab name\n");
57 goto out;
59 keytab_name = keytab_str;
60 break;
61 case KERBEROS_VERIFY_DEDICATED_KEYTAB:
62 keytab_name = lp_dedicated_keytab_file();
63 break;
64 default:
65 DBG_ERR("Invalid kerberos method set (%d)\n",
66 lp_kerberos_method());
67 ret = KRB5_KT_BADNAME;
68 goto out;
71 if (keytab_name == NULL || keytab_name[0] == '\0') {
72 DBG_ERR("Invalid keytab name\n");
73 ret = KRB5_KT_BADNAME;
74 goto out;
77 ret = smb_krb5_kt_open(context, keytab_name, true, keytab);
78 if (ret != 0) {
79 DBG_WARNING("smb_krb5_kt_open failed (%s)\n",
80 error_message(ret));
81 goto out;
84 out:
85 return ret;
88 static bool fill_default_spns(TALLOC_CTX *ctx, const char *machine_name,
89 const char *my_fqdn, const char *spn,
90 const char ***spns)
92 char *psp1, *psp2;
94 if (*spns == NULL) {
95 *spns = talloc_zero_array(ctx, const char*, 3);
96 if (*spns == NULL) {
97 return false;
101 psp1 = talloc_asprintf(ctx,
102 "%s/%s",
103 spn,
104 machine_name);
105 if (psp1 == NULL) {
106 return false;
109 if (!strlower_m(&psp1[strlen(spn) + 1])) {
110 return false;
112 (*spns)[0] = psp1;
114 psp2 = talloc_asprintf(ctx,
115 "%s/%s",
116 spn,
117 my_fqdn);
118 if (psp2 == NULL) {
119 return false;
122 if (!strlower_m(&psp2[strlen(spn) + 1])) {
123 return false;
126 (*spns)[1] = psp2;
128 return true;
131 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)
136 const char **spn_names = NULL;
137 ADS_STATUS aderr;
138 struct spn_struct* spn_struct = NULL;
139 char *tmp = NULL;
141 /* SPN should have '/' */
142 tmp = strchr_m(service_or_spn, '/');
143 if (tmp != NULL) {
144 spn_struct = parse_spn(ctx, service_or_spn);
145 if (spn_struct == NULL) {
146 return false;
150 DBG_INFO("Attempting to add/update '%s'\n", service_or_spn);
152 if (spn_struct != NULL) {
153 spn_names = talloc_zero_array(ctx, const char*, 2);
154 spn_names[0] = service_or_spn;
155 } else {
156 bool ok;
158 ok = fill_default_spns(ctx,
159 lp_netbios_name(),
160 my_fqdn,
161 service_or_spn,
162 &spn_names);
163 if (!ok) {
164 return false;
167 aderr = ads_add_service_principal_names(ads,
168 lp_netbios_name(),
169 spn_names);
170 if (!ADS_ERR_OK(aderr)) {
171 DBG_WARNING("Failed to add service principal name.\n");
172 return false;
175 return true;
179 * Create kerberos principal(s) from SPN or service name.
181 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)
187 char *princ_s = NULL;
188 char *short_princ_s = NULL;
189 const char *service = service_or_spn;
190 const char *host = my_fqdn;
191 struct spn_struct* spn_struct = NULL;
192 char *tmp = NULL;
193 bool ok = true;
195 /* SPN should have '/' */
196 tmp = strchr_m(service_or_spn, '/');
197 if (tmp != NULL) {
198 spn_struct = parse_spn(ctx, service_or_spn);
199 if (spn_struct == NULL) {
200 ok = false;
201 goto out;
204 if (spn_struct != NULL) {
205 service = spn_struct->serviceclass;
206 host = spn_struct->host;
208 princ_s = talloc_asprintf(ctx, "%s/%s@%s",
209 service,
210 host, lp_realm());
211 if (princ_s == NULL) {
212 ok = false;
213 goto out;
216 if (spn_struct == NULL) {
217 short_princ_s = talloc_asprintf(ctx, "%s/%s@%s",
218 service, lp_netbios_name(),
219 lp_realm());
220 if (short_princ_s == NULL) {
221 ok = false;
222 goto out;
225 *p_princ_s = princ_s;
226 *p_short_princ_s = short_princ_s;
227 out:
228 return ok;
231 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)
237 krb5_error_code ret = 0;
238 char *princ_s = NULL;
239 char *short_princ_s = NULL;
240 krb5_enctype enctypes[4] = {
241 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
242 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
243 ENCTYPE_ARCFOUR_HMAC,
246 size_t i;
248 /* Construct our principal */
249 if (strchr_m(srvPrinc, '@')) {
250 /* It's a fully-named principal. */
251 princ_s = talloc_asprintf(tmpctx, "%s", srvPrinc);
252 if (!princ_s) {
253 ret = -1;
254 goto out;
256 } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
257 /* It's the machine account, as used by smbclient clients. */
258 princ_s = talloc_asprintf(tmpctx, "%s@%s",
259 srvPrinc, lp_realm());
260 if (!princ_s) {
261 ret = -1;
262 goto out;
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. */
269 if (!service_or_spn_to_kerberos_princ(tmpctx,
270 srvPrinc,
271 my_fqdn,
272 &princ_s,
273 &short_princ_s)) {
274 ret = -1;
275 goto out;
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 */
283 if (update_ads && !strequal(srvPrinc, "cifs") &&
284 !strequal(srvPrinc, "host")) {
285 if (!ads_set_machine_account_spns(tmpctx,
286 ads,
287 srvPrinc,
288 my_fqdn)) {
289 ret = -1;
290 goto out;
295 for (i = 0; enctypes[i]; i++) {
297 /* add the fqdn principal to the keytab */
298 ret = smb_krb5_kt_add_password(context,
299 keytab,
300 kvno,
301 princ_s,
302 salt_princ_s,
303 enctypes[i],
304 password);
305 if (ret) {
306 DBG_WARNING("Failed to add entry to keytab\n");
307 goto out;
310 /* add the short principal name if we have one */
311 if (short_princ_s) {
312 ret = smb_krb5_kt_add_password(context,
313 keytab,
314 kvno,
315 short_princ_s,
316 salt_princ_s,
317 enctypes[i],
318 password);
319 if (ret) {
320 DBG_WARNING("Failed to add short entry to keytab\n");
321 goto out;
325 out:
326 return ret;
329 /**********************************************************************
330 Adds a single service principal, i.e. 'host' to the system keytab
331 ***********************************************************************/
333 int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
335 krb5_error_code ret = 0;
336 krb5_context context = NULL;
337 krb5_keytab keytab = NULL;
338 krb5_data password;
339 krb5_kvno kvno;
340 char *salt_princ_s = NULL;
341 char *password_s = NULL;
342 char *my_fqdn;
343 TALLOC_CTX *tmpctx = NULL;
344 char **hostnames_array = NULL;
345 size_t num_hostnames = 0;
347 ret = smb_krb5_init_context_common(&context);
348 if (ret) {
349 DBG_ERR("kerberos init context failed (%s)\n",
350 error_message(ret));
351 return -1;
354 ret = ads_keytab_open(context, &keytab);
355 if (ret != 0) {
356 goto out;
359 /* retrieve the password */
360 if (!secrets_init()) {
361 DBG_WARNING("secrets_init failed\n");
362 ret = -1;
363 goto out;
365 password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
366 if (!password_s) {
367 DBG_WARNING("failed to fetch machine password\n");
368 ret = -1;
369 goto out;
371 ZERO_STRUCT(password);
372 password.data = password_s;
373 password.length = strlen(password_s);
375 /* we need the dNSHostName value here */
376 tmpctx = talloc_init(__location__);
377 if (!tmpctx) {
378 DBG_ERR("talloc_init() failed!\n");
379 ret = -1;
380 goto out;
383 my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
384 if (!my_fqdn) {
385 DBG_ERR("unable to determine machine account's dns name in "
386 "AD!\n");
387 ret = -1;
388 goto out;
391 /* make sure we have a single instance of the computer account */
392 if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) {
393 DBG_ERR("unable to determine machine account's short name in "
394 "AD!\n");
395 ret = -1;
396 goto out;
399 kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
400 if (kvno == -1) {
401 /* -1 indicates failure, everything else is OK */
402 DBG_WARNING("ads_get_machine_kvno failed to determine the "
403 "system's kvno.\n");
404 ret = -1;
405 goto out;
408 salt_princ_s = kerberos_secrets_fetch_salt_princ();
409 if (salt_princ_s == NULL) {
410 DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
411 ret = -1;
412 goto out;
415 ret = add_kt_entry_etypes(context, tmpctx, ads, salt_princ_s, keytab,
416 kvno, srvPrinc, my_fqdn, &password,
417 update_ads);
418 if (ret != 0) {
419 goto out;
422 if (ADS_ERR_OK(ads_get_additional_dns_hostnames(tmpctx, ads,
423 lp_netbios_name(),
424 &hostnames_array,
425 &num_hostnames))) {
426 size_t i;
428 for (i = 0; i < num_hostnames; i++) {
430 ret = add_kt_entry_etypes(context, tmpctx, ads,
431 salt_princ_s, keytab,
432 kvno, srvPrinc,
433 hostnames_array[i],
434 &password, update_ads);
435 if (ret != 0) {
436 goto out;
441 out:
442 SAFE_FREE(salt_princ_s);
443 TALLOC_FREE(tmpctx);
445 if (keytab) {
446 krb5_kt_close(context, keytab);
448 if (context) {
449 krb5_free_context(context);
451 return (int)ret;
454 /**********************************************************************
455 Delete a single service principal, i.e. 'host' from the system keytab
456 ***********************************************************************/
458 int ads_keytab_delete_entry(ADS_STRUCT *ads, const char *srvPrinc)
460 TALLOC_CTX *frame = talloc_stackframe();
461 krb5_error_code ret = 0;
462 krb5_context context = NULL;
463 krb5_keytab keytab = NULL;
464 char *princ_s = NULL;
465 krb5_principal princ = NULL;
466 char *short_princ_s = NULL;
467 krb5_principal short_princ = NULL;
468 bool ok;
470 ret = smb_krb5_init_context_common(&context);
471 if (ret) {
472 DBG_ERR("kerberos init context failed (%s)\n",
473 error_message(ret));
474 goto out;
477 ret = ads_keytab_open(context, &keytab);
478 if (ret != 0) {
479 goto out;
482 /* Construct our principal */
483 if (strchr_m(srvPrinc, '@')) {
484 /* It's a fully-named principal. */
485 princ_s = talloc_asprintf(frame, "%s", srvPrinc);
486 if (!princ_s) {
487 ret = -1;
488 goto out;
490 } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
491 /* It's the machine account, as used by smbclient clients. */
492 princ_s = talloc_asprintf(frame, "%s@%s",
493 srvPrinc, lp_realm());
494 if (!princ_s) {
495 ret = -1;
496 goto out;
498 } else {
500 * It's a normal service principal.
502 char *my_fqdn = NULL;
503 char *tmp = NULL;
506 * SPN should have '/' otherwise we
507 * need to fallback and find our dnshostname
509 tmp = strchr_m(srvPrinc, '/');
510 if (tmp == NULL) {
511 my_fqdn = ads_get_dnshostname(ads, frame, lp_netbios_name());
512 if (!my_fqdn) {
513 DBG_ERR("unable to determine machine account's dns name in "
514 "AD!\n");
515 ret = -1;
516 goto out;
520 ok = service_or_spn_to_kerberos_princ(frame,
521 srvPrinc,
522 my_fqdn,
523 &princ_s,
524 &short_princ_s);
525 if (!ok) {
526 ret = -1;
527 goto out;
531 ret = smb_krb5_parse_name(context, princ_s, &princ);
532 if (ret) {
533 DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
534 "failed (%s)\n", princ_s, error_message(ret)));
535 goto out;
538 if (short_princ_s != NULL) {
539 ret = smb_krb5_parse_name(context, short_princ_s, &short_princ);
540 if (ret) {
541 DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
542 "failed (%s)\n", short_princ_s, error_message(ret)));
543 goto out;
547 /* Seek and delete old keytab entries */
548 ret = smb_krb5_kt_seek_and_delete_old_entries(context,
549 keytab,
550 false, /* keep_old_kvno */
552 false, /* enctype_only */
553 ENCTYPE_NULL,
554 princ_s,
555 princ,
556 false); /* flush */
557 if (ret) {
558 goto out;
561 if (short_princ_s == NULL) {
562 goto out;
565 /* Seek and delete old keytab entries */
566 ret = smb_krb5_kt_seek_and_delete_old_entries(context,
567 keytab,
568 false, /* keep_old_kvno */
570 false, /* enctype_only */
571 ENCTYPE_NULL,
572 short_princ_s,
573 short_princ,
574 false); /* flush */
575 if (ret) {
576 goto out;
579 out:
580 if (princ) {
581 krb5_free_principal(context, princ);
583 if (short_princ) {
584 krb5_free_principal(context, short_princ);
586 if (keytab) {
587 krb5_kt_close(context, keytab);
589 if (context) {
590 krb5_free_context(context);
592 TALLOC_FREE(frame);
593 return ret;
596 /**********************************************************************
597 Flushes all entries from the system keytab.
598 ***********************************************************************/
600 int ads_keytab_flush(ADS_STRUCT *ads)
602 krb5_error_code ret = 0;
603 krb5_context context = NULL;
604 krb5_keytab keytab = NULL;
605 ADS_STATUS aderr;
607 ret = smb_krb5_init_context_common(&context);
608 if (ret) {
609 DBG_ERR("kerberos init context failed (%s)\n",
610 error_message(ret));
611 return ret;
614 ret = ads_keytab_open(context, &keytab);
615 if (ret != 0) {
616 goto out;
619 /* Seek and delete all old keytab entries */
620 ret = smb_krb5_kt_seek_and_delete_old_entries(context,
621 keytab,
622 false, /* keep_old_kvno */
624 false, /* enctype_only */
625 ENCTYPE_NULL,
626 NULL,
627 NULL,
628 true); /* flush */
629 if (ret) {
630 goto out;
633 aderr = ads_clear_service_principal_names(ads, lp_netbios_name());
634 if (!ADS_ERR_OK(aderr)) {
635 DEBUG(1, (__location__ ": Error while clearing service "
636 "principal listings in LDAP.\n"));
637 ret = -1;
638 goto out;
641 out:
642 if (keytab) {
643 krb5_kt_close(context, keytab);
645 if (context) {
646 krb5_free_context(context);
648 return ret;
651 /**********************************************************************
652 Adds all the required service principals to the system keytab.
653 ***********************************************************************/
655 int ads_keytab_create_default(ADS_STRUCT *ads)
657 krb5_error_code ret = 0;
658 krb5_context context = NULL;
659 krb5_keytab keytab = NULL;
660 krb5_kt_cursor cursor = {0};
661 krb5_keytab_entry kt_entry = {0};
662 krb5_kvno kvno;
663 size_t found = 0;
664 char *sam_account_name, *upn;
665 char **oldEntries = NULL, *princ_s[26];
666 TALLOC_CTX *frame;
667 char *machine_name;
668 char **spn_array;
669 size_t num_spns;
670 size_t i;
671 bool ok = false;
672 ADS_STATUS status;
674 ZERO_STRUCT(kt_entry);
675 ZERO_STRUCT(cursor);
677 frame = talloc_stackframe();
678 if (frame == NULL) {
679 ret = -1;
680 goto done;
683 status = ads_get_service_principal_names(frame,
684 ads,
685 lp_netbios_name(),
686 &spn_array,
687 &num_spns);
688 if (!ADS_ERR_OK(status)) {
689 ret = -1;
690 goto done;
693 for (i = 0; i < num_spns; i++) {
694 char *srv_princ;
695 char *p;
697 srv_princ = strlower_talloc(frame, spn_array[i]);
698 if (srv_princ == NULL) {
699 ret = -1;
700 goto done;
703 p = strchr_m(srv_princ, '/');
704 if (p == NULL) {
705 continue;
707 p[0] = '\0';
709 /* Add the SPNs found on the DC */
710 ret = ads_keytab_add_entry(ads, srv_princ, false);
711 if (ret != 0) {
712 DEBUG(1, ("ads_keytab_add_entry failed while "
713 "adding '%s' principal.\n",
714 spn_array[i]));
715 goto done;
719 #if 0 /* don't create the CIFS/... keytab entries since no one except smbd
720 really needs them and we will fall back to verifying against
721 secrets.tdb */
723 ret = ads_keytab_add_entry(ads, "cifs", false));
724 if (ret != 0 ) {
725 DEBUG(1, (__location__ ": ads_keytab_add_entry failed while "
726 "adding 'cifs'.\n"));
727 return ret;
729 #endif
731 memset(princ_s, '\0', sizeof(princ_s));
733 ret = smb_krb5_init_context_common(&context);
734 if (ret) {
735 DBG_ERR("kerberos init context failed (%s)\n",
736 error_message(ret));
737 goto done;
740 machine_name = talloc_strdup(frame, lp_netbios_name());
741 if (!machine_name) {
742 ret = -1;
743 goto done;
746 /* now add the userPrincipalName and sAMAccountName entries */
747 ok = ads_has_samaccountname(ads, frame, machine_name);
748 if (!ok) {
749 DEBUG(0, (__location__ ": unable to determine machine "
750 "account's name in AD!\n"));
751 ret = -1;
752 goto done;
756 * append '$' to netbios name so 'ads_keytab_add_entry' recognises
757 * it as a machine account rather than a service or Windows SPN.
759 sam_account_name = talloc_asprintf(frame, "%s$",machine_name);
760 if (sam_account_name == NULL) {
761 ret = -1;
762 goto done;
764 /* upper case the sAMAccountName to make it easier for apps to
765 know what case to use in the keytab file */
766 if (!strupper_m(sam_account_name)) {
767 ret = -1;
768 goto done;
771 ret = ads_keytab_add_entry(ads, sam_account_name, false);
772 if (ret != 0) {
773 DEBUG(1, (__location__ ": ads_keytab_add_entry() failed "
774 "while adding sAMAccountName (%s)\n",
775 sam_account_name));
776 goto done;
779 /* remember that not every machine account will have a upn */
780 upn = ads_get_upn(ads, frame, machine_name);
781 if (upn) {
782 ret = ads_keytab_add_entry(ads, upn, false);
783 if (ret != 0) {
784 DEBUG(1, (__location__ ": ads_keytab_add_entry() "
785 "failed while adding UPN (%s)\n", upn));
786 goto done;
790 /* Now loop through the keytab and update any other existing entries */
791 kvno = (krb5_kvno)ads_get_machine_kvno(ads, machine_name);
792 if (kvno == (krb5_kvno)-1) {
793 DEBUG(1, (__location__ ": ads_get_machine_kvno() failed to "
794 "determine the system's kvno.\n"));
795 goto done;
798 DEBUG(3, (__location__ ": Searching for keytab entries to preserve "
799 "and update.\n"));
801 ret = ads_keytab_open(context, &keytab);
802 if (ret != 0) {
803 goto done;
806 ret = krb5_kt_start_seq_get(context, keytab, &cursor);
807 if (ret != KRB5_KT_END && ret != ENOENT ) {
808 while ((ret = krb5_kt_next_entry(context, keytab,
809 &kt_entry, &cursor)) == 0) {
810 smb_krb5_kt_free_entry(context, &kt_entry);
811 ZERO_STRUCT(kt_entry);
812 found++;
815 krb5_kt_end_seq_get(context, keytab, &cursor);
816 ZERO_STRUCT(cursor);
819 * Hmmm. There is no "rewind" function for the keytab. This means we
820 * have a race condition where someone else could add entries after
821 * we've counted them. Re-open asap to minimise the race. JRA.
823 DEBUG(3, (__location__ ": Found %zd entries in the keytab.\n", found));
824 if (!found) {
825 goto done;
828 oldEntries = talloc_zero_array(frame, char *, found + 1);
829 if (!oldEntries) {
830 DEBUG(1, (__location__ ": Failed to allocate space to store "
831 "the old keytab entries (talloc failed?).\n"));
832 ret = -1;
833 goto done;
836 ret = krb5_kt_start_seq_get(context, keytab, &cursor);
837 if (ret == KRB5_KT_END || ret == ENOENT) {
838 krb5_kt_end_seq_get(context, keytab, &cursor);
839 ZERO_STRUCT(cursor);
840 goto done;
843 while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
844 if (kt_entry.vno != kvno) {
845 char *ktprinc = NULL;
846 char *p;
848 /* This returns a malloc'ed string in ktprinc. */
849 ret = smb_krb5_unparse_name(oldEntries, context,
850 kt_entry.principal,
851 &ktprinc);
852 if (ret) {
853 DEBUG(1, (__location__
854 ": smb_krb5_unparse_name failed "
855 "(%s)\n", error_message(ret)));
856 goto done;
859 * From looking at the krb5 source they don't seem to
860 * take locale or mb strings into account.
861 * Maybe this is because they assume utf8 ?
862 * In this case we may need to convert from utf8 to
863 * mb charset here ? JRA.
865 p = strchr_m(ktprinc, '@');
866 if (p) {
867 *p = '\0';
870 p = strchr_m(ktprinc, '/');
871 if (p) {
872 *p = '\0';
874 for (i = 0; i < found; i++) {
875 if (!oldEntries[i]) {
876 oldEntries[i] = ktprinc;
877 break;
879 if (!strcmp(oldEntries[i], ktprinc)) {
880 TALLOC_FREE(ktprinc);
881 break;
884 if (i == found) {
885 TALLOC_FREE(ktprinc);
888 smb_krb5_kt_free_entry(context, &kt_entry);
889 ZERO_STRUCT(kt_entry);
891 krb5_kt_end_seq_get(context, keytab, &cursor);
892 ZERO_STRUCT(cursor);
894 ret = 0;
895 for (i = 0; oldEntries[i]; i++) {
896 ret |= ads_keytab_add_entry(ads, oldEntries[i], false);
897 TALLOC_FREE(oldEntries[i]);
900 done:
901 TALLOC_FREE(oldEntries);
902 TALLOC_FREE(frame);
904 if (context) {
905 if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
906 smb_krb5_kt_free_entry(context, &kt_entry);
908 if (!all_zero((uint8_t *)&cursor, sizeof(cursor)) && keytab) {
909 krb5_kt_end_seq_get(context, keytab, &cursor);
911 if (keytab) {
912 krb5_kt_close(context, keytab);
914 krb5_free_context(context);
916 return ret;
919 #endif /* HAVE_ADS */
921 /**********************************************************************
922 List system keytab.
923 ***********************************************************************/
925 int ads_keytab_list(const char *keytab_name)
927 krb5_error_code ret = 0;
928 krb5_context context = NULL;
929 krb5_keytab keytab = NULL;
930 krb5_kt_cursor cursor;
931 krb5_keytab_entry kt_entry;
933 ZERO_STRUCT(kt_entry);
934 ZERO_STRUCT(cursor);
936 ret = smb_krb5_init_context_common(&context);
937 if (ret) {
938 DBG_ERR("kerberos init context failed (%s)\n",
939 error_message(ret));
940 return ret;
943 if (keytab_name == NULL) {
944 #ifdef HAVE_ADS
945 ret = ads_keytab_open(context, &keytab);
946 #else
947 ret = ENOENT;
948 #endif
949 } else {
950 ret = smb_krb5_kt_open(context, keytab_name, False, &keytab);
952 if (ret) {
953 DEBUG(1, ("smb_krb5_kt_open failed (%s)\n",
954 error_message(ret)));
955 goto out;
958 ret = krb5_kt_start_seq_get(context, keytab, &cursor);
959 if (ret) {
960 ZERO_STRUCT(cursor);
961 goto out;
964 printf("Vno Type Principal\n");
966 while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
968 char *princ_s = NULL;
969 char *etype_s = NULL;
970 krb5_enctype enctype = 0;
972 ret = smb_krb5_unparse_name(talloc_tos(), context,
973 kt_entry.principal, &princ_s);
974 if (ret) {
975 goto out;
978 enctype = smb_krb5_kt_get_enctype_from_entry(&kt_entry);
980 ret = smb_krb5_enctype_to_string(context, enctype, &etype_s);
981 if (ret &&
982 (asprintf(&etype_s, "UNKNOWN: %d", enctype) == -1)) {
983 TALLOC_FREE(princ_s);
984 goto out;
987 printf("%3d %-43s %s\n", kt_entry.vno, etype_s, princ_s);
989 TALLOC_FREE(princ_s);
990 SAFE_FREE(etype_s);
992 ret = smb_krb5_kt_free_entry(context, &kt_entry);
993 if (ret) {
994 goto out;
998 ret = krb5_kt_end_seq_get(context, keytab, &cursor);
999 if (ret) {
1000 goto out;
1003 /* Ensure we don't double free. */
1004 ZERO_STRUCT(kt_entry);
1005 ZERO_STRUCT(cursor);
1006 out:
1008 if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
1009 smb_krb5_kt_free_entry(context, &kt_entry);
1011 if (!all_zero((uint8_t *)&cursor, sizeof(cursor)) && keytab) {
1012 krb5_kt_end_seq_get(context, keytab, &cursor);
1015 if (keytab) {
1016 krb5_kt_close(context, keytab);
1018 if (context) {
1019 krb5_free_context(context);
1021 return ret;
1024 #endif /* HAVE_KRB5 */