1 diff --git a/CHANGELOG b/CHANGELOG
2 index 85af0ad..fcfbe62 100644
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.
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 {
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
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;
41 @@ -376,7 +377,7 @@ int
42 sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
45 - krb5_principal tgs_princ, krb5_client_princ = ctxt->krb5_client_princ;
46 + krb5_principal tgs_princ, krb5_client_princ;
50 @@ -386,8 +387,8 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
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);
59 ret = krb5_init_context(&ctxt->krb5ctxt);
61 @@ -424,13 +425,12 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
62 "calling krb5_sname_to_principal using defaults");
64 ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
65 - "autofsclient", KRB5_NT_SRV_HST,
66 + default_client, KRB5_NT_SRV_HST,
70 "krb5_sname_to_principal failed for "
72 - ctxt->client_princ ? "" : "autofsclient", ret);
73 + "%s with error %d", default_client, ret);
77 @@ -441,11 +441,11 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
79 "krb5_unparse_name failed with error %d",
81 - goto out_cleanup_cc;
82 + goto out_cleanup_client_princ;
86 - "principal used for authentication: \"%s\"", tmp_name);
87 + "principal used for authentication: %s", tmp_name);
89 krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name);
91 @@ -461,14 +461,14 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
94 "krb5_build_principal failed with error %d", ret);
95 - goto out_cleanup_cc;
96 + goto out_cleanup_client_princ;
99 ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name);
101 error(logopt, "krb5_unparse_name failed with error %d",
103 - goto out_cleanup_cc;
104 + goto out_cleanup_client_princ;
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;
113 status = pthread_mutex_lock(&krb5cc_mutex);
116 @@ -503,7 +502,7 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
119 "krb5_cc_initialize failed with error %d", ret);
120 - goto out_cleanup_unparse;
121 + goto out_cleanup_creds;
124 /* and store credentials for that principal */
125 @@ -511,26 +510,34 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
128 "krb5_cc_store_cred failed with error %d", ret);
129 - goto out_cleanup_unparse;
130 + goto out_cleanup_creds;
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;
140 ctxt->kinit_successful = 1;
142 debug(logopt, "Kerberos authentication was successful!");
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);
151 -out_cleanup_unparse:
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);
161 status = pthread_mutex_lock(&krb5cc_mutex);
163 @@ -554,6 +561,152 @@ out_cleanup_cc:
167 + * Check a client given external credential cache.
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.
173 + * Upon failure, -1 is returned.
176 +sasl_do_kinit_ext_cc(unsigned logopt, struct lookup_context *ctxt)
178 + krb5_principal def_princ;
179 + krb5_principal krb5_client_princ;
180 + krb5_error_code ret;
181 + char *cc_princ, *client_princ;
183 + if (ctxt->kinit_done)
185 + ctxt->kinit_done = 1;
188 + "using external credential cache for auth: client principal %s",
189 + ctxt->client_princ ? ctxt->client_princ : default_client);
191 + ret = krb5_init_context(&ctxt->krb5ctxt);
193 + error(logopt, "krb5_init_context failed with %d", ret);
197 + ret = krb5_cc_resolve(ctxt->krb5ctxt, ctxt->client_cc, &ctxt->krb5_ccache);
199 + error(logopt, "krb5_cc_resolve failed with error %d",
201 + krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
202 + krb5_free_context(ctxt->krb5ctxt);
206 + ret = krb5_cc_get_principal(ctxt->krb5ctxt, ctxt->krb5_ccache, &def_princ);
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);
214 + ret = krb5_unparse_name(ctxt->krb5ctxt, def_princ, &cc_princ);
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);
223 + debug(logopt, "external credential cache default principal %s", cc_princ);
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
230 + if (ctxt->client_princ)
231 + client_princ = ctxt->client_princ;
234 + "calling krb5_sname_to_principal using defaults");
236 + ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
237 + default_client, KRB5_NT_SRV_HST,
238 + &krb5_client_princ);
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);
250 + ret = krb5_unparse_name(ctxt->krb5ctxt,
251 + krb5_client_princ, &client_princ);
254 + "krb5_unparse_name failed with error %d",
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);
264 + "principal used for authentication: %s", client_princ);
266 + krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
270 + * Check if the principal to be used matches the default principal in
271 + * the external cred cache.
273 + if (strcmp(cc_princ, client_princ)) {
275 + "configured client principal %s ",
276 + ctxt->client_princ);
278 + "external credential cache default principal %s",
281 + "cannot use credential cache, external "
282 + "default principal does not match configured "
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);
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);
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);
305 + ctxt->kinit_successful = 1;
307 + debug(logopt, "Kerberos authentication was successful!");
313 * Attempt to bind to the ldap server using a given authentication
314 * mechanism. ldap should be a properly initialzed ldap pointer.
316 @@ -570,7 +723,11 @@ sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const c
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);
324 + result = sasl_do_kinit(logopt, ctxt);
329 @@ -774,7 +931,7 @@ autofs_sasl_done(struct lookup_context *ctxt)
333 - if (--krb5cc_in_use)
334 + if (--krb5cc_in_use || ctxt->client_cc)
335 ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
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;
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".
354 (void)get_property(logopt, root, "clientprinc", &client_princ);
355 + (void)get_property(logopt, root, "credentialcache", &client_cc);
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)
361 ctxt->secret = secret;
362 ctxt->client_princ = client_princ;
363 + ctxt->client_cc = client_cc;
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
371 - "client principal: %s",
372 + "client principal: %s "
373 + "credential cache: %s",
374 user, secret ? "specified" : "unspecified",
376 + client_princ, client_cc);
380 @@ -1128,6 +1131,8 @@ static void free_context(struct lookup_context *ctxt)
382 if (ctxt->client_princ)
383 free(ctxt->client_princ);
384 + if (ctxt->client_cc)
385 + free(ctxt->client_cc);
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>.
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.
404 <autofs_ldap_sasl_conf