2 * Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from
3 * http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view
5 * Copyright (c) 2002-2004 The Regents of the University of Michigan.
8 * Andy Adamson <andros@umich.edu>
9 * J. Bruce Fields <bfields@umich.edu>
10 * Marius Aamodt Eriksen <marius@umich.edu>
11 * Kevin Coffman <kwc@umich.edu>
17 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
18 * All Rights Reserved.
20 * Export of this software from the United States of America may
21 * require a specific license from the United States Government.
22 * It is the responsibility of any person or organization contemplating
23 * export to obtain such a license before exporting.
25 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
26 * distribute this software and its documentation for any purpose and
27 * without fee is hereby granted, provided that the above copyright
28 * notice appear in all copies and that both that copyright notice and
29 * this permission notice appear in supporting documentation, and that
30 * the name of M.I.T. not be used in advertising or publicity pertaining
31 * to distribution of the software without specific, written prior
32 * permission. Furthermore if you modify this software you must label
33 * your software as modified software and not distribute it in such a
34 * fashion that it might be confused with the original M.I.T. software.
35 * M.I.T. makes no representations about the suitability of
36 * this software for any purpose. It is provided "as is" without express
37 * or implied warranty.
41 * Copyright 1994 by OpenVision Technologies, Inc.
43 * Permission to use, copy, modify, distribute, and sell this software
44 * and its documentation for any purpose is hereby granted without fee,
45 * provided that the above copyright notice appears in all copies and
46 * that both that copyright notice and this permission notice appear in
47 * supporting documentation, and that the name of OpenVision not be used
48 * in advertising or publicity pertaining to distribution of the software
49 * without specific, written prior permission. OpenVision makes no
50 * representations about the suitability of this software for any
51 * purpose. It is provided "as is" without express or implied warranty.
53 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
54 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
55 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
56 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
57 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
58 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
59 * PERFORMANCE OF THIS SOFTWARE.
64 Copyright (c) 2004 The Regents of the University of Michigan.
67 Redistribution and use in source and binary forms, with or without
68 modification, are permitted provided that the following conditions
71 1. Redistributions of source code must retain the above copyright
72 notice, this list of conditions and the following disclaimer.
73 2. Redistributions in binary form must reproduce the above copyright
74 notice, this list of conditions and the following disclaimer in the
75 documentation and/or other materials provided with the distribution.
76 3. Neither the name of the University nor the names of its
77 contributors may be used to endorse or promote products derived
78 from this software without specific prior written permission.
80 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
81 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
82 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
83 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
84 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
85 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
86 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
87 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
88 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
89 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
90 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
98 #include <sys/param.h>
100 #include <sys/types.h>
101 #include <sys/stat.h>
102 #include <sys/utsname.h>
103 #include <sys/socket.h>
104 #include <arpa/inet.h>
117 #include <gssapi/gssapi.h>
118 #ifdef USE_PRIVATE_KRB5_FUNCTIONS
119 #include <gssapi/gssapi_krb5.h>
124 #include "err_util.h"
125 #include "gss_util.h"
126 #include "gss_oids.h"
127 #include "krb5_util.h"
129 /* Global list of principals/cache file names for machine credentials */
130 struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
132 /* Encryption types supported by the kernel rpcsec_gss code */
133 int num_krb5_enctypes = 0;
134 krb5_enctype *krb5_enctypes = NULL;
136 /* credential expire time in advance */
137 unsigned long machine_cred_expire_advance = 300; /* 5 mins */
139 /*==========================*/
140 /*=== Internal routines ===*/
141 /*==========================*/
143 static int select_krb5_ccache(const struct dirent *d);
144 static int gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d);
145 static int gssd_get_single_krb5_cred(krb5_context context,
146 krb5_keytab kt, struct gssd_k5_kt_princ *ple);
147 static int gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt,
151 * convenient macros, these perhaps need further cleanup
155 #define KEYTAB_ENTRY_MATCH(kte, name) \
157 (kte).principal->data[0].length == (sizeof(name)-1) && \
158 strncmp((kte).principal->data[0].data, (name), sizeof(name)-1) == 0 \
160 #define KRB5_FREE_UNPARSED_NAME(ctx, name) \
161 krb5_free_unparsed_name((ctx), (name));
162 #define KRB5_STRDUP(str) \
163 strndup((str).data, (str).length)
164 #define KRB5_STRCMP(str, name) \
166 (str)->length != strlen(name) || \
167 strncmp((str)->data, (name), (str)->length) != 0 \
169 #define KRB5_STRCASECMP(str, name) \
171 (str)->length != strlen(name) || \
172 strncasecmp((str)->data, (name), (str)->length) != 0 \
175 #else /* !HAVE_KRB5 */
177 #define KEYTAB_ENTRY_MATCH(kte, name) \
179 strlen((kte).principal->name.name_string.val[0]) == \
180 (sizeof(name)-1) && \
181 strncmp(kte.principal->name.name_string.val[0], (name), \
182 sizeof(name)-1) == 0 \
184 #define KRB5_FREE_UNPARSED_NAME(ctx, name) \
186 #define KRB5_STRDUP(str) \
188 #define KRB5_STRCMP(str, name) \
189 strcmp((str), (name))
190 #define KRB5_STRCASECMP(str, name) \
191 strcmp((str), (name))
193 #endif /* HAVE_KRB5 */
196 * Called from the scandir function to weed out potential krb5
197 * credentials cache files
200 * 0 => don't select this one
201 * 1 => select this one
204 select_krb5_ccache(const struct dirent *d)
207 * Note: We used to check d->d_type for DT_REG here,
208 * but apparenlty reiser4 always has DT_UNKNOWN.
209 * Check for IS_REG after stat() call instead.
211 if (strstr(d->d_name, GSSD_DEFAULT_CRED_PREFIX))
218 * Look in the ccachedir for files that look like they
219 * are Kerberos Credential Cache files for a given UID. Return
220 * non-zero and the dirent pointer for the entry most likely to be
221 * what we want. Otherwise, return zero and no dirent pointer.
222 * The caller is responsible for freeing the dirent if one is returned.
225 * 0 => could not find an existing entry
226 * 1 => found an existing entry
229 gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d)
231 struct dirent **namelist;
235 struct dirent *best_match_dir = NULL;
236 struct stat best_match_stat, tmp_stat;
238 memset(&best_match_stat, 0, sizeof(best_match_stat));
240 n = scandir(ccachedir, &namelist, select_krb5_ccache, 0);
242 perror("scandir looking for krb5 credentials caches");
246 for (i = 0; i < n; i++) {
247 printerr(3, "CC file '%s' being considered\n",
248 namelist[i]->d_name);
249 snprintf(statname, sizeof(statname),
250 "%s/%s", ccachedir, namelist[i]->d_name);
251 if (stat(statname, &tmp_stat)) {
252 printerr(0, "Error doing stat on file '%s'\n",
257 /* Only pick caches owned by the user (uid) */
258 if (tmp_stat.st_uid != uid) {
259 printerr(3, "'%s' owned by %u, not %u\n",
260 statname, tmp_stat.st_uid, uid);
264 if (!S_ISREG(tmp_stat.st_mode)) {
265 printerr(3, "'%s' is not a regular file\n",
270 printerr(3, "CC file '%s' matches owner check and has "
272 namelist[i]->d_name, tmp_stat.st_mtime);
274 * if more than one match is found, return the most
275 * recent (the one with the latest mtime), and
276 * don't free the dirent
279 best_match_dir = namelist[i];
280 best_match_stat = tmp_stat;
285 * If the current match has an mtime later
286 * than the one we are looking at, then use
287 * the current match. Otherwise, we still
288 * have the best match.
290 if (tmp_stat.st_mtime >
291 best_match_stat.st_mtime) {
292 free(best_match_dir);
293 best_match_dir = namelist[i];
294 best_match_stat = tmp_stat;
299 printerr(3, "CC file '%s' is our "
300 "current best match "
301 "with mtime of %u\n",
302 best_match_dir->d_name,
303 best_match_stat.st_mtime);
317 * Obtain credentials via a key in the keytab given
318 * a keytab handle and a gssd_k5_kt_princ structure.
319 * Checks to see if current credentials are expired,
320 * if not, uses the keytab to obtain new credentials.
323 * 0 => success (or credentials have not expired)
327 gssd_get_single_krb5_cred(krb5_context context,
329 struct gssd_k5_kt_princ *ple)
331 krb5_get_init_creds_opt options;
333 krb5_ccache ccache = NULL;
334 char kt_name[BUFSIZ];
335 char cc_name[BUFSIZ];
337 time_t now = time(0);
340 memset(&my_creds, 0, sizeof(my_creds));
342 if (ple->ccname && ple->endtime > now + machine_cred_expire_advance) {
343 printerr(2, "INFO: Credentials in CC '%s' are good until %d\n",
344 ple->ccname, ple->endtime);
349 if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) {
350 printerr(0, "ERROR: Unable to get keytab name in "
351 "gssd_get_single_krb5_cred\n");
355 krb5_get_init_creds_opt_init(&options);
356 krb5_get_init_creds_opt_set_address_list(&options, NULL);
358 #ifdef TEST_SHORT_LIFETIME
359 /* set a short lifetime (for debugging only!) */
360 printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n");
361 krb5_get_init_creds_opt_set_tkt_life(&options, 5*60);
363 /* FIXME try to get the ticket with lifetime as long as possible,
364 * to work around ticket-expiry + recovery problem in cmd3-11
367 krb5_get_init_creds_opt_set_tkt_life(&options, 30*24*60*60);
369 if ((code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ,
370 kt, 0, NULL, &options))) {
372 if ((krb5_unparse_name(context, ple->princ, &pname))) {
375 printerr(0, "WARNING: %s while getting initial ticket for "
376 "principal '%s' from keytab '%s'\n",
378 pname ? pname : "<unparsable>", kt_name);
379 if (pname) KRB5_FREE_UNPARSED_NAME(context, pname);
384 * Initialize cache file which we're going to be using
388 cache_type = "MEMORY";
391 snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s",
393 GSSD_DEFAULT_CRED_DIR, GSSD_DEFAULT_CRED_PREFIX,
394 GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm);
395 ple->endtime = my_creds.times.endtime;
396 ple->ccname = strdup(cc_name);
397 if (ple->ccname == NULL) {
398 printerr(0, "ERROR: no storage to duplicate credentials "
403 if ((code = krb5_cc_resolve(context, cc_name, &ccache))) {
404 printerr(0, "ERROR: %s while opening credential cache '%s'\n",
405 error_message(code), cc_name);
408 if ((code = krb5_cc_initialize(context, ccache, ple->princ))) {
409 printerr(0, "ERROR: %s while initializing credential "
410 "cache '%s'\n", error_message(code), cc_name);
413 if ((code = krb5_cc_store_cred(context, ccache, &my_creds))) {
414 printerr(0, "ERROR: %s while storing credentials in '%s'\n",
415 error_message(code), cc_name);
420 printerr(1, "Using (machine) credentials cache: '%s'\n", cc_name);
423 krb5_cc_close(context, ccache);
424 krb5_free_cred_contents(context, &my_creds);
428 static struct gssd_k5_kt_princ * gssd_get_realm_ple(void *r)
430 struct gssd_k5_kt_princ *ple;
432 krb5_data *realm = (krb5_data *)r;
434 char *realm = (char *)r;
437 for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
438 if (KRB5_STRCMP(realm, ple->realm) == 0)
444 static void gssd_free_ple(krb5_context kctx, struct gssd_k5_kt_princ *ple)
447 krb5_free_principal(kctx, ple->princ);
455 static int gssd_remove_ple(krb5_context kctx, struct gssd_k5_kt_princ *ple)
457 struct gssd_k5_kt_princ **prev = &gssd_k5_kt_princ_list;
458 struct gssd_k5_kt_princ *ent = gssd_k5_kt_princ_list;
460 for (; ent; prev = &ent->next, ent = ent->next) {
465 gssd_free_ple(kctx, ent);
472 struct gssd_k5_kt_princ *gssd_create_ple(krb5_context kctx,
473 krb5_principal principal)
475 struct gssd_k5_kt_princ *ple;
476 krb5_error_code code;
478 ple = malloc(sizeof(*ple));
480 printerr(0, "ERROR: could not allocate storage "
481 "for principal list entry\n");
485 memset(ple, 0, sizeof(*ple));
487 ple->realm = KRB5_STRDUP(principal->realm);
488 if (ple->realm == NULL) {
489 printerr(0, "ERROR: not enough memory while copying realm to "
490 "principal list entry\n");
494 code = krb5_copy_principal(kctx, principal, &ple->princ);
496 printerr(0, "ERROR: %s while copying principal "
497 "to principal list entry\n",
498 error_message(code));
504 gssd_free_ple(kctx, ple);
509 * Process the given keytab file and create a list of principals we
510 * might use to perform mount operations.
517 gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt, char *kt_name)
519 krb5_kt_cursor cursor;
520 krb5_keytab_entry kte;
521 krb5_error_code code;
522 struct gssd_k5_kt_princ *ple;
526 * Look through each entry in the keytab file and determine
527 * if we might want to use it later to do a mount. If so,
528 * save info in the global principal list
529 * (gssd_k5_kt_princ_list).
530 * Note: (ple == principal list entry)
532 if ((code = krb5_kt_start_seq_get(context, kt, &cursor))) {
533 printerr(0, "ERROR: %s while beginning keytab scan "
535 error_message(code), kt_name);
540 while ((code = krb5_kt_next_entry(context, kt, &kte, &cursor)) == 0) {
542 if ((code = krb5_unparse_name(context, kte.principal,
544 printerr(0, "WARNING: Skipping keytab entry because "
545 "we failed to unparse principal name: %s\n",
546 error_message(code));
549 printerr(2, "Processing keytab entry for principal '%s'\n",
552 /* mds service entry:
553 * - hostname and realm should match this node
554 * - replace existing non-mds entry of this realm
556 if (KEYTAB_ENTRY_MATCH(kte, GSSD_SERVICE_MDS)) {
557 krb5_principal princ = kte.principal;
558 krb5_data *princ_host;
559 struct utsname utsbuf;
560 struct hostent *host;
562 if (KRB5_STRCASECMP(krb5_princ_realm(context, princ),
564 printerr(2, "alien mds service entry, skip\n");
568 princ_host = krb5_princ_component(context, princ, 1);
569 if (princ_host == NULL) {
570 printerr(2, "mds service entry: no hostname in "
571 "principal, skip\n");
575 if (uname(&utsbuf)) {
576 printerr(2, "mds service entry: unable to get "
580 host = gethostbyname(utsbuf.nodename);
582 printerr(2, "mds service entry: unable to get "
583 "local hostname, skip\n");
587 if (KRB5_STRCASECMP(princ_host, host->h_name) != 0) {
588 printerr(2, "mds service entry: hostname "
589 "doesn't match: %s - %.*s, skip\n",
591 princ_host->length, princ_host->data);
595 ple = gssd_get_realm_ple((void *)&kte.principal->realm);
598 printerr(2,"mds service entry: found a"
599 "duplicated one, it's like a "
600 "mis-configuration, skip\n");
604 gssd_remove_ple(context, ple);
605 printerr(2, "mds service entry: replace an "
606 "existed non-mds one\n");
608 } else if (KEYTAB_ENTRY_MATCH(kte, LUSTRE_ROOT_NAME)) {
609 ple = gssd_get_realm_ple((void *)&kte.principal->realm);
611 if (ple->fl_mds || ple->fl_root) {
612 printerr(2, "root entry: found a "
613 "existed %s entry, skip\n",
614 ple->fl_mds ? "mds" : "root");
618 gssd_remove_ple(context, ple);
619 printerr(2, "root entry: replace an existed "
620 "non-mds non-root one\n");
623 printerr(2, "We will NOT use this entry (%s)\n",
629 printerr(2, "We will use this entry (%s)\n", pname);
630 ple = gssd_create_ple(context, kte.principal);
632 KRB5_FREE_UNPARSED_NAME(context, pname);
636 /* add proper flags */
637 if (KEYTAB_ENTRY_MATCH(kte, GSSD_SERVICE_MDS))
639 else if (KEYTAB_ENTRY_MATCH(kte, LUSTRE_ROOT_NAME))
643 if (gssd_k5_kt_princ_list == NULL)
644 gssd_k5_kt_princ_list = ple;
646 ple->next = gssd_k5_kt_princ_list;
647 gssd_k5_kt_princ_list = ple;
650 KRB5_FREE_UNPARSED_NAME(context, pname);
653 if ((code = krb5_kt_end_seq_get(context, kt, &cursor))) {
654 printerr(0, "WARNING: %s while ending keytab scan for "
656 error_message(code), kt_name);
665 * Depending on the version of Kerberos, we either need to use
666 * a private function, or simply set the environment variable.
669 gssd_set_krb5_ccache_name(char *ccname)
671 #ifdef USE_GSS_KRB5_CCACHE_NAME
672 unsigned int maj_stat, min_stat;
674 printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n",
676 maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL);
677 if (maj_stat != GSS_S_COMPLETE) {
678 printerr(0, "WARNING: gss_krb5_ccache_name with "
679 "name '%s' failed (%s)\n",
680 ccname, error_message(min_stat));
684 * Set the KRB5CCNAME environment variable to tell the krb5 code
685 * which credentials cache to use. (Instead of using the private
686 * function above for which there is no generic gssapi
689 printerr(2, "using environment variable to select krb5 ccache %s\n",
691 setenv("KRB5CCNAME", ccname, 1);
696 * Parse the supported encryption type information
699 parse_enctypes(char *enctypes)
705 /* Just in case this ever gets called more than once */
706 if (krb5_enctypes != NULL) {
708 krb5_enctypes = NULL;
709 num_krb5_enctypes = 0;
712 /* count the number of commas */
713 for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
714 comma = strchr(curr, ',');
720 /* If no more commas and we're not at the end, there's one more value */
724 /* Empty string, return an error */
728 /* Allocate space for enctypes array */
729 if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
733 /* Now parse each value into the array */
734 for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
735 krb5_enctypes[i++] = atoi(curr);
736 comma = strchr(curr, ',');
741 num_krb5_enctypes = n;
745 /*==========================*/
746 /*=== External routines ===*/
747 /*==========================*/
750 * Attempt to find the best match for a credentials cache file
751 * given only a UID. We really need more information, but we
752 * do the best we can.
758 gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername)
760 char buf[MAX_NETOBJ_SZ];
763 printerr(2, "getting credentials for client with uid %u for "
764 "server %s\n", uid, servername);
765 memset(buf, 0, sizeof(buf));
767 if (gssd_find_existing_krb5_ccache(uid, &d)) {
768 snprintf(buf, sizeof(buf), "FILE:%s/%s",
769 ccachedir, d->d_name);
773 snprintf(buf, sizeof(buf), "FILE:%s/%s%u",
774 ccachedir, GSSD_DEFAULT_CRED_PREFIX, uid);
775 printerr(2, "using %s as credentials cache for client with "
776 "uid %u for server %s\n", buf, uid, servername);
777 gssd_set_krb5_ccache_name(buf);
781 * Let the gss code know where to find the machine credentials ccache.
787 gssd_setup_krb5_machine_gss_ccache(char *ccname)
789 printerr(2, "using %s as credentials cache for machine creds\n",
791 gssd_set_krb5_ccache_name(ccname);
795 * The first time through this routine, go through the keytab and
796 * determine which keys we will try to use as machine credentials.
797 * Every time through this routine, try to obtain credentials using
798 * the keytab entries selected the first time through.
801 * 0 => obtained one or more credentials
807 gssd_refresh_krb5_machine_creds(void)
809 krb5_context context = NULL;
810 krb5_keytab kt = NULL;;
811 krb5_error_code code;
813 struct gssd_k5_kt_princ *ple;
815 static int processed_keytab = 0;
818 code = krb5_init_context(&context);
820 printerr(0, "ERROR: %s while initializing krb5 in "
821 "gssd_refresh_krb5_machine_creds\n",
822 error_message(code));
827 printerr(2, "Using keytab file '%s'\n", keytabfile);
829 if ((code = krb5_kt_resolve(context, keytabfile, &kt))) {
830 printerr(0, "ERROR: %s while resolving keytab '%s'\n",
831 error_message(code), keytabfile);
835 /* Only go through the keytab file once. Only print messages once. */
836 if (gssd_k5_kt_princ_list == NULL && !processed_keytab) {
837 processed_keytab = 1;
838 gssd_process_krb5_keytab(context, kt, keytabfile);
839 if (gssd_k5_kt_princ_list == NULL) {
840 printerr(0, "ERROR: No usable keytab entries found in "
841 "keytab '%s'\n", keytabfile);
842 printerr(0, "You must have a valid keytab entry for "
843 "%s/<your.host>@<YOUR.REALM> on MDT nodes, "
844 "and %s@<YOUR.REALM> on client nodes, in "
845 "keytab file %s ?\n",
846 GSSD_SERVICE_MDS, LUSTRE_ROOT_NAME,
852 * If we don't have any keytab entries we liked, then we have a problem
854 if (gssd_k5_kt_princ_list == NULL) {
860 * Now go through the list of saved entries and get initial
861 * credentials for them (We can't do this while making the
862 * list because it messes up the keytab iteration cursor
863 * when we use the keytab to get credentials.)
865 for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
866 if ((gssd_get_single_krb5_cred(context, kt, ple)) == 0) {
871 printerr(0, "ERROR: No usable machine credentials obtained\n");
877 if (kt) krb5_kt_close(context, kt);
878 krb5_free_context(context);
885 * Return an array of pointers to names of credential cache files
886 * which can be used to try to create gss contexts with a server.
889 * 0 => list is attached
893 gssd_get_krb5_machine_cred_list(char ***list)
897 int listsize = listinc;
900 struct gssd_k5_kt_princ *ple;
905 /* Refresh machine credentials */
906 retval = gssd_refresh_krb5_machine_creds();
910 l = malloc(listsize * sizeof(char *));
916 for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
918 if (i + 1 > listsize) {
922 tmp = realloc(l, listsize * sizeof(char *));
929 l[i] = strdup(ple->ccname);
930 if (l[i++] == NULL) {
950 * Frees the list of names returned in get_krb5_machine_cred_list()
953 gssd_free_krb5_machine_cred_list(char **list)
959 for (n = list; n && *n; n++) {
966 * Called upon exit. Destroys machine credentials.
969 gssd_destroy_krb5_machine_creds(void)
971 krb5_context context;
972 krb5_error_code code = 0;
974 struct gssd_k5_kt_princ *ple;
976 code = krb5_init_context(&context);
978 printerr(0, "ERROR: %s while initializing krb5\n",
979 error_message(code));
983 for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
986 if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) {
987 printerr(0, "WARNING: %s while resolving credential "
988 "cache '%s' for destruction\n",
989 error_message(code), ple->ccname);
993 if ((code = krb5_cc_destroy(context, ccache))) {
994 printerr(0, "WARNING: %s while destroying credential "
996 error_message(code), ple->ccname);
1000 krb5_free_context(context);