Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 130701790bf2d95e902edf16031ff596 > files > 232

autofs-5.0.1-0.rc2.164.el5_8.src.rpm

diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
index 5b5c475..d6a754d 100644
--- a/include/lookup_ldap.h
+++ b/include/lookup_ldap.h
@@ -67,10 +67,10 @@ struct lookup_context {
 	char        *user;
 	char        *secret;
 	char        *client_princ;
+	char        *client_cc;
 	int          kinit_done;
 	int          kinit_successful;
 #ifdef WITH_SASL
-	krb5_principal  krb5_client_princ;
 	krb5_context krb5ctxt;
 	krb5_ccache  krb5_ccache;
 	sasl_conn_t  *sasl_conn;
diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
index 303b7f2..f24f46b 100644
--- a/modules/cyrus-sasl.c
+++ b/modules/cyrus-sasl.c
@@ -72,6 +72,7 @@
  */
 static const char *krb5ccenv = "KRB5CCNAME";
 static const char *krb5ccval = "MEMORY:_autofstkt";
+static const char *default_client = "autofsclient";
 static pthread_mutex_t krb5cc_mutex = PTHREAD_MUTEX_INITIALIZER;
 static unsigned int krb5cc_in_use = 0;
 
@@ -376,7 +377,7 @@ int
 sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 {
 	krb5_error_code ret;
-	krb5_principal tgs_princ, krb5_client_princ = ctxt->krb5_client_princ;
+	krb5_principal tgs_princ, krb5_client_princ;
 	krb5_creds my_creds;
 	char *tgs_name;
 	int status;
@@ -386,8 +387,8 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 	ctxt->kinit_done = 1;
 
 	debug(logopt,
-	      "initializing kerberos ticket: client principal %s ",
-	      ctxt->client_princ ? ctxt->client_princ : "autofsclient");
+	      "initializing kerberos ticket: client principal %s",
+	      ctxt->client_princ ? ctxt->client_princ : default_client);
 
 	ret = krb5_init_context(&ctxt->krb5ctxt);
 	if (ret) {
@@ -424,13 +425,12 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 		      "calling krb5_sname_to_principal using defaults");
 
 		ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
-					"autofsclient", KRB5_NT_SRV_HST, 
+					default_client, KRB5_NT_SRV_HST, 
 					&krb5_client_princ);
 		if (ret) {
 			error(logopt,
 			      "krb5_sname_to_principal failed for "
-			      "%s with error %d",
-			      ctxt->client_princ ? "" : "autofsclient", ret);
+			      "%s with error %d", default_client, ret);
 			goto out_cleanup_cc;
 		}
 
@@ -441,11 +441,11 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 			debug(logopt,
 			      "krb5_unparse_name failed with error %d",
 			      ret);
-			goto out_cleanup_cc;
+			goto out_cleanup_client_princ;
 		}
 
 		debug(logopt,
-		      "principal used for authentication: \"%s\"", tmp_name);
+		      "principal used for authentication: %s", tmp_name);
 
 		krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name);
 	}
@@ -461,14 +461,14 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 	if (ret) {
 		error(logopt,
 		      "krb5_build_principal failed with error %d", ret);
-		goto out_cleanup_cc;
+		goto out_cleanup_client_princ;
 	}
 
 	ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name);
 	if (ret) {
 		error(logopt, "krb5_unparse_name failed with error %d",
 		      ret);
-		goto out_cleanup_cc;
+		goto out_cleanup_client_princ;
 	}
 
 	debug(logopt, "Using tgs name %s", tgs_name);
@@ -486,7 +486,6 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 		goto out_cleanup_unparse;
 	}
 
-
 	status = pthread_mutex_lock(&krb5cc_mutex);
 	if (status)
 		fatal(status);
@@ -503,7 +502,7 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 	if (ret) {
 		error(logopt,
 		      "krb5_cc_initialize failed with error %d", ret);
-		goto out_cleanup_unparse;
+		goto out_cleanup_creds;
 	}
 
 	/* and store credentials for that principal */
@@ -511,26 +510,34 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
 	if (ret) {
 		error(logopt,
 		      "krb5_cc_store_cred failed with error %d", ret);
-		goto out_cleanup_unparse;
+		goto out_cleanup_creds;
 	}
 
 	/* finally, set the environment variable to point to our
 	 * credentials cache */
 	if (setenv(krb5ccenv, krb5ccval, 1) != 0) {
 		error(logopt, "setenv failed with %d", errno);
-		goto out_cleanup_unparse;
+		goto out_cleanup_creds;
 	}
 	ctxt->kinit_successful = 1;
 
 	debug(logopt, "Kerberos authentication was successful!");
 
 	krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
