]>
Commit | Line | Data |
---|---|---|
3d551623 PG |
1 | diff --git a/CHANGELOG b/CHANGELOG |
2 | index 85af0ad..fcfbe62 100644 | |
3 | --- a/CHANGELOG | |
4 | +++ b/CHANGELOG | |
5 | @@ -50,6 +50,7 @@ | |
6 | - fix off-by-one error for lookup of map keys exactly 255 characters long. | |
7 | - improve handling of server not available. | |
8 | - fix LDAP_URI server selection. | |
9 | +- add authentication option for using an external credential cache. | |
10 | ||
11 | 18/06/2007 autofs-5.0.2 | |
12 | ----------------------- | |
13 | diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h | |
14 | index 5b5c475..d6a754d 100644 | |
15 | --- a/include/lookup_ldap.h | |
16 | +++ b/include/lookup_ldap.h | |
17 | @@ -67,10 +67,10 @@ struct lookup_context { | |
18 | char *user; | |
19 | char *secret; | |
20 | char *client_princ; | |
21 | + char *client_cc; | |
22 | int kinit_done; | |
23 | int kinit_successful; | |
24 | #ifdef WITH_SASL | |
25 | - krb5_principal krb5_client_princ; | |
26 | krb5_context krb5ctxt; | |
27 | krb5_ccache krb5_ccache; | |
28 | sasl_conn_t *sasl_conn; | |
29 | diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c | |
30 | index 303b7f2..f24f46b 100644 | |
31 | --- a/modules/cyrus-sasl.c | |
32 | +++ b/modules/cyrus-sasl.c | |
33 | @@ -72,6 +72,7 @@ | |
34 | */ | |
35 | static const char *krb5ccenv = "KRB5CCNAME"; | |
36 | static const char *krb5ccval = "MEMORY:_autofstkt"; | |
37 | +static const char *default_client = "autofsclient"; | |
38 | static pthread_mutex_t krb5cc_mutex = PTHREAD_MUTEX_INITIALIZER; | |
39 | static unsigned int krb5cc_in_use = 0; | |
40 | ||
41 | @@ -376,7 +377,7 @@ int | |
42 | sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
43 | { | |
44 | krb5_error_code ret; | |
45 | - krb5_principal tgs_princ, krb5_client_princ = ctxt->krb5_client_princ; | |
46 | + krb5_principal tgs_princ, krb5_client_princ; | |
47 | krb5_creds my_creds; | |
48 | char *tgs_name; | |
49 | int status; | |
50 | @@ -386,8 +387,8 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
51 | ctxt->kinit_done = 1; | |
52 | ||
53 | debug(logopt, | |
54 | - "initializing kerberos ticket: client principal %s ", | |
55 | - ctxt->client_princ ? ctxt->client_princ : "autofsclient"); | |
56 | + "initializing kerberos ticket: client principal %s", | |
57 | + ctxt->client_princ ? ctxt->client_princ : default_client); | |
58 | ||
59 | ret = krb5_init_context(&ctxt->krb5ctxt); | |
60 | if (ret) { | |
61 | @@ -424,13 +425,12 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
62 | "calling krb5_sname_to_principal using defaults"); | |
63 | ||
64 | ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL, | |
65 | - "autofsclient", KRB5_NT_SRV_HST, | |
66 | + default_client, KRB5_NT_SRV_HST, | |
67 | &krb5_client_princ); | |
68 | if (ret) { | |
69 | error(logopt, | |
70 | "krb5_sname_to_principal failed for " | |
71 | - "%s with error %d", | |
72 | - ctxt->client_princ ? "" : "autofsclient", ret); | |
73 | + "%s with error %d", default_client, ret); | |
74 | goto out_cleanup_cc; | |
75 | } | |
76 | ||
77 | @@ -441,11 +441,11 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
78 | debug(logopt, | |
79 | "krb5_unparse_name failed with error %d", | |
80 | ret); | |
81 | - goto out_cleanup_cc; | |
82 | + goto out_cleanup_client_princ; | |
83 | } | |
84 | ||
85 | debug(logopt, | |
86 | - "principal used for authentication: \"%s\"", tmp_name); | |
87 | + "principal used for authentication: %s", tmp_name); | |
88 | ||
89 | krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name); | |
90 | } | |
91 | @@ -461,14 +461,14 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
92 | if (ret) { | |
93 | error(logopt, | |
94 | "krb5_build_principal failed with error %d", ret); | |
95 | - goto out_cleanup_cc; | |
96 | + goto out_cleanup_client_princ; | |
97 | } | |
98 | ||
99 | ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name); | |
100 | if (ret) { | |
101 | error(logopt, "krb5_unparse_name failed with error %d", | |
102 | ret); | |
103 | - goto out_cleanup_cc; | |
104 | + goto out_cleanup_client_princ; | |
105 | } | |
106 | ||
107 | debug(logopt, "Using tgs name %s", tgs_name); | |
108 | @@ -486,7 +486,6 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
109 | goto out_cleanup_unparse; | |
110 | } | |
111 | ||
112 | - | |
113 | status = pthread_mutex_lock(&krb5cc_mutex); | |
114 | if (status) | |
115 | fatal(status); | |
116 | @@ -503,7 +502,7 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
117 | if (ret) { | |
118 | error(logopt, | |
119 | "krb5_cc_initialize failed with error %d", ret); | |
120 | - goto out_cleanup_unparse; | |
121 | + goto out_cleanup_creds; | |
122 | } | |
123 | ||
124 | /* and store credentials for that principal */ | |
125 | @@ -511,26 +510,34 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt) | |
126 | if (ret) { | |
127 | error(logopt, | |
128 | "krb5_cc_store_cred failed with error %d", ret); | |
129 | - goto out_cleanup_unparse; | |
130 | + goto out_cleanup_creds; | |
131 | } | |
132 | ||
133 | /* finally, set the environment variable to point to our | |
134 | * credentials cache */ | |
135 | if (setenv(krb5ccenv, krb5ccval, 1) != 0) { | |
136 | error(logopt, "setenv failed with %d", errno); | |
137 | - goto out_cleanup_unparse; | |
138 | + goto out_cleanup_creds; | |
139 | } | |
140 | ctxt->kinit_successful = 1; | |
141 | ||
142 | debug(logopt, "Kerberos authentication was successful!"); | |
143 | ||
144 | krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name); | |
145 | + krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds); | |
146 | + krb5_free_principal(ctxt->krb5ctxt, tgs_princ); | |
147 | + krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ); | |
148 | ||
149 | return 0; | |
150 | ||
151 | -out_cleanup_unparse: | |
152 | +out_cleanup_creds: | |
153 | krb5cc_in_use--; | |
154 | + krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds); | |
155 | +out_cleanup_unparse: | |
156 | + krb5_free_principal(ctxt->krb5ctxt, tgs_princ); | |
157 | krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name); | |
158 | +out_cleanup_client_princ: | |
159 | + krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ); | |
160 | out_cleanup_cc: | |
161 | status = pthread_mutex_lock(&krb5cc_mutex); | |
162 | if (status) | |
163 | @@ -554,6 +561,152 @@ out_cleanup_cc: | |
164 | } | |
165 | ||
166 | /* | |
167 | + * Check a client given external credential cache. | |
168 | + * | |
169 | + * Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful | |
170 | + * are set for cleanup purposes. The krb5 context and ccache entries in | |
171 | + * the lookup_context are also filled in. | |
172 | + * | |
173 | + * Upon failure, -1 is returned. | |
174 | + */ | |
175 | +int | |
176 | +sasl_do_kinit_ext_cc(unsigned logopt, struct lookup_context *ctxt) | |
177 | +{ | |
178 | + krb5_principal def_princ; | |
179 | + krb5_principal krb5_client_princ; | |
180 | + krb5_error_code ret; | |
181 | + char *cc_princ, *client_princ; | |
182 | + | |
183 | + if (ctxt->kinit_done) | |
184 | + return 0; | |
185 | + ctxt->kinit_done = 1; | |
186 | + | |
187 | + debug(logopt, | |
188 | + "using external credential cache for auth: client principal %s", | |
189 | + ctxt->client_princ ? ctxt->client_princ : default_client); | |
190 | + | |
191 | + ret = krb5_init_context(&ctxt->krb5ctxt); | |
192 | + if (ret) { | |
193 | + error(logopt, "krb5_init_context failed with %d", ret); | |
194 | + return -1; | |
195 | + } | |
196 | + | |
197 | + ret = krb5_cc_resolve(ctxt->krb5ctxt, ctxt->client_cc, &ctxt->krb5_ccache); | |
198 | + if (ret) { | |
199 | + error(logopt, "krb5_cc_resolve failed with error %d", | |
200 | + ret); | |
201 | + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
202 | + krb5_free_context(ctxt->krb5ctxt); | |
203 | + return -1; | |
204 | + } | |
205 | + | |
206 | + ret = krb5_cc_get_principal(ctxt->krb5ctxt, ctxt->krb5_ccache, &def_princ); | |
207 | + if (ret) { | |
208 | + error(logopt, "krb5_cc_get_principal failed with error %d", ret); | |
209 | + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
210 | + krb5_free_context(ctxt->krb5ctxt); | |
211 | + return -1; | |
212 | + } | |
213 | + | |
214 | + ret = krb5_unparse_name(ctxt->krb5ctxt, def_princ, &cc_princ); | |
215 | + if (ret) { | |
216 | + error(logopt, "krb5_unparse_name failed with error %d", ret); | |
217 | + krb5_free_principal(ctxt->krb5ctxt, def_princ); | |
218 | + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
219 | + krb5_free_context(ctxt->krb5ctxt); | |
220 | + return -1; | |
221 | + } | |
222 | + | |
223 | + debug(logopt, "external credential cache default principal %s", cc_princ); | |
224 | + | |
225 | + /* | |
226 | + * If the principal isn't set in the config construct the default | |
227 | + * so we can check against the default principal of the external | |
228 | + * cred cache. | |
229 | + */ | |
230 | + if (ctxt->client_princ) | |
231 | + client_princ = ctxt->client_princ; | |
232 | + else { | |
233 | + debug(logopt, | |
234 | + "calling krb5_sname_to_principal using defaults"); | |
235 | + | |
236 | + ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL, | |
237 | + default_client, KRB5_NT_SRV_HST, | |
238 | + &krb5_client_princ); | |
239 | + if (ret) { | |
240 | + error(logopt, | |
241 | + "krb5_sname_to_principal failed for " | |
242 | + "%s with error %d", default_client, ret); | |
243 | + krb5_free_principal(ctxt->krb5ctxt, def_princ); | |
244 | + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
245 | + krb5_free_context(ctxt->krb5ctxt); | |
246 | + return -1; | |
247 | + } | |
248 | + | |
249 | + | |
250 | + ret = krb5_unparse_name(ctxt->krb5ctxt, | |
251 | + krb5_client_princ, &client_princ); | |
252 | + if (ret) { | |
253 | + debug(logopt, | |
254 | + "krb5_unparse_name failed with error %d", | |
255 | + ret); | |
256 | + krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ); | |
257 | + krb5_free_principal(ctxt->krb5ctxt, def_princ); | |
258 | + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
259 | + krb5_free_context(ctxt->krb5ctxt); | |
260 | + return -1; | |
261 | + } | |
262 | + | |
263 | + debug(logopt, | |
264 | + "principal used for authentication: %s", client_princ); | |
265 | + | |
266 | + krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ); | |
267 | + } | |
268 | + | |
269 | + /* | |
270 | + * Check if the principal to be used matches the default principal in | |
271 | + * the external cred cache. | |
272 | + */ | |
273 | + if (strcmp(cc_princ, client_princ)) { | |
274 | + error(logopt, | |
275 | + "configured client principal %s ", | |
276 | + ctxt->client_princ); | |
277 | + error(logopt, | |
278 | + "external credential cache default principal %s", | |
279 | + cc_princ); | |
280 | + error(logopt, | |
281 | + "cannot use credential cache, external " | |
282 | + "default principal does not match configured " | |
283 | + "principal"); | |
284 | + if (!ctxt->client_princ) | |
285 | + krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ); | |
286 | + krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ); | |
287 | + krb5_free_principal(ctxt->krb5ctxt, def_princ); | |
288 | + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
289 | + krb5_free_context(ctxt->krb5ctxt); | |
290 | + return -1; | |
291 | + } | |
292 | + | |
293 | + if (!ctxt->client_princ) | |
294 | + krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ); | |
295 | + krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ); | |
296 | + krb5_free_principal(ctxt->krb5ctxt, def_princ); | |
297 | + | |
298 | + /* Set the environment variable to point to the external cred cache */ | |
299 | + if (setenv(krb5ccenv, ctxt->client_cc, 1) != 0) { | |
300 | + error(logopt, "setenv failed with %d", errno); | |
301 | + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
302 | + krb5_free_context(ctxt->krb5ctxt); | |
303 | + return -1; | |
304 | + } | |
305 | + ctxt->kinit_successful = 1; | |
306 | + | |
307 | + debug(logopt, "Kerberos authentication was successful!"); | |
308 | + | |
309 | + return 0; | |
310 | +} | |
311 | + | |
312 | +/* | |
313 | * Attempt to bind to the ldap server using a given authentication | |
314 | * mechanism. ldap should be a properly initialzed ldap pointer. | |
315 | * | |
316 | @@ -570,7 +723,11 @@ sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const c | |
317 | int result; | |
318 | ||
319 | if (!strncmp(mech, "GSSAPI", 6)) { | |
320 | - if (sasl_do_kinit(logopt, ctxt) != 0) | |
321 | + if (ctxt->client_cc) | |
322 | + result = sasl_do_kinit_ext_cc(logopt, ctxt); | |
323 | + else | |
324 | + result = sasl_do_kinit(logopt, ctxt); | |
325 | + if (result != 0) | |
326 | return NULL; | |
327 | } | |
328 | ||
329 | @@ -774,7 +931,7 @@ autofs_sasl_done(struct lookup_context *ctxt) | |
330 | if (status) | |
331 | fatal(status); | |
332 | ||
333 | - if (--krb5cc_in_use) | |
334 | + if (--krb5cc_in_use || ctxt->client_cc) | |
335 | ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
336 | else | |
337 | ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache); | |
338 | diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c | |
339 | index 93f0477..13fbff7 100644 | |
340 | --- a/modules/lookup_ldap.c | |
341 | +++ b/modules/lookup_ldap.c | |
342 | @@ -651,7 +651,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) | |
343 | xmlNodePtr root = NULL; | |
344 | char *authrequired, *auth_conf, *authtype; | |
345 | char *user = NULL, *secret = NULL; | |
346 | - char *client_princ = NULL; | |
347 | + char *client_princ = NULL, *client_cc = NULL; | |
348 | char *usetls, *tlsrequired; | |
349 | ||
350 | authtype = user = secret = NULL; | |
351 | @@ -840,6 +840,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) | |
352 | * client. The default is "autofsclient/hostname@REALM". | |
353 | */ | |
354 | (void)get_property(logopt, root, "clientprinc", &client_princ); | |
355 | + (void)get_property(logopt, root, "credentialcache", &client_cc); | |
356 | ||
357 | ctxt->auth_conf = auth_conf; | |
358 | ctxt->use_tls = use_tls; | |
359 | @@ -851,6 +852,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) | |
360 | ctxt->user = user; | |
361 | ctxt->secret = secret; | |
362 | ctxt->client_princ = client_princ; | |
363 | + ctxt->client_cc = client_cc; | |
364 | ||
365 | debug(logopt, MODPREFIX | |
366 | "ldap authentication configured with the following options:"); | |
367 | @@ -863,9 +865,10 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) | |
368 | debug(logopt, MODPREFIX | |
369 | "user: %s, " | |
370 | "secret: %s, " | |
371 | - "client principal: %s", | |
372 | + "client principal: %s " | |
373 | + "credential cache: %s", | |
374 | user, secret ? "specified" : "unspecified", | |
375 | - client_princ); | |
376 | + client_princ, client_cc); | |
377 | ||
378 | out: | |
379 | xmlFreeDoc(doc); | |
380 | @@ -1128,6 +1131,8 @@ static void free_context(struct lookup_context *ctxt) | |
381 | free(ctxt->secret); | |
382 | if (ctxt->client_princ) | |
383 | free(ctxt->client_princ); | |
384 | + if (ctxt->client_cc) | |
385 | + free(ctxt->client_cc); | |
386 | if (ctxt->mapname) | |
387 | free(ctxt->mapname); | |
388 | if (ctxt->qdn) | |
389 | diff --git a/samples/autofs_ldap_auth.conf b/samples/autofs_ldap_auth.conf | |
390 | index e10d1ea..a1f60c0 100644 | |
391 | --- a/samples/autofs_ldap_auth.conf | |
392 | +++ b/samples/autofs_ldap_auth.conf | |
393 | @@ -56,6 +56,11 @@ clientprinc - When using GSSAPI authentication, this attribute is | |
394 | consulted to determine the principal name to use when | |
395 | authenticating to the directory server. By default, this will | |
396 | be set to "autofsclient/<fqdn>@<REALM>. | |
397 | + | |
398 | +credentialcache - When using GSSAPI authentication, this attribute | |
399 | + can be used to specify an externally configured credential | |
400 | + cache that is used during authentication. By default, autofs | |
401 | + will setup a memory based credential cache. | |
402 | --> | |
403 | ||
404 | <autofs_ldap_sasl_conf |