]>
Commit | Line | Data |
---|---|---|
f5eebee2 JR |
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]; | |
8 | int use_memcache = 0; | |
9 | +int use_kcmcache = 0; | |
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) | |
14 | static void | |
15 | usage(char *progname) | |
16 | { | |
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", | |
19 | progname); | |
20 | exit(1); | |
21 | } | |
22 | @@ -102,7 +103,7 @@ main(int argc, char *argv[]) | |
23 | char *progname; | |
24 | ||
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) { | |
28 | switch (opt) { | |
29 | case 'f': | |
30 | fg = 1; | |
31 | @@ -113,6 +114,9 @@ main(int argc, char *argv[]) | |
32 | case 'M': | |
33 | use_memcache = 1; | |
34 | break; | |
35 | + case 'K': | |
36 | + use_kcmcache = 1; | |
37 | + break; | |
38 | case 'n': | |
39 | root_uses_machine_creds = 0; | |
40 | break; | |
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 | |
57 | @@ -125,6 +125,7 @@ | |
58 | #include "err_util.h" | |
59 | #include "gss_util.h" | |
60 | #include "krb5_util.h" | |
61 | +#include "xcommon.h" | |
62 | ||
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) | |
66 | return err; | |
67 | } | |
68 | ||
69 | +#ifdef HAVE_HEIMDAL | |
70 | +static int | |
71 | +gssd_find_existing_krb5_ccache_kcm(uid_t uid, char **cc) | |
72 | +{ | |
73 | + krb5_context context; | |
74 | + krb5_cc_cache_cursor cursor; | |
75 | + krb5_ccache id; | |
76 | + char *best_match_name = NULL; | |
77 | + krb5_timestamp best_match_mtime, mtime; | |
78 | + char *ccname; | |
79 | + uid_t ccuid; | |
80 | + int i; | |
81 | + int found = 0; | |
82 | + char buf[1030]; | |
83 | + char *princname = NULL; | |
84 | + char *realm = NULL; | |
85 | + int score, best_match_score = 0, err = -EACCES; | |
86 | + | |
87 | + *cc = NULL; | |
88 | + if (krb5_init_context(&context)) | |
89 | + return err; | |
90 | + | |
91 | + if (krb5_cc_cache_get_first(context, "KCM", &cursor)) | |
92 | + return err; | |
93 | + | |
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"); | |
98 | + continue; | |
99 | + } | |
100 | + for (i=0,ccuid=0; ccname[i] && isdigit(ccname[i]); i++) { | |
101 | + ccuid = ccuid*10 + (ccname[i] - '0'); | |
102 | + } | |
103 | + if (i == 0) { | |
104 | + printerr(3, "CC '%s' not available due to" | |
105 | + " non-standard name\n", | |
106 | + ccname); | |
107 | + continue; | |
108 | + } | |
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); | |
113 | + continue; | |
114 | + } | |
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", | |
118 | + ccname); | |
119 | + err = -EKEYEXPIRED; | |
120 | + continue; | |
121 | + } | |
122 | + krb5_cc_last_change_time(context, id, &mtime); | |
123 | + | |
124 | + score = 0; | |
125 | + if (preferred_realm && strcmp(realm, preferred_realm) == 0) | |
126 | + score++; | |
127 | + | |
128 | + printerr(3, "CC '%s'(%s@%s) passed all checks and" | |
129 | + " has mtime of %u\n", | |
130 | + ccname, princname, realm, mtime); | |
131 | + /* | |
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 | |
135 | + */ | |
136 | + if (!found) { | |
137 | + best_match_name = ccname; | |
138 | + best_match_mtime = mtime; | |
139 | + best_match_score = score; | |
140 | + found++; | |
141 | + } else { | |
142 | + /* | |
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. | |
149 | + */ | |
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; | |
157 | + } else { | |
158 | + free(ccname); | |
159 | + } | |
160 | + printerr(3, "CC '%s' is our current best match " | |
161 | + "with mtime of %u\n", | |
162 | + best_match_name, best_match_mtime); | |
163 | + } | |
164 | + free(princname); | |
165 | + free(realm); | |
166 | + } | |
167 | + krb5_cc_cache_end_seq_get(context, cursor); | |
168 | + krb5_free_context(context); | |
169 | + if (found) { | |
170 | + *cc = best_match_name; | |
171 | + return 0; | |
172 | + } | |
173 | + | |
174 | + return err; | |
175 | +} | |
176 | +#endif | |
177 | + | |
178 | /* | |
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); | |
186 | - if (err) | |
187 | - return err; | |
188 | +#ifdef HAVE_HEIMDAL | |
189 | + if (use_kcmcache) { | |
190 | + char *s; | |
191 | + err = gssd_find_existing_krb5_ccache_kcm(uid, &s); | |
192 | + if (err) | |
193 | + return err; | |
194 | + | |
195 | + snprintf(buf, sizeof(buf), "KCM:%s", s); | |
196 | + free(s); | |
197 | + } else { | |
198 | +#endif | |
199 | + err = gssd_find_existing_krb5_ccache(uid, dirname, &d); | |
200 | + if (err) | |
201 | + return err; | |
202 | ||
203 | - snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name); | |
204 | - free(d); | |
205 | + snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name); | |
206 | + free(d); | |
207 | +#ifdef HAVE_HEIMDAL | |
208 | + } | |
209 | +#endif | |
210 | ||
211 | printerr(2, "using %s as credentials cache for client with " | |
212 | "uid %u for server %s\n", buf, uid, servername); |