+	krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
+	krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
+	krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
 
 	return 0;
 
-out_cleanup_unparse:
+out_cleanup_creds:
 	krb5cc_in_use--;
+	krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
+out_cleanup_unparse:
+	krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
 	krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
+out_cleanup_client_princ:
+	krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
 out_cleanup_cc:
 	status = pthread_mutex_lock(&krb5cc_mutex);
 	if (status)
@@ -554,6 +561,152 @@ out_cleanup_cc:
 }
 
 /*
+ *  Check a client given external credential cache.
+ *
+ *  Returns 0 upon success.  ctxt->kinit_done and ctxt->kinit_successful
+ *  are set for cleanup purposes.  The krb5 context and ccache entries in
+ *  the lookup_context are also filled in.
+ *
+ *  Upon failure, -1 is returned.
+ */
+int
+sasl_do_kinit_ext_cc(unsigned logopt, struct lookup_context *ctxt)
+{
+	krb5_principal def_princ;
+	krb5_principal krb5_client_princ;
+	krb5_error_code ret;
+	char *cc_princ, *client_princ;
+
+	if (ctxt->kinit_done)
+		return 0;
+	ctxt->kinit_done = 1;
+
+	debug(logopt,
+	      "using external credential cache for auth: client principal %s",
+	      ctxt->client_princ ? ctxt->client_princ : default_client);
+
+	ret = krb5_init_context(&ctxt->krb5ctxt);
+	if (ret) {
+		error(logopt, "krb5_init_context failed with %d", ret);
+		return -1;
+	}
+
+	ret = krb5_cc_resolve(ctxt->krb5ctxt, ctxt->client_cc, &ctxt->krb5_ccache);
+	if (ret) {
+		error(logopt, "krb5_cc_resolve failed with error %d",
+		      ret);
+		krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+		krb5_free_context(ctxt->krb5ctxt);
+		return -1;
+	}
+
+	ret = krb5_cc_get_principal(ctxt->krb5ctxt, ctxt->krb5_ccache, &def_princ);
+	if (ret) {
+		error(logopt, "krb5_cc_get_principal failed with error %d", ret);
+		krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+		krb5_free_context(ctxt->krb5ctxt);
+		return -1;
+	}
+
+	ret = krb5_unparse_name(ctxt->krb5ctxt, def_princ, &cc_princ);
+	if (ret) {
+		error(logopt, "krb5_unparse_name failed with error %d", ret);
+		krb5_free_principal(ctxt->krb5ctxt, def_princ);
+		krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+		krb5_free_context(ctxt->krb5ctxt);
+		return -1;
+	}
+
+	debug(logopt, "external credential cache default principal %s", cc_princ);
+
+	/*
+	 * If the principal isn't set in the config construct the default
+	 * so we can check against the default principal of the external
+	 * cred cache.
+	 */
+	if (ctxt->client_princ)
+		client_princ = ctxt->client_princ;
+	else {
+		debug(logopt,
+		      "calling krb5_sname_to_principal using defaults");
+
+		ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
+					default_client, KRB5_NT_SRV_HST, 
+					&krb5_client_princ);
+		if (ret) {
+			error(logopt,
+			      "krb5_sname_to_principal failed for "
+			      "%s with error %d", default_client, ret);
+			krb5_free_principal(ctxt->krb5ctxt, def_princ);
+			krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+			krb5_free_context(ctxt->krb5ctxt);
+			return -1;
+		}
+
+
+		ret = krb5_unparse_name(ctxt->krb5ctxt,
+					krb5_client_princ, &client_princ);
+		if (ret) {
+			debug(logopt,
+			      "krb5_unparse_name failed with error %d",
+			      ret);
+			krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
+			krb5_free_principal(ctxt->krb5ctxt, def_princ);
+			krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+			krb5_free_context(ctxt->krb5ctxt);
+			return -1;
+		}
+
+		debug(logopt,
+		      "principal used for authentication: %s", client_princ);
+
+		krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
+	}
+
+	/*
+	 * Check if the principal to be used matches the default principal in
+	 * the external cred cache.
+	 */
+	if (strcmp(cc_princ, client_princ)) {
+		error(logopt,
+		      "configured client principal %s ",
+		      ctxt->client_princ);
+		error(logopt,
+		      "external credential cache default principal %s",
+		      cc_princ);
+		error(logopt, 
+		      "cannot use credential cache, external "
+		      "default principal does not match configured "
+		      "principal");
+		if (!ctxt->client_princ)
+			krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
+		krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
+		krb5_free_principal(ctxt->krb5ctxt, def_princ);
+		krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+		krb5_free_context(ctxt->krb5ctxt);
+		return -1;
+	}
+
+	if (!ctxt->client_princ)
+		krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
+	krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
+	krb5_free_principal(ctxt->krb5ctxt, def_princ);
+
+	/* Set the environment variable to point to the external cred cache */
+	if (setenv(krb5ccenv, ctxt->client_cc, 1) != 0) {
+		error(logopt, "setenv failed with %d", errno);
+		krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+		krb5_free_context(ctxt->krb5ctxt);
+		return -1;
+	}
+	ctxt->kinit_successful = 1;
+
+	debug(logopt, "Kerberos authentication was successful!");
+
+	return 0;
+}
+
+/*
  *  Attempt to bind to the ldap server using a given authentication
  *  mechanism.  ldap should be a properly initialzed ldap pointer.
  *
@@ -570,7 +723,11 @@ sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const c
 	int result;
 
 	if (!strncmp(mech, "GSSAPI", 6)) {
-		if (sasl_do_kinit(logopt, ctxt) != 0)
+		if (ctxt->client_cc)
+			result = sasl_do_kinit_ext_cc(logopt, ctxt);
+		else
+			result = sasl_do_kinit(logopt, ctxt);
+		if (result != 0)
 			return NULL;
 	}
 
@@ -774,7 +931,7 @@ autofs_sasl_done(struct lookup_context *ctxt)
 		if (status)
 			fatal(status);
 
-		if (--krb5cc_in_use)
+		if (--krb5cc_in_use || ctxt->client_cc)
 			ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
 		else 
 			ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 93f0477..13fbff7 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -651,7 +651,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
 	xmlNodePtr   root = NULL;
 	char         *authrequired, *auth_conf, *authtype;
 	char         *user = NULL, *secret = NULL;
-	char         *client_princ = NULL;
+	char         *client_princ = NULL, *client_cc = NULL;
 	char	     *usetls, *tlsrequired;
 
 	authtype = user = secret = NULL;
@@ -840,6 +840,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
 	 * client.  The default is "autofsclient/hostname@REALM".
 	 */
 	(void)get_property(logopt, root, "clientprinc", &client_princ);
