rpms/autofs/devel autofs-5.0.0_beta6-auth-kerberos-update.patch, NONE, 1.1 autofs-5.0.0_beta6-check-return.patch, NONE, 1.1 autofs-5.0.0_beta6-default-auth-config.patch, NONE, 1.1 autofs-5.0.0_beta6-gssapi-segfault-exit.patch, NONE, 1.1 autofs.spec, 1.116, 1.117
fedora-cvs-commits at redhat.com
fedora-cvs-commits at redhat.com
Mon Jul 3 05:38:31 UTC 2006
Author: ikent
Update of /cvs/dist/rpms/autofs/devel
In directory cvs.devel.redhat.com:/tmp/cvs-serv26633
Modified Files:
autofs.spec
Added Files:
autofs-5.0.0_beta6-auth-kerberos-update.patch
autofs-5.0.0_beta6-check-return.patch
autofs-5.0.0_beta6-default-auth-config.patch
autofs-5.0.0_beta6-gssapi-segfault-exit.patch
Log Message:
* Mon Jul 3 2006 Ian Kent <ikent at redhat.com> - 5.0.0_beta6-2
- merge LDAP authentication update for GSSAPI (Jeff Moyer).
- update default auth config to add options documenetation (Jeff Moyer).
- workaround segfaults at exit after using GSSAPI library.
- fix not checking return in init_ldap_connection (jeff Moyer).
autofs-5.0.0_beta6-auth-kerberos-update.patch:
CHANGELOG | 4
include/lookup_ldap.h | 18 +-
modules/cyrus-sasl.c | 356 +++++++++++++++++++++++++++++++++++++++++++++-----
modules/lookup_ldap.c | 156 ++++++++++++---------
4 files changed, 430 insertions(+), 104 deletions(-)
--- NEW FILE autofs-5.0.0_beta6-auth-kerberos-update.patch ---
diff --git a/CHANGELOG b/CHANGELOG
index fb55ec3..df66913 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+?/7/2006 autofs-5.0.0
+---------------------
+- merge LDAP authentication update for GSSAPI (Jeff Moyer).
+
29/6/2006 autofs-5.0.0_beta6
----------------------------
- lookup_init cleanup and fix missed memory leak.
diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
index db6389c..ebff193 100644
--- a/include/lookup_ldap.h
+++ b/include/lookup_ldap.h
@@ -34,6 +34,14 @@ struct lookup_context {
char *sasl_mech;
char *user;
char *secret;
+ char *client_princ;
+ int kinit_done;
+ int kinit_successful;
+ krb5_principal krb5_client_princ;
+ krb5_context krb5ctxt;
+ krb5_ccache krb5_ccache;
+ sasl_conn_t *sasl_conn;
+ /* keytab file name needs to be added */
struct parse_mod *parse;
};
@@ -48,14 +56,14 @@ #define LDAP_TLS_INIT 1
#define LDAP_TLS_RELEASE 2
/* lookup_ldap.c */
-LDAP *ldap_connection_init(struct lookup_context *ctxt);
-int ldap_unbind_connection(LDAP *ldap, struct lookup_context *ctxt);
+LDAP *init_ldap_connection(struct lookup_context *ctxt);
+int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt);
int authtype_requires_creds(const char *authtype);
/* cyrus-sasl.c */
-int sasl_init(char *id, char *secret);
-int sasl_choose_mech(struct lookup_context *ctxt, char **mechanism);
-sasl_conn_t *sasl_bind_mech(LDAP *ldap, const char *mech);
+int autofs_sasl_init(LDAP *ldap, struct lookup_context *ctxt);
+int autofs_sasl_bind(LDAP *ldap, struct lookup_context *ctxt);
+void autofs_sasl_unbind(struct lookup_context *ctxt);
#endif
#endif /* _lookup_ldap_h */
diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
index 7066113..b89d749 100644
--- a/modules/cyrus-sasl.c
+++ b/modules/cyrus-sasl.c
@@ -35,7 +35,7 @@
*
* This file implements SASL authentication to an LDAP server for the
* following mechanisms:
- * GSSAPI, EXTERNAL, ANONYMOUS, PLAIN, DIGEST-MD5, KERBEROS_V5
+ * GSSAPI, EXTERNAL, ANONYMOUS, PLAIN, DIGEST-MD5, KERBEROS_V5, LOGIN
* The mechanism to use is specified in an external file,
* LDAP_AUTH_CONF_FILE. See the samples directory in the autofs
* distribution for an example configuration file.
@@ -43,8 +43,8 @@
* This file is written with the intent that it will work with both the
* openldap and the netscape ldap client libraries.
*
- * Author: Nalin <nalin at redhat.com>
- * Modified by Jeff <jmoyer at redhat.com> to adapt it to autofs.
+ * Author: Nalin Dahyabhai <nalin at redhat.com>
+ * Modified by Jeff Moyer <jmoyer at redhat.com> to adapt it to autofs.
*/
#include <sys/types.h>
#include <sys/wait.h>
@@ -66,6 +66,13 @@ #error "Could not determine the proper v
#endif
#endif
+/*
+ * Once a krb5 credentials cache is setup, we need to set the KRB5CCNAME
+ * environment variable so that the library knows where to find it.
+ */
+static const char *krb5ccenv = "KRB5CCNAME";
+static const char *krb5ccval = "MEMORY:_autofstkt";
+
static int sasl_log_func(void *, int, const char *);
static int getpass_func(sasl_conn_t *, void *, int, sasl_secret_t **);
static int getuser_func(void *, int, const char **, unsigned *);
@@ -128,8 +135,8 @@ getuser_func(void *context, int id, cons
}
/*
- * This function creates a sasl_secret_t from the credentials
- * specefied in sasl_init. sasl_client_auth can return SASL_OK or
+ * This function creates a sasl_secret_t from the credentials specified in
+ * the configuration file. sasl_client_auth can return SASL_OK or
* SASL_NOMEM. We simply propagate this return value to the caller.
*/
static int
@@ -353,9 +360,182 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn
return ret;
}
+/*
+ * Read client credentials from the default keytab, create a credentials
+ * cache, add the TGT to that cache, and set the environment variable so
+ * that the sasl/krb5 libraries can find our credentials.
+ *
+ * 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(struct lookup_context *ctxt)
+{
+ krb5_error_code ret;
+ krb5_principal tgs_princ, krb5_client_princ = ctxt->krb5_client_princ;
+ krb5_creds my_creds;
+ char *tgs_name;
+
+ if (ctxt->kinit_done)
+ return 0;
+ ctxt->kinit_done = 1;
+
+ debug(LOGOPT_NONE,
+ "initializing kerberos ticket: client principal %s ",
+ ctxt->client_princ ?: "autofsclient");
+
+ ret = krb5_init_context(&ctxt->krb5ctxt);
+ if (ret) {
+ error(LOGOPT_ANY, "krb5_init_context failed with %d", ret);
+ return -1;
+ }
+
+ ret = krb5_cc_resolve(ctxt->krb5ctxt, krb5ccval, &ctxt->krb5_ccache);
+ if (ret) {
+ error(LOGOPT_ANY, "krb5_cc_resolve failed with error %d",
+ ret);
+ krb5_free_context(ctxt->krb5ctxt);
+ return -1;
+ }
+
+ if (ctxt->client_princ) {
+ debug(LOGOPT_NONE,
+ "calling krb5_parse_name on client principal %s",
+ ctxt->client_princ);
+
+ ret = krb5_parse_name(ctxt->krb5ctxt, ctxt->client_princ,
+ &krb5_client_princ);
+ if (ret) {
+ error(LOGOPT_ANY,
+ "krb5_parse_name failed for "
+ "specified client principal %s",
+ ctxt->client_princ);
+ goto out_cleanup_cc;
+ }
+ } else {
+ char *tmp_name = NULL;
+
+ debug(LOGOPT_NONE,
+ "calling krb5_sname_to_principal using defaults");
+
+ ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
+ "autofsclient", KRB5_NT_SRV_HST,
+ &krb5_client_princ);
+ if (ret) {
+ error(LOGOPT_ANY,
+ "krb5_sname_to_principal failed for "
+ "%s with error %d",
+ ctxt->client_princ ?: "autofsclient", ret);
+ goto out_cleanup_cc;
+ }
+
+
+ ret = krb5_unparse_name(ctxt->krb5ctxt,
+ krb5_client_princ, &tmp_name);
+ if (ret) {
+ debug(LOGOPT_NONE,
+ "krb5_unparse_name failed with error %d",
+ ret);
+ goto out_cleanup_cc;
+ }
+
+ debug(LOGOPT_NONE,
+ "principal used for authentication: \"%s\"", tmp_name);
+
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name);
+ }
+
+ /* setup a principal for the ticket granting service */
+ ret = krb5_build_principal_ext(ctxt->krb5ctxt, &tgs_princ,
+ krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->length,
+ krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->data,
+ strlen(KRB5_TGS_NAME), KRB5_TGS_NAME,
+ krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->length,
+ krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->data,
+ 0);
+ if (ret) {
+ error(LOGOPT_ANY,
+ "krb5_build_principal failed with error %d", ret);
+ goto out_cleanup_cc;
+ }
+
+ ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name);
+ if (ret) {
+ error(LOGOPT_ANY, "krb5_unparse_name failed with error %d",
+ ret);
+ goto out_cleanup_cc;
+ }
+
+ debug(LOGOPT_NONE, "Using tgs name %s", tgs_name);
+
+ memset(&my_creds, 0, sizeof(my_creds));
+ ret = krb5_get_init_creds_keytab(ctxt->krb5ctxt, &my_creds,
+ krb5_client_princ,
+ NULL /*keytab*/,
+ 0 /* relative start time */,
+ tgs_name, NULL);
+ if (ret) {
+ error(LOGOPT_ANY,
+ "krb5_get_init_creds_keytab failed with error %d",
+ ret);
+ goto out_cleanup_unparse;
+ }
+
+ /* tell the cache what the default principal is */
+ ret = krb5_cc_initialize(ctxt->krb5ctxt,
+ ctxt->krb5_ccache, krb5_client_princ);
+ if (ret) {
+ error(LOGOPT_ANY,
+ "krb5_cc_initialize failed with error %d", ret);
+ goto out_cleanup_unparse;
+ }
+
+ /* and store credentials for that principal */
+ ret = krb5_cc_store_cred(ctxt->krb5ctxt, ctxt->krb5_ccache, &my_creds);
+ if (ret) {
+ error(LOGOPT_ANY,
+ "krb5_cc_store_cred failed with error %d", ret);
+ goto out_cleanup_unparse;
+ }
+
+ /* finally, set the environment variable to point to our
+ * credentials cache */
+ if (setenv(krb5ccenv, krb5ccval, 1) != 0) {
+ error(LOGOPT_ANY, "setenv failed with %d", errno);
+ goto out_cleanup_unparse;
+ }
+ ctxt->kinit_successful = 1;
+
+ debug(LOGOPT_NONE, "Kerberos authentication was successful!");
+
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
+ return 0;
+
+out_cleanup_unparse:
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
+out_cleanup_cc:
+ ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ if (ret)
+ warn(LOGOPT_ANY,
+ "krb5_cc_destroy failed with non-fatal error %d", ret);
+
+ krb5_free_context(ctxt->krb5ctxt);
+
+ return -1;
+}
+
+/*
+ * Attempt to bind to the ldap server using a given authentication
+ * mechanism. ldap should be a properly initialzed ldap pointer.
+ *
+ * Returns a valid sasl_conn_t pointer upon success, NULL on failure.
+ */
sasl_conn_t *
-sasl_bind_mech(LDAP *ldap, const char *mech)
+sasl_bind_mech(LDAP *ldap, struct lookup_context *ctxt, const char *mech)
{
sasl_conn_t *conn;
char *tmp, *host = NULL;
@@ -364,17 +544,27 @@ sasl_bind_mech(LDAP *ldap, const char *m
const char *chosen_mech;
int result;
+ if (!strncmp(mech, "GSSAPI", 6)) {
+ if (sasl_do_kinit(ctxt) != 0)
+ return NULL;
+ }
+
+ debug(LOGOPT_NONE, "Attempting sasl bind with mechanism %s", mech);
+
result = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
- if (result != LDAP_SUCCESS) {
+ if (result != LDAP_SUCCESS || !host) {
debug(LOGOPT_NONE, "failed to get hostname for connection");
return NULL;
}
+
if ((tmp = strchr(host, ':')))
*tmp = '\0';
/* Create a new authentication context for the service. */
result = sasl_client_new("ldap", host, NULL, NULL, NULL, 0, &conn);
if (result != SASL_OK) {
+ error(LOGOPT_ANY, "sasl_client_new failed with error %d",
+ result);
ldap_memfree(host);
return NULL;
}
@@ -385,10 +575,10 @@ sasl_bind_mech(LDAP *ldap, const char *m
/* OK and CONTINUE are the only non-fatal return codes here. */
if ((result != SASL_OK) && (result != SASL_CONTINUE)) {
- error(LOGOPT_ANY, "%s", sasl_errdetail(conn));
+ error(LOGOPT_ANY, "sasl_client start failed with error: %s",
+ sasl_errdetail(conn));
ldap_memfree(host);
- if (conn)
- sasl_dispose(&conn);
+ sasl_dispose(&conn);
return NULL;
}
@@ -396,12 +586,15 @@ sasl_bind_mech(LDAP *ldap, const char *m
&clientout, &clientoutlen, chosen_mech, result);
if (result == 0) {
ldap_memfree(host);
+ debug(LOGOPT_NONE, "sasl bind with mechanism %s succeeded",
+ chosen_mech);
return conn;
}
- ldap_memfree(host);
+ info(LOGOPT_ANY, "sasl bind with mechanism %s failed", mech);
/* sasl bind failed */
+ ldap_memfree(host);
sasl_dispose(&conn);
return NULL;
@@ -411,27 +604,17 @@ sasl_bind_mech(LDAP *ldap, const char *m
* Returns 0 if a suitable authentication mechanism is available. Returns
* -1 on error or if no mechanism is supported by both client and server.
*/
-int
-sasl_choose_mech(struct lookup_context *ctxt, char **mechanism)
+sasl_conn_t *
+sasl_choose_mech(LDAP *ldap, struct lookup_context *ctxt)
{
- LDAP *ldap;
sasl_conn_t *conn;
int authenticated;
int i;
char **mechanisms;
- /* TODO: what's this here for ? */
- *mechanism = NULL;
-
- ldap = ldap_connection_init(ctxt);
- if (!ldap)
- return -1;
-
mechanisms = get_server_SASL_mechanisms(ldap);
- if (!mechanisms) {
- ldap_unbind_connection(ldap, ctxt);
- return -1;
- }
+ if (!mechanisms)
+ return NULL;
/* Try each supported mechanism in turn. */
authenticated = 0;
@@ -440,32 +623,137 @@ sasl_choose_mech(struct lookup_context *
* This routine is called if there is no configured
* mechanism. As such, we can skip over any auth
* mechanisms that require user credentials. These include
- * PLAIN and DIGEST-MD5.
+ * PLAIN, LOGIN, and DIGEST-MD5.
*/
if (authtype_requires_creds(mechanisms[i]))
continue;
- conn = sasl_bind_mech(ldap, mechanisms[i]);
+ conn = sasl_bind_mech(ldap, ctxt, mechanisms[i]);
if (conn) {
- sasl_dispose(&conn);
+ ctxt->sasl_mech = strdup(mechanisms[i]);
+ if (!ctxt->sasl_mech) {
+ crit(LOGOPT_ANY,
+ "Successfully authenticated with "
+ "mechanism %s, but failed to allocate "
+ "memory to hold the mechanism type.",
+ mechanisms[i]);
+ sasl_dispose(&conn);
+ ldap_value_free(mechanisms);
+ return NULL;
+ }
authenticated = 1;
break;
}
+ debug(LOGOPT_NONE, "Failed to authenticate with mech %s",
+ mechanisms[i]);
}
+ debug(LOGOPT_NONE, "authenticated: %d, sasl_mech: %s",
+ authenticated, ctxt->sasl_mech);
+
ldap_value_free(mechanisms);
- return (authenticated > 0) ? 0 : -1;
+ return conn;
}
int
-sasl_init(char *id, char *secret)
+autofs_sasl_bind(LDAP *ldap, struct lookup_context *ctxt)
{
- /* Start up Cyrus SASL--only needs to be done once. */
- if (sasl_client_init(callbacks) != SASL_OK)
+ sasl_conn_t *conn;
+
+ if (!ctxt->sasl_mech)
return -1;
- sasl_auth_id = id;
- sasl_auth_secret = secret;
+ conn = sasl_bind_mech(ldap, ctxt, ctxt->sasl_mech);
+ if (!conn)
+ return -1;
+ ctxt->sasl_conn = conn;
return 0;
}
+
+/*
+ * Routine called when unbinding an ldap connection.
+ */
+void
+autofs_sasl_unbind(struct lookup_context *ctxt)
+{
+ if (ctxt->sasl_conn) {
+ sasl_dispose(&ctxt->sasl_conn);
+ ctxt->sasl_conn = NULL;
+ }
+}
+
+/*
+ * Given a lookup context that has been initialized with any user-specified
+ * parameters, figure out which sasl mechanism to use. Then, initialize
+ * the necessary parameters to authenticate with the chosen mechanism.
+ *
+ * Return Values:
+ * 0 - Success
+ * -1 - Failure
+ */
+int
+autofs_sasl_init(LDAP *ldap, struct lookup_context *ctxt)
+{
+ sasl_conn_t *conn;
+
+ /* Start up Cyrus SASL--only needs to be done once. */
+ if (sasl_client_init(callbacks) != SASL_OK) {
+ error(LOGOPT_ANY, "sasl_client_init failed");
+ return -1;
+ }
+
+ sasl_auth_id = ctxt->user;
+ sasl_auth_secret = ctxt->secret;
+
+ /*
+ * If sasl_mech was not filled in, it means that there was no
+ * mechanism specified in the configuration file. Try to auto-
+ * select one.
+ */
+ if (ctxt->sasl_mech)
+ conn = sasl_bind_mech(ldap, ctxt, ctxt->sasl_mech);
+ else
+ conn = sasl_choose_mech(ldap, ctxt);
+
+ if (conn) {
+ sasl_dispose(&conn);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Destructor routine. This should be called when finished with an ldap
+ * session.
+ */
+void
+autofs_sasl_done(struct lookup_context *ctxt)
+{
+ int ret;
+
+ if (ctxt && ctxt->sasl_conn) {
+ sasl_dispose(&ctxt->sasl_conn);
+ ctxt->sasl_conn = NULL;
+ }
+
+ if (ctxt->kinit_successful) {
+
+ ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ if (ret)
+ warn(LOGOPT_ANY,
+ "krb5_cc_destroy failed with non-fatal error %d",
+ ret);
+
+ krb5_free_context(ctxt->krb5ctxt);
+ if (unsetenv(krb5ccenv) != 0)
+ warn(LOGOPT_ANY,
+ "unsetenv failed with error %d", errno);
+
+ ctxt->krb5ctxt = NULL;
+ ctxt->krb5_ccache = NULL;
+ ctxt->kinit_done = 0;
+ ctxt->kinit_successful = 0;
+ }
+}
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index adbf13d..3c9c332 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -43,7 +43,7 @@ #define MODPREFIX "lookup(ldap): "
int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
-int ldap_bind_anonymous(LDAP *ldap, struct lookup_context *ctxt)
+int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
{
int rv;
@@ -53,7 +53,6 @@ int ldap_bind_anonymous(LDAP *ldap, stru
rv = ldap_simple_bind_s(ldap, NULL, NULL);
if (rv != LDAP_SUCCESS) {
- ldap_unbind(ldap);
crit(LOGOPT_ANY,
MODPREFIX "Unable to bind to the LDAP server: "
"%s, error %s", ctxt->server ?: "(default)",
@@ -64,11 +63,12 @@ int ldap_bind_anonymous(LDAP *ldap, stru
return 0;
}
-int ldap_unbind_connection(LDAP *ldap, struct lookup_context *ctxt)
+int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt)
{
int rv;
#if WITH_SASL
+ debug(LOGOPT_NONE, "use_tls: %d", ctxt->use_tls);
/*
* The OpenSSL library can't handle having its message and error
* string database loaded multiple times and segfaults if the
@@ -81,9 +81,10 @@ #if WITH_SASL
ERR_remove_state(0);
ctxt->use_tls = LDAP_TLS_INIT;
}
+ autofs_sasl_unbind(ctxt);
#endif
- rv = ldap_unbind(ldap);
+ rv = ldap_unbind_ext(ldap, NULL, NULL);
if (rv != LDAP_SUCCESS)
error(LOGOPT_ANY,
"unbind failed: %s", ldap_err2string(rv));
@@ -91,7 +92,7 @@ #endif
return rv;
}
-LDAP *ldap_connection_init(struct lookup_context *ctxt)
+LDAP *init_ldap_connection(struct lookup_context *ctxt)
{
LDAP *ldap = NULL;
int timeout = 8;
@@ -100,6 +101,12 @@ LDAP *ldap_connection_init(struct lookup
ctxt->version = 3;
/* Initialize the LDAP context. */
+ /* LDAP_PORT should not be hard-coded, here. If we are going to
+ * parse ldap strings ourselves, then we can put the port specified
+ * in the host:port format here. Otherwise, we can just pass the
+ * host:port string to the ldap_init call and let the library handle
+ * it. -JM
+ */
ldap = ldap_init(ctxt->server, LDAP_PORT);
if (!ldap) {
crit(LOGOPT_ANY,
@@ -112,7 +119,7 @@ LDAP *ldap_connection_init(struct lookup
rv = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ctxt->version);
if (rv != LDAP_OPT_SUCCESS) {
/* fall back to LDAPv2 */
- ldap_unbind(ldap);
+ ldap_unbind_ext(ldap, NULL, NULL);
ldap = ldap_init(ctxt->server, LDAP_PORT);
if (!ldap) {
crit(LOGOPT_ANY, MODPREFIX "couldn't initialize LDAP");
@@ -135,7 +142,7 @@ #if WITH_SASL
error(LOGOPT_ANY,
MODPREFIX
"TLS required but connection is version 2");
- ldap_unbind(ldap);
+ ldap_unbind_ext(ldap, NULL, NULL);
return NULL;
}
return ldap;
@@ -143,7 +150,7 @@ #if WITH_SASL
rv = ldap_start_tls_s(ldap, NULL, NULL);
if (rv != LDAP_SUCCESS) {
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
if (ctxt->tls_required) {
error(LOGOPT_ANY,
MODPREFIX
@@ -152,7 +159,7 @@ #if WITH_SASL
return NULL;
}
ctxt->use_tls = LDAP_TLS_DONT_USE;
- ldap = ldap_connection_init(ctxt);
+ ldap = init_ldap_connection(ctxt);
ctxt->use_tls = LDAP_TLS_INIT;
return ldap;
}
@@ -168,39 +175,32 @@ static LDAP *do_connect(struct lookup_co
LDAP *ldap;
int rv;
- ldap = ldap_connection_init(ctxt);
+ ldap = init_ldap_connection(ctxt);
if (!ldap)
return NULL;
#if WITH_SASL
- if (ctxt->auth_required && ctxt->sasl_mech) {
- sasl_conn_t *conn;
+ debug(LOGOPT_NONE, "auth_required: %d, sasl_mech %s",
+ ctxt->auth_required, ctxt->sasl_mech);
- debug(LOGOPT_NONE,
- MODPREFIX
- "attempting sasl bind, mechanism %s, user %s",
- ctxt->sasl_mech, ctxt->user);
-
- rv = 0;
- conn = sasl_bind_mech(ldap, ctxt->sasl_mech);
- if (!conn) {
- error(LOGOPT_ANY, MODPREFIX "sasl bind failed");
- rv = 1;
- }
-
- sasl_dispose(&conn);
+ if (ctxt->auth_required || ctxt->sasl_mech) {
+ rv = autofs_sasl_bind(ldap, ctxt);
+ debug(LOGOPT_NONE, MODPREFIX
+ "autofs_sasl_bind returned %d", rv);
} else {
- rv = ldap_bind_anonymous(ldap, ctxt);
+ rv = bind_ldap_anonymous(ldap, ctxt);
debug(LOGOPT_NONE,
- MODPREFIX "doing anonymous bind, ret %d", rv);
+ MODPREFIX "ldap anonymous bind returned %d", rv);
}
#else
- rv = ldap_bind_anonymous(ldap, ctxt);
- debug(LOGOPT_NONE, MODPREFIX "doing anonymous bind, ret %d", rv);
+ rv = bind_ldap_anonymous(ldap, ctxt);
+ debug(LOGOPT_NONE, MODPREFIX "ldap anonymous bind returned %d", rv);
#endif
- if (rv != 0)
+ if (rv != 0) {
+ unbind_ldap_connection(ldap, ctxt);
return NULL;
+ }
return ldap;
}
@@ -228,13 +228,14 @@ int get_property(xmlNodePtr node, const
}
/*
- * For plain text and digest-md5 authentication types, we need
+ * For plain text, login and digest-md5 authentication types, we need
* user and password credentials.
*/
int authtype_requires_creds(const char *authtype)
{
if (!strncmp(authtype, "PLAIN", strlen("PLAIN")) ||
- !strncmp(authtype, "DIGEST-MD5", strlen("DIGEST-MD5")))
+ !strncmp(authtype, "DIGEST-MD5", strlen("DIGEST-MD5")) ||
+ !strncmp(authtype, "LOGIN", strlen("LOGIN")))
return 1;
return 0;
}
@@ -262,6 +263,7 @@ int parse_ldap_config(struct lookup_cont
xmlNodePtr root = NULL;
char *authrequired, *auth_conf, *authtype;
char *user = NULL, *secret = NULL;
+ char *client_princ = NULL;
char *usetls, *tlsrequired;
authtype = user = secret = NULL;
@@ -290,6 +292,7 @@ int parse_ldap_config(struct lookup_cont
ctxt->sasl_mech = NULL;
ctxt->user = NULL;
ctxt->secret = NULL;
+ ctxt->client_princ = NULL;
return 0;
}
error(LOGOPT_ANY,
@@ -444,6 +447,12 @@ int parse_ldap_config(struct lookup_cont
}
}
+ /*
+ * We allow the admin to specify the principal to use for the
+ * client. The default is "autofsclient/hostname at REALM".
+ */
+ (void)get_property(root, "clientprinc", &client_princ);
+
ctxt->auth_conf = auth_conf;
ctxt->use_tls = use_tls;
ctxt->tls_required = tls_required;
@@ -451,6 +460,22 @@ int parse_ldap_config(struct lookup_cont
ctxt->sasl_mech = authtype;
ctxt->user = user;
ctxt->secret = secret;
+ ctxt->client_princ = client_princ;
+
+ debug(LOGOPT_NONE,
+ "ldap authentication configured with the following options:\n");
+ debug(LOGOPT_NONE,
+ "use_tls: %u, "
+ "tls_required: %u, "
+ "auth_required: %u, "
+ "sasl_mech: %s\n",
+ use_tls, tls_required, auth_required, authtype);
+ debug(LOGOPT_NONE,
+ "user: %s, "
+ "secret: %s, "
+ "client principal: %s\n",
+ user, secret ? "specified" : "unspecified",
+ client_princ);
out:
xmlFreeDoc(doc);
@@ -470,11 +495,10 @@ out:
* Returns 0 on success, with authtype, user and secret filled in as
* appropriate. Returns -1 on failre.
*/
-int ldap_auth_init(struct lookup_context *ctxt)
+int auth_init(struct lookup_context *ctxt)
{
int ret;
-
- ctxt->sasl_mech = NULL;
+ LDAP *ldap;
/*
* First, check to see if a preferred authentication method was
@@ -486,22 +510,23 @@ int ldap_auth_init(struct lookup_context
if (ret)
return -1;
+ ldap = init_ldap_connection(ctxt);
+ if (!ldap)
+ return -1;
+
/*
* Initialize the sasl library. It is okay if user and secret
* are NULL, here.
+ *
+ * The autofs_sasl_init routine will figure out which mechamism
+ * to use. If kerberos is used, it will also take care to initialize
+ * the credential cache and the client and service principals.
*/
- if (sasl_init(ctxt->user, ctxt->secret) != 0)
+ ret = autofs_sasl_init(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
+ if (ret) {
+ ctxt->sasl_mech = NULL;
return -1;
-
- /*
- * If sasl_mech was not filled in, it means that there was no
- * mechanism specified in the configuration file. Try to auto-
- * select one if there are credentials.
- */
- if (ctxt->sasl_mech == NULL && ctxt->user != NULL) {
- ret = sasl_choose_mech(ctxt, &ctxt->sasl_mech);
- if (ret != 0)
- return -1;
}
return 0;
@@ -850,9 +875,10 @@ #if WITH_SASL
* Determine which authentication mechanism to use. We sanity-
* check by binding to the server temporarily.
*/
- ret = ldap_auth_init(ctxt);
- if (ret) {
- error(LOGOPT_ANY, MODPREFIX "cannot initialize auth setup");
+ ret = auth_init(ctxt);
+ if (ret && ctxt->auth_required) {
+ error(LOGOPT_ANY, MODPREFIX
+ "cannot initialize authentication setup");
free_context(ctxt);
return 1;
}
@@ -865,16 +891,14 @@ #endif
return 1;
}
- if (!get_query_dn(ldap, ctxt)) {
+ ret = get_query_dn(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
+ if (!ret) {
error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
- ldap_unbind_connection(ldap, ctxt);
free_context(ctxt);
return 1;
}
- /* Okay, we're done here. */
- ldap_unbind_connection(ldap, ctxt);
-
/* Open the parser, if we can. */
ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
if (!ctxt->parse) {
@@ -941,7 +965,7 @@ int lookup_read_master(struct master *ma
error(LOGOPT_NONE,
MODPREFIX "query failed for %s: %s",
query, ldap_err2string(rv));
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return NSS_STATUS_NOTFOUND;
}
@@ -951,7 +975,7 @@ int lookup_read_master(struct master *ma
MODPREFIX "query succeeded, no matches for %s",
query);
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return NSS_STATUS_NOTFOUND;
} else
debug(LOGOPT_NONE, MODPREFIX "examining entries");
@@ -1026,7 +1050,7 @@ next:
/* Clean up. */
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return NSS_STATUS_SUCCESS;
}
@@ -1092,7 +1116,7 @@ static int read_one_map(struct autofs_po
debug(ap->logopt,
MODPREFIX "query failed for %s: %s",
query, ldap_err2string(rv));
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
*result_ldap = rv;
return NSS_STATUS_NOTFOUND;
}
@@ -1102,7 +1126,7 @@ static int read_one_map(struct autofs_po
debug(ap->logopt,
MODPREFIX "query succeeded, no matches for %s", query);
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return NSS_STATUS_NOTFOUND;
} else
debug(ap->logopt, MODPREFIX "examining entries");
@@ -1216,7 +1240,7 @@ next:
/* Clean up. */
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return NSS_STATUS_SUCCESS;
}
@@ -1308,7 +1332,7 @@ static int lookup_one(struct autofs_poin
if ((rv != LDAP_SUCCESS) || !result) {
crit(ap->logopt, MODPREFIX "query failed for %s", query);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return CHE_FAIL;
}
@@ -1320,7 +1344,7 @@ static int lookup_one(struct autofs_poin
debug(ap->logopt,
MODPREFIX "got answer, but no entry for %s", query);
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return CHE_MISSING;
}
@@ -1332,7 +1356,7 @@ static int lookup_one(struct autofs_poin
MODPREFIX "key %s has duplicate entries", *keyValue);
ldap_value_free(keyValue);
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return CHE_FAIL;
}
@@ -1344,7 +1368,7 @@ static int lookup_one(struct autofs_poin
MODPREFIX "no %s defined for %s", info, query);
ldap_value_free(keyValue);
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return CHE_MISSING;
}
@@ -1405,7 +1429,7 @@ done:
/* Clean up. */
ldap_value_free(keyValue);
ldap_msgfree(result);
- ldap_unbind_connection(ldap, ctxt);
+ unbind_ldap_connection(ldap, ctxt);
return ret;
}
@@ -1564,6 +1588,8 @@ int lookup_done(void *context)
#if WITH_SASL
EVP_cleanup();
ERR_free_strings();
+
+ autofs_sasl_done(ctxt);
#endif
free_context(ctxt);
return rv;
autofs-5.0.0_beta6-check-return.patch:
CHANGELOG | 1 +
modules/lookup_ldap.c | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
--- NEW FILE autofs-5.0.0_beta6-check-return.patch ---
diff --git a/CHANGELOG b/CHANGELOG
index 4345c6e..58c8bbc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@
- merge LDAP authentication update for GSSAPI (Jeff Moyer).
- update default auth config to add options documenetation (Jeff Moyer).
- workaround segfaults at exit after using GSSAPI library.
+- fix not checking return in init_ldap_connection (jeff Moyer).
29/6/2006 autofs-5.0.0_beta6
----------------------------
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 3c9c332..003b836 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -160,7 +160,8 @@ #if WITH_SASL
}
ctxt->use_tls = LDAP_TLS_DONT_USE;
ldap = init_ldap_connection(ctxt);
- ctxt->use_tls = LDAP_TLS_INIT;
+ if (ldap)
+ ctxt->use_tls = LDAP_TLS_INIT;
return ldap;
}
ctxt->use_tls = LDAP_TLS_RELEASE;
autofs-5.0.0_beta6-default-auth-config.patch:
CHANGELOG | 1
samples/autofs_ldap_auth.conf | 56 +++++++++++++++++++++++++++++++++++++++---
2 files changed, 54 insertions(+), 3 deletions(-)
--- NEW FILE autofs-5.0.0_beta6-default-auth-config.patch ---
diff --git a/CHANGELOG b/CHANGELOG
index df66913..854e1f5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
?/7/2006 autofs-5.0.0
---------------------
- merge LDAP authentication update for GSSAPI (Jeff Moyer).
+- update default auth config to add options documenetation (Jeff Moyer).
29/6/2006 autofs-5.0.0_beta6
----------------------------
diff --git a/samples/autofs_ldap_auth.conf b/samples/autofs_ldap_auth.conf
index 265571e..1b20c09 100644
--- a/samples/autofs_ldap_auth.conf
+++ b/samples/autofs_ldap_auth.conf
@@ -1,9 +1,59 @@
<?xml version="1.0" ?>
+<!--
+This files contains a single entry with multiple attributes tied to it.
+The attributes are:
+
+usetls - Determines whether an encrypted connection to the ldap server
+ should be attempted. Legal values for the entry are:
+ "yes"
+ "no"
+
+tlsrequired - This flag tells whether the ldap connection must be
+ encrypted. If set to "yes", the automounter will fail to start
+ if an encrypted connection cannot be established. Legal values
+ for this option include:
+ "yes"
+ "no"
+
+authrequired - This is a boolean flag which tells whether an
+ authenticated connection to the ldap server is required in order
+ to perform ldap queries. If this flag is set to yes, then only
+ authenticated connections to the ldap server will be allowed.
+ Legal values for this option include:
+ "yes"
+ "no"
+
+authtype - This attribute can be used to specify a preferred
+ authentication mechanism. In normal operations, the
+ automounter will attempt to authenticate to the ldap server
+ using the list of supportedSASLmechanisms obtained from the
+ directory server. Explicitly setting the authtype will bypass
+ this selection and only try the mechanism specified. Legal
+ values for this attribute include:
+ "GSSAPI"
+ "LOGIN"
+ "PLAIN"
+ "ANONYMOUS"
+ "DIGEST-MD5"
+
+user - This attribute holds the authentication identity used by
+ authentication mechanisms that require it. Legal values for
+ this attribute include any printable characters that can be
+ used by the selected authentication mechanism.
+
+secret - This attribute holds the secret used by authentication
+ mechanisms that require it. Legal values for this attribute
+ include any printable characters that can be used by the
+ selected authentication mechanism.
+
+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>.
+-->
+
<autofs_ldap_sasl_conf
usetls="no"
tlsrequired="no"
authrequired="no"
- authtype="DIGEST-MD5"
- user="xyz"
- secret="abc"
/>
autofs-5.0.0_beta6-gssapi-segfault-exit.patch:
CHANGELOG | 1 +
daemon/automount.c | 21 +++++++++++++++++++--
modules/cyrus-sasl.c | 47 +++++++++++++++++++++++++++++++++++++++++------
3 files changed, 61 insertions(+), 8 deletions(-)
--- NEW FILE autofs-5.0.0_beta6-gssapi-segfault-exit.patch ---
diff --git a/CHANGELOG b/CHANGELOG
index 854e1f5..4345c6e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,7 @@
---------------------
- merge LDAP authentication update for GSSAPI (Jeff Moyer).
- update default auth config to add options documenetation (Jeff Moyer).
+- workaround segfaults at exit after using GSSAPI library.
29/6/2006 autofs-5.0.0_beta6
----------------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 38940c7..e0e33fe 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1208,8 +1208,6 @@ static void handle_mounts_cleanup(void *
/* If we have been canceled then we may hold the state mutex. */
mutex_operation_wait(&ap->state_mutex);
- msg("shut down path %s", ap->path);
-
master_remove_mapent(ap->entry);
master_free_mapent_sources(ap->entry, 1);
master_free_mapent(ap->entry);
@@ -1226,6 +1224,8 @@ static void handle_mounts_cleanup(void *
}
}
+ msg("shut down path %s", ap->path);
+
return;
}
@@ -1353,6 +1353,23 @@ void *handle_mounts(void *arg)
*/
pthread_cleanup_pop(1);
+ /*
+ * A cowboy .. me!
+ * That noise yu ear aint spuurs sonny!!
+ *
+ * The libkrb5support destructor called indirectly through
+ * libgssapi_krb5 which is used bt libkrb5 (somehow) must run
+ * to completion before the last thread using it exits so
+ * that it's per thread data keys are deleted or we get a
+ * little segfault at exit. So much for dlclose being
+ * syncronous.
+ *
+ * So, the solution is a recipe for disaster.
+ * Hope we don't get a really busy system!
+ */
+ /* sleep(1); */
+ sched_yield();
+
return NULL;
}
diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
index b89d749..8571001 100644
--- a/modules/cyrus-sasl.c
+++ b/modules/cyrus-sasl.c
@@ -72,6 +72,8 @@ #endif
*/
static const char *krb5ccenv = "KRB5CCNAME";
static const char *krb5ccval = "MEMORY:_autofstkt";
+static pthread_mutex_t krb5cc_mutex = PTHREAD_MUTEX_INITIALIZER;
+static unsigned int krb5cc_in_use = 0;
static int sasl_log_func(void *, int, const char *);
static int getpass_func(sasl_conn_t *, void *, int, sasl_secret_t **);
@@ -378,6 +380,7 @@ sasl_do_kinit(struct lookup_context *ctx
krb5_principal tgs_princ, krb5_client_princ = ctxt->krb5_client_princ;
krb5_creds my_creds;
char *tgs_name;
+ int status;
if (ctxt->kinit_done)
return 0;
@@ -484,9 +487,20 @@ sasl_do_kinit(struct lookup_context *ctx
goto out_cleanup_unparse;
}
- /* tell the cache what the default principal is */
- ret = krb5_cc_initialize(ctxt->krb5ctxt,
+
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
+ if (krb5cc_in_use++ == 0)
+ /* tell the cache what the default principal is */
+ ret = krb5_cc_initialize(ctxt->krb5ctxt,
ctxt->krb5_ccache, krb5_client_princ);
+
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
if (ret) {
error(LOGOPT_ANY,
"krb5_cc_initialize failed with error %d", ret);
@@ -518,11 +532,22 @@ sasl_do_kinit(struct lookup_context *ctx
out_cleanup_unparse:
krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
out_cleanup_cc:
- ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
+ if (krb5cc_in_use)
+ ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ else
+ ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
if (ret)
warn(LOGOPT_ANY,
"krb5_cc_destroy failed with non-fatal error %d", ret);
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
krb5_free_context(ctxt->krb5ctxt);
return -1;
@@ -731,7 +756,7 @@ autofs_sasl_init(LDAP *ldap, struct look
void
autofs_sasl_done(struct lookup_context *ctxt)
{
- int ret;
+ int status, ret;
if (ctxt && ctxt->sasl_conn) {
sasl_dispose(&ctxt->sasl_conn);
@@ -739,13 +764,23 @@ autofs_sasl_done(struct lookup_context *
}
if (ctxt->kinit_successful) {
-
- ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
+ if (--krb5cc_in_use)
+ ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ else
+ ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
if (ret)
warn(LOGOPT_ANY,
"krb5_cc_destroy failed with non-fatal error %d",
ret);
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
krb5_free_context(ctxt->krb5ctxt);
if (unsetenv(krb5ccenv) != 0)
warn(LOGOPT_ANY,
Index: autofs.spec
===================================================================
RCS file: /cvs/dist/rpms/autofs/devel/autofs.spec,v
retrieving revision 1.116
retrieving revision 1.117
diff -u -r1.116 -r1.117
--- autofs.spec 29 Jun 2006 11:06:37 -0000 1.116
+++ autofs.spec 3 Jul 2006 05:38:26 -0000 1.117
@@ -4,13 +4,17 @@
Summary: A tool for automatically mounting and unmounting filesystems.
Name: autofs
%define version 5.0.0_beta6
-%define release 1
+%define release 2
Version: %{version}
Release: %{release}
Epoch: 1
License: GPL
Group: System Environment/Daemons
Source: ftp://ftp.kernel.org/pub/linux/daemons/autofs/v5/autofs-%{version}.tar.bz2
+Patch1: autofs-5.0.0_beta6-auth-kerberos-update.patch
+Patch2: autofs-5.0.0_beta6-default-auth-config.patch
+Patch3: autofs-5.0.0_beta6-gssapi-segfault-exit.patch
+Patch4: autofs-5.0.0_beta6-check-return.patch
Buildroot: /var/tmp/autofs-tmp
BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel
Prereq: chkconfig
@@ -49,6 +53,10 @@
%prep
%setup -q
echo %{version}-%{release} > .version
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
%build
#CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir}
@@ -105,6 +113,12 @@
%{_libdir}/autofs/*
%changelog
+* Mon Jul 3 2006 Ian Kent <ikent at redhat.com> - 5.0.0_beta6-2
+- merge LDAP authentication update for GSSAPI (Jeff Moyer).
+- update default auth config to add options documenetation (Jeff Moyer).
+- workaround segfaults at exit after using GSSAPI library.
+- fix not checking return in init_ldap_connection (jeff Moyer).
+
* Thu Jun 29 2006 Ian Kent <ikent at redhat.com> - 5.0.0_beta6-1
- consolidate to beta6, including:
- mode change update for config file.
More information about the fedora-cvs-commits
mailing list