1 diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
2 index ccadb07..c1339b6 100644
3 --- a/utils/gssd/gssd.c
4 +++ b/utils/gssd/gssd.c
5 @@ -60,6 +60,7 @@ char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
6 char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR;
7 char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1];
10 int root_uses_machine_creds = 1;
11 unsigned int context_timeout = 0;
12 char *preferred_realm = NULL;
13 @@ -85,7 +86,7 @@ sig_hup(int signal)
17 - fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n",
18 + fprintf(stderr, "usage: %s [-f] [-K] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n",
22 @@ -102,7 +103,7 @@ main(int argc, char *argv[])
25 memset(ccachesearch, 0, sizeof(ccachesearch));
26 - while ((opt = getopt(argc, argv, "fvrmnMp:k:d:t:R:")) != -1) {
27 + while ((opt = getopt(argc, argv, "fvrmnMKp:k:d:t:R:")) != -1) {
31 @@ -113,6 +114,9 @@ main(int argc, char *argv[])
39 root_uses_machine_creds = 0;
41 diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
42 index b1b5793..82c4406 100644
43 --- a/utils/gssd/gssd.h
44 +++ b/utils/gssd/gssd.h
45 @@ -63,6 +63,7 @@ extern char pipefs_dir[PATH_MAX];
46 extern char keytabfile[PATH_MAX];
47 extern char *ccachesearch[];
48 extern int use_memcache;
49 +extern int use_kcmcache;
50 extern int root_uses_machine_creds;
51 extern unsigned int context_timeout;
52 extern char *preferred_realm;
53 diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
54 index f071600..503cac2 100644
55 --- a/utils/gssd/krb5_util.c
56 +++ b/utils/gssd/krb5_util.c
60 #include "krb5_util.h"
63 /* Global list of principals/cache file names for machine credentials */
64 struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
65 @@ -299,6 +300,115 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
71 +gssd_find_existing_krb5_ccache_kcm(uid_t uid, char **cc)
73 + krb5_context context;
74 + krb5_cc_cache_cursor cursor;
76 + char *best_match_name = NULL;
77 + krb5_timestamp best_match_mtime, mtime;
83 + char *princname = NULL;
85 + int score, best_match_score = 0, err = -EACCES;
88 + if (krb5_init_context(&context))
91 + if (krb5_cc_cache_get_first(context, "KCM", &cursor))
94 + while (krb5_cc_cache_next(context, cursor, &id) == 0) {
95 + ccname = xstrdup(krb5_cc_get_name(context, id));
96 + if (ccname == NULL) {
97 + printerr(0, "Error getting CC name\n");
100 + for (i=0,ccuid=0; ccname[i] && isdigit(ccname[i]); i++) {
101 + ccuid = ccuid*10 + (ccname[i] - '0');
104 + printerr(3, "CC '%s' not available due to"
105 + " non-standard name\n",
109 + /* Only pick caches owned by the user (uid) */
110 + if (ccuid != uid) {
111 + printerr(3, "CC '%s' owned by %u, not %u\n",
112 + ccname, ccuid, uid);
115 + snprintf(buf, sizeof(buf), "KCM:%s", ccname);
116 + if (!query_krb5_ccache(buf, &princname, &realm)) {
117 + printerr(3, "CC '%s' is expired or corrupt\n",
119 + err = -EKEYEXPIRED;
122 + krb5_cc_last_change_time(context, id, &mtime);
125 + if (preferred_realm && strcmp(realm, preferred_realm) == 0)
128 + printerr(3, "CC '%s'(%s@%s) passed all checks and"
129 + " has mtime of %u\n",
130 + ccname, princname, realm, mtime);
132 + * if more than one match is found, return the most
133 + * recent (the one with the latest mtime), and
134 + * don't free the dirent
137 + best_match_name = ccname;
138 + best_match_mtime = mtime;
139 + best_match_score = score;
143 + * If current score is higher than best match
144 + * score, we use the current match. Otherwise,
145 + * if the current match has an mtime later
146 + * than the one we are looking at, then use
147 + * the current match. Otherwise, we still
148 + * have the best match.
150 + if (best_match_score < score ||
151 + (best_match_score == score &&
152 + mtime > best_match_mtime)) {
153 + free(best_match_name);
154 + best_match_name = ccname;
155 + best_match_mtime = mtime;
156 + best_match_score = score;
160 + printerr(3, "CC '%s' is our current best match "
161 + "with mtime of %u\n",
162 + best_match_name, best_match_mtime);
167 + krb5_cc_cache_end_seq_get(context, cursor);
168 + krb5_free_context(context);
170 + *cc = best_match_name;
179 * Obtain credentials via a key in the keytab given
180 * a keytab handle and a gssd_k5_kt_princ structure.
181 @@ -1002,12 +1112,26 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirname)
182 printerr(2, "getting credentials for client with uid %u for "
183 "server %s\n", uid, servername);
184 memset(buf, 0, sizeof(buf));
185 - err = gssd_find_existing_krb5_ccache(uid, dirname, &d);
189 + if (use_kcmcache) {
191 + err = gssd_find_existing_krb5_ccache_kcm(uid, &s);
195 + snprintf(buf, sizeof(buf), "KCM:%s", s);
199 + err = gssd_find_existing_krb5_ccache(uid, dirname, &d);
203 - snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
205 + snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
211 printerr(2, "using %s as credentials cache for client with "
212 "uid %u for server %s\n", buf, uid, servername);