+	(void)get_property(logopt, root, "credentialcache", &client_cc);
 
 	ctxt->auth_conf = auth_conf;
 	ctxt->use_tls = use_tls;
@@ -851,6 +852,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
 	ctxt->user = user;
 	ctxt->secret = secret;
 	ctxt->client_princ = client_princ;
+	ctxt->client_cc = client_cc;
 
 	debug(logopt, MODPREFIX
 	      "ldap authentication configured with the following options:");
@@ -863,9 +865,10 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
 	debug(logopt, MODPREFIX
 	      "user: %s, "
 	      "secret: %s, "
-	      "client principal: %s",
+	      "client principal: %s "
+	      "credential cache: %s",
 	      user, secret ? "specified" : "unspecified",
-	      client_princ);
+	      client_princ, client_cc);
 
 out:
 	xmlFreeDoc(doc);
@@ -1128,6 +1131,8 @@ static void free_context(struct lookup_context *ctxt)
 		free(ctxt->secret);
 	if (ctxt->client_princ)
 		free(ctxt->client_princ);
+	if (ctxt->client_cc)
+		free(ctxt->client_cc);
 	if (ctxt->mapname)
 		free(ctxt->mapname);
 	if (ctxt->qdn)
diff --git a/samples/autofs_ldap_auth.conf b/samples/autofs_ldap_auth.conf
index e10d1ea..a1f60c0 100644
--- a/samples/autofs_ldap_auth.conf
+++ b/samples/autofs_ldap_auth.conf
@@ -56,6 +56,11 @@ clientprinc  -  When using GSSAPI authentication, this attribute is
 	    consulted to determine the principal name to use when
 	    authenticating to the directory server.  By default, this will
 	    be set to "autofsclient/<fqdn>@<REALM>.
+
+credentialcache - When using GSSAPI authentication, this attribute
+	    can be used to specify an externally configured credential
+	    cache that is used during authentication. By default, autofs
+	    will setup a memory based credential cache.
 -->
 
 <autofs_ldap_sasl_conf