autofs-5.0.5 - add external bind method
From: Ian Kent <raven@themaw.net>
Add sasl external bind handler.
---
CHANGELOG | 1
include/lookup_ldap.h | 7 ++
man/autofs_ldap_auth.conf.5.in | 24 +++++++-
modules/Makefile | 5 +
modules/cyrus-sasl-extern.c | 117 +++++++++++++++++++++++++++++++++++++++++
modules/cyrus-sasl.c | 20 +++++++
modules/lookup_ldap.c | 78 ++++++++++++++++++++++-----
7 files changed, 234 insertions(+), 18 deletions(-)
create mode 100644 modules/cyrus-sasl-extern.c
--- autofs-5.0.5.orig/CHANGELOG
+++ autofs-5.0.5/CHANGELOG
@@ -51,6 +51,7 @@
- fix init script status privilege error.
- always read file maps mount lookup map read fix.
- fix direct map not updating on reread.
+- add external bind method.
03/09/2009 autofs-5.0.5
-----------------------
--- autofs-5.0.5.orig/include/lookup_ldap.h
+++ autofs-5.0.5/include/lookup_ldap.h
@@ -10,6 +10,7 @@
#include <krb5.h>
#endif
+#include "list.h"
#include "dclist.h"
struct ldap_schema {
@@ -76,9 +77,13 @@ struct lookup_context {
int kinit_done;
int kinit_successful;
#ifdef WITH_SASL
+ /* Kerberos */
krb5_context krb5ctxt;
krb5_ccache krb5_ccache;
sasl_conn_t *sasl_conn;
+ /* SASL external */
+ char *extern_cert;
+ char *extern_key;
#endif
/* keytab file name needs to be added */
@@ -111,6 +116,8 @@ int autofs_sasl_bind(unsigned logopt, LD
void autofs_sasl_unbind(struct lookup_context *ctxt);
void autofs_sasl_dispose(struct lookup_context *ctxt);
void autofs_sasl_done(void);
+/* cyrus-sasl-extern */
+int do_sasl_extern(LDAP *ldap, struct lookup_context *ctxt);
#endif
#endif
--- autofs-5.0.5.orig/man/autofs_ldap_auth.conf.5.in
+++ autofs-5.0.5/man/autofs_ldap_auth.conf.5.in
@@ -60,12 +60,30 @@ authentication mechanism. If no suitabl
to the ldap server are made without authentication. Finally, if it is set to
simple, then simple authentication will be used instead of SASL.
.TP
-\fBauthtype="GSSAPI"|"LOGIN"|"PLAIN"|"ANONYMOUS"|"DIGEST-MD5"\fP
+\fBauthtype="GSSAPI"|"LOGIN"|"PLAIN"|"ANONYMOUS"|"DIGEST-MD5|EXTERNAL"\fP
This attribute can be used to specify a preferred authentication mechanism.
- In normal operations, the automounter will attempt to authenticate to the
+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.
+and only try the mechanism specified. The EXTERNAL mechanism may be used to
+authenticate using a client certificate and requires that authrequired
+set to "yes" if using SSL or usetls, tlsrequired and authrequired all set to
+"yes" if using TLS, in addition to authtype being set to EXTERNAL.
+.sp
+If using authtype EXTERNAL two additional configuration entries are
+required:
+.sp
+\fBexternal_cert="<client certificate path>"\fP
+.sp
+This specifies the path of the file containing the client certificate.
+.sp
+\fBexternal_key="<client certificate key path>"\fP
+.sp
+This specifies the path of the file containing the client certificate key.
+.sp
+These two configuration entries are mandatory when using the EXTERNAL method
+as the HOME environment variable cannot be assumed to be set or, if it is,
+to be set to the location we expect.
.TP
\fBuser="<username>"\fP
This attribute holds the authentication identity used by authentication
--- autofs-5.0.5.orig/modules/Makefile
+++ autofs-5.0.5/modules/Makefile
@@ -41,7 +41,7 @@ ifeq ($(LDAP), 1)
SRCS += lookup_ldap.c
MODS += lookup_ldap.so
ifeq ($(SASL), 1)
- SASL_OBJ = cyrus-sasl.o
+ SASL_OBJ = cyrus-sasl.o cyrus-sasl-extern.o
LDAP_FLAGS += $(SASL_FLAGS) $(XML_FLAGS) $(KRB5_FLAGS) -DLDAP_THREAD_SAFE
LIBLDAP += $(LIBSASL) $(XML_LIBS) $(KRB5_LIBS)
endif
@@ -92,6 +92,9 @@ lookup_hesiod.so: lookup_hesiod.c
cyrus-sasl.o: cyrus-sasl.c
$(CC) $(CFLAGS) $(LDAP_FLAGS) -c $<
+cyrus-sasl-extern.o: cyrus-sasl-extern.c
+ $(CC) $(CFLAGS) $(LDAP_FLAGS) -c $<
+
lookup_ldap.so: lookup_ldap.c dclist.o $(SASL_OBJ)
$(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \
lookup_ldap.c dclist.o $(SASL_OBJ) \
--- /dev/null
+++ autofs-5.0.5/modules/cyrus-sasl-extern.c
@@ -0,0 +1,117 @@
+/*
+ * cyrus-sasl-extern.c - Module for Cyrus sasl external authentication.
+ *
+ * Copyright 2010 Ian Kent <raven@themaw.net>
+ * Copyright 2010 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "config.h"
+
+#ifdef WITH_SASL
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sasl/sasl.h>
+#include <ldap.h>
+#include <ldap_cdefs.h>
+#include <lber_types.h>
+
+#include "lookup_ldap.h"
+
+struct values {
+ char *mech;
+ char *realm;
+ char *authcid;
+ char *authzid;
+ char *password;
+ char **resps;
+ int nresps;
+};
+
+static int interaction(unsigned flags, sasl_interact_t *interact, void *values)
+{
+ const char *val = interact->defresult;
+ struct values *vals = values;
+
+ switch(interact->id) {
+ case SASL_CB_GETREALM:
+ if (values)
+ val = vals->realm;
+ break;
+
+ case SASL_CB_AUTHNAME:
+ if (values)
+ val = vals->authcid;
+ break;
+
+ case SASL_CB_PASS:
+ if (values)
+ val = vals->password;
+ break;
+
+ case SASL_CB_USER:
+ if (values)
+ val = vals->authzid;
+ break;
+
+ case SASL_CB_NOECHOPROMPT:
+ case SASL_CB_ECHOPROMPT:
+ break;
+ }
+
+ if (val && !*val)
+ val = NULL;
+
+ if (val || interact->id == SASL_CB_USER) {
+ interact->result = (val && *val) ? val : "";
+ interact->len = strlen(interact->result);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int sasl_extern_interact(LDAP *ldap, unsigned flags, void *values, void *list)
+{
+ sasl_interact_t *interact = list;
+
+ if (!ldap)
+ return LDAP_PARAM_ERROR;
+
+ while (interact->id != SASL_CB_LIST_END) {
+ int rc = interaction(flags, interact, values);
+ if (rc)
+ return rc;
+ interact++;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int do_sasl_extern(LDAP *ldap, struct lookup_context *ctxt)
+{
+ int flags = LDAP_SASL_QUIET;
+ char *mech = ctxt->sasl_mech;
+ struct values values;
+ int rc;
+
+ memset(&values, 0, sizeof(struct values));
+ values.mech = mech;
+
+ rc = ldap_sasl_interactive_bind_s(ldap, NULL, mech, NULL, NULL,
+ flags, sasl_extern_interact, &values);
+ return rc;
+}
+#endif
--- autofs-5.0.5.orig/modules/cyrus-sasl.c
+++ autofs-5.0.5/modules/cyrus-sasl.c
@@ -875,6 +875,26 @@ autofs_sasl_bind(unsigned logopt, LDAP *
if (ctxt->sasl_conn)
return 0;
+ if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
+ int result;
+
+ debug(logopt,
+ "Attempting sasl bind with mechanism %s",
+ ctxt->sasl_mech);
+
+ result = do_sasl_extern(ldap, ctxt);
+ if (result)
+ debug(logopt,
+ "Failed to authenticate with mech %s",
+ ctxt->sasl_mech);
+ else
+ debug(logopt,
+ "sasl bind with mechanism %s succeeded",
+ ctxt->sasl_mech);
+
+ return result;
+ }
+
sasl_auth_id = ctxt->user;
sasl_auth_secret = ctxt->secret;
--- autofs-5.0.5.orig/modules/lookup_ldap.c
+++ autofs-5.0.5/modules/lookup_ldap.c
@@ -41,6 +41,9 @@
int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+#define ENV_LDAPTLS_CERT "LDAPTLS_CERT"
+#define ENV_LDAPTLS_KEY "LDAPTLS_KEY"
+
static struct ldap_schema common_schema[] = {
{"nisMap", "nisMapName", "nisObject", "cn", "nisMapEntry"},
{"automountMap", "ou", "automount", "cn", "automountInformation"},
@@ -61,6 +64,16 @@ struct ldap_search_params {
static int decode_percent_hack(const char *, char **);
+static int set_env(unsigned logopt, const char *name, const char *val)
+{
+ int ret = setenv(name, val, 1);
+ if (ret == -1) {
+ error(logopt, "failed to set config value for %s", name);
+ return 0;
+ }
+ return 1;
+}
+
#ifndef HAVE_LDAP_CREATE_PAGE_CONTROL
int ldap_create_page_control(LDAP *ldap, ber_int_t pagesize,
struct berval *cookie, char isCritical,
@@ -578,13 +591,17 @@ static LDAP *do_connect(unsigned logopt,
{
LDAP *ldap;
- ldap = init_ldap_connection(logopt, uri, ctxt);
- if (!ldap)
- return NULL;
+ if (ctxt->extern_cert && ctxt->extern_key) {
+ set_env(logopt, ENV_LDAPTLS_CERT, ctxt->extern_cert);
+ set_env(logopt, ENV_LDAPTLS_KEY, ctxt->extern_key);
+ }
- if (!do_bind(logopt, ldap, uri, ctxt)) {
- unbind_ldap_connection(logopt, ldap, ctxt);
- return NULL;
+ ldap = init_ldap_connection(logopt, uri, ctxt);
+ if (ldap) {
+ if (!do_bind(logopt, ldap, uri, ctxt)) {
+ unbind_ldap_connection(logopt, ldap, ctxt);
+ ldap = NULL;
+ }
}
return ldap;
@@ -839,6 +856,7 @@ int parse_ldap_config(unsigned logopt, s
xmlNodePtr root = NULL;
char *authrequired, *auth_conf, *authtype;
char *user = NULL, *secret = NULL;
+ char *extern_cert = NULL, *extern_key = NULL;
char *client_princ = NULL, *client_cc = NULL;
char *usetls, *tlsrequired;
@@ -1023,6 +1041,26 @@ int parse_ldap_config(unsigned logopt, s
ret = -1;
goto out;
}
+ } else if (auth_required == LDAP_AUTH_REQUIRED &&
+ (authtype && !strncmp(authtype, "EXTERNAL", 8))) {
+ ret = get_property(logopt, root, "external_cert", &extern_cert);
+ ret |= get_property(logopt, root, "external_key", &extern_key);
+ /*
+ * For EXTERNAL auth to function we need a client certificate
+ * and and certificate key. The ca certificate used to verify
+ * the server certificate must also be set correctly in the
+ * global configuration as the connection must be encrypted
+ * and the server and client certificates must have been
+ * verified for the EXTERNAL method to be offerred by the
+ * server. If the cert and key have not been set in the autofs
+ * configuration they must be set in the ldap rc file.
+ */
+ if (ret != 0 || !extern_cert || !extern_key) {
+ if (extern_cert)
+ free(extern_cert);
+ if (extern_key)
+ free(extern_key);
+ }
}
/*
@@ -1043,6 +1081,8 @@ int parse_ldap_config(unsigned logopt, s
ctxt->secret = secret;
ctxt->client_princ = client_princ;
ctxt->client_cc = client_cc;
+ ctxt->extern_cert = extern_cert;
+ ctxt->extern_key = extern_key;
debug(logopt, MODPREFIX
"ldap authentication configured with the following options:");
@@ -1052,14 +1092,20 @@ int parse_ldap_config(unsigned logopt, s
"auth_required: %u, "
"sasl_mech: %s",
use_tls, tls_required, auth_required, authtype);
- debug(logopt, MODPREFIX
- "user: %s, "
- "secret: %s, "
- "client principal: %s "
- "credential cache: %s",
- user, secret ? "specified" : "unspecified",
- client_princ, client_cc);
-
+ if (authtype && !strncmp(authtype, "EXTERNAL", 8)) {
+ debug(logopt, MODPREFIX "external cert: %s",
+ extern_cert ? extern_cert : "ldap default");
+ debug(logopt, MODPREFIX "external key: %s ",
+ extern_key ? extern_key : "ldap default");
+ } else {
+ debug(logopt, MODPREFIX
+ "user: %s, "
+ "secret: %s, "
+ "client principal: %s "
+ "credential cache: %s",
+ user, secret ? "specified" : "unspecified",
+ client_princ, client_cc);
+ }
out:
xmlFreeDoc(doc);
@@ -1326,6 +1372,10 @@ static void free_context(struct lookup_c
defaults_free_searchdns(ctxt->sdns);
if (ctxt->dclist)
free_dclist(ctxt->dclist);
+ if (ctxt->extern_cert)
+ free(ctxt->extern_cert);
+ if (ctxt->extern_key)
+ free(ctxt->extern_key);
free(ctxt);
return;