saslauthd patch for the bind-like method with SASL
IKEDA Yasuyuki <[email protected]>
| Newsgroups | gmane.comp.security.cyrus.sasl |
|---|---|
| Message-ID | <[email protected]> |
Hello all. I wrote an attached patch to work with the following case. How about merge this patch to the cyrus-sasl source tree? When you use the SASL authentication with LDAP, you specify the attribute used as a user ID in the LDAP server configuration (for example, sasl-regexp in OpenLDAP). In my case, the user ID a user enters is not the attribute specified as SASL authentication user ID: a user enters his or her mail user name, but the LDAP server accepts only emploee IDs for the SASL authentication (and could not configure the LDAP server to use mail user names as SASL authentication ID for some reasons) . To work with the above case, my patched saslauthd authenticates a user as following: 1. First, binds the LDAP server with ldap_id or ldap_bind_dn 2. Searches for the user object to the authenticate, with the ID the user entered. 3. Retrieves the attribute in the user object, which can use for the SASL authentication. 4. Binds with the retrieved SASL user ID and the password the user entered. This works like the bind method do, but can be used with SASL. I'm happy if I can use this feature in the upstream cyrus-sasl. -- IKEDA Yasuyuki <[email protected]>
cyrus-sasl-2.1.25-saslbind.patch
(application/octet-stream, 6 KB)
diff -uNr cyrus-sasl-2.1.25.orig/saslauthd/lak.c cyrus-sasl-2.1.25/saslauthd/lak.c
--- cyrus-sasl-2.1.25.orig/saslauthd/lak.c 2009-12-04 04:07:03.000000000 +0900
+++ cyrus-sasl-2.1.25/saslauthd/lak.c 2012-11-04 00:58:23.843750000 +0900
@@ -91,6 +91,7 @@
static int lak_auth_custom(LAK *, const char *, const char *, const char *, const char *);
static int lak_auth_bind(LAK *, const char *, const char *, const char *, const char *);
static int lak_auth_fastbind(LAK *, const char *, const char *, const char *, const char *);
+static int lak_auth_saslbind(LAK *, const char *, const char *, const char *, const char *);
static int lak_group_member(LAK *, const char *, const char *, const char *, const char *);
static char *lak_result_get(const LAK_RESULT *, const char *);
static int lak_result_add(const char *, const char *, LAK_RESULT **);
@@ -110,6 +111,7 @@
{ LAK_AUTH_METHOD_BIND, lak_auth_bind },
{ LAK_AUTH_METHOD_CUSTOM, lak_auth_custom },
{ LAK_AUTH_METHOD_FASTBIND, lak_auth_fastbind },
+ { LAK_AUTH_METHOD_SASLBIND, lak_auth_saslbind },
{ -1, NULL }
};
@@ -235,6 +237,8 @@
conf->auth_method = LAK_AUTH_METHOD_CUSTOM;
} else if (!strcasecmp(p, "fastbind")) {
conf->auth_method = LAK_AUTH_METHOD_FASTBIND;
+ } else if (!strcasecmp(p, "saslbind")) {
+ conf->auth_method = LAK_AUTH_METHOD_SASLBIND;
}
} else if (!strcasecmp(key, "ldap_timeout")) {
conf->timeout.tv_sec = lak_config_int(p);
@@ -278,6 +282,9 @@
!strcasecmp(key, "ldap_sasl_authz_id"))
strlcpy(conf->authz_id, p, LAK_BUF_LEN);
+ else if (!strcasecmp(key, "ldap_sasl_username_attr"))
+ strlcpy(conf->sasl_username_attr, p, LAK_BUF_LEN);
+
else if (!strcasecmp(key, "ldap_realm") ||
!strcasecmp(key, "ldap_sasl_realm"))
strlcpy(conf->realm, p, LAK_BUF_LEN);
@@ -323,6 +330,10 @@
conf->auth_method == LAK_AUTH_METHOD_BIND)
conf->auth_method = LAK_AUTH_METHOD_FASTBIND;
+ if (!conf->use_sasl &&
+ conf->auth_method == LAK_AUTH_METHOD_SASLBIND)
+ conf->auth_method = LAK_AUTH_METHOD_BIND;
+
if ( ISSET(conf->group_filter) &&
ISSET(conf->search_base) &&
EMPTY(conf->group_search_base) )
@@ -389,6 +400,7 @@
conf->restart = 1;
conf->start_tls = 0;
conf->use_sasl = 0;
+ strlcpy(conf->sasl_username_attr, "cn", LAK_BUF_LEN);
strlcpy(conf->path, configfile, LAK_PATH_LEN);
@@ -1509,6 +1521,50 @@
return rc;
}
+
+static int lak_auth_saslbind(
+ LAK *lak,
+ const char *user,
+ const char *service,
+ const char *realm,
+ const char *password)
+{
+ LAK_USER *lu = NULL;
+ LAK_RESULT *lres;
+ int rc;
+ const char *attrs[] = { lak->conf->sasl_username_attr, NULL};
+
+ rc = lak_retrieve(lak, user, service, realm, attrs, &lres);
+ if (rc != LAK_OK)
+ return rc;
+
+ syslog(LOG_INFO|LOG_AUTH, "Mapped user: %s -> %s", user, lres->value);
+ rc = lak_user(
+ NULL,
+ lres->value,
+ NULL,
+ lak->conf->mech,
+ lak->conf->realm,
+ password,
+ &lu);
+ if (rc != LAK_OK)
+ goto done;
+
+ rc = lak_bind(lak, lu);
+
+ if ( rc == LAK_OK &&
+ (ISSET(lak->conf->group_dn) ||
+ ISSET(lak->conf->group_filter)) )
+ rc = lak_group_member(lak, user, service, realm, NULL);
+
+done:;
+ if (lu)
+ lak_user_free(lu);
+ if (lres != NULL)
+ lak_result_free(lres);
+
+ return rc;
+}
int lak_authenticate(
LAK *lak,
diff -uNr cyrus-sasl-2.1.25.orig/saslauthd/lak.h cyrus-sasl-2.1.25/saslauthd/lak.h
--- cyrus-sasl-2.1.25.orig/saslauthd/lak.h 2004-02-25 06:56:31.000000000 +0900
+++ cyrus-sasl-2.1.25/saslauthd/lak.h 2012-10-31 21:43:37.078125000 +0900
@@ -58,6 +58,7 @@
#define LAK_AUTH_METHOD_BIND 0
#define LAK_AUTH_METHOD_CUSTOM 1
#define LAK_AUTH_METHOD_FASTBIND 2
+#define LAK_AUTH_METHOD_SASLBIND 3
#define LAK_GROUP_MATCH_METHOD_ATTR 0
#define LAK_GROUP_MATCH_METHOD_FILTER 1
@@ -84,6 +85,7 @@
char search_base[LAK_DN_LEN];
char filter[LAK_DN_LEN];
char password_attr[LAK_BUF_LEN];
+ char sasl_username_attr[LAK_BUF_LEN];
char group_dn[LAK_DN_LEN];
char group_attr[LAK_BUF_LEN];
char group_filter[LAK_DN_LEN];
diff -uNr cyrus-sasl-2.1.25.orig/saslauthd/LDAP_SASLAUTHD cyrus-sasl-2.1.25/saslauthd/LDAP_SASLAUTHD
--- cyrus-sasl-2.1.25.orig/saslauthd/LDAP_SASLAUTHD 2004-02-25 06:56:31.000000000 +0900
+++ cyrus-sasl-2.1.25/saslauthd/LDAP_SASLAUTHD 2012-11-04 22:27:01.535024200 +0900
@@ -82,7 +82,7 @@
within the first set of <>. There may be a second set of <> which provide
available values.
-ldap_auth_method: <bind|fastbind> <bind|custom|fastbind>
+ldap_auth_method: <bind|fastbind> <bind|custom|fastbind|saslbind>
Specify an authentication method.
The bind method uses the LDAP bind facility to verify the password. The
@@ -101,6 +101,18 @@
1. Expanding the ldap_filter expression gives the user's fully-qualified DN
2. There is no cost to staying bound as a named user
+ The saslbind method works as following:
+ 1. binds using SASL with ldap_id (or ldap_bind_dn) and ldap_password.
+ 2. searches for the user using ldap_search_base and ldap_filter
+ as the bind method do, and retrieves the username from the attribute
+ specified with ldap_sasl_username_attr.
+ 3. binds using SASL with the retrieved username and the passed password.
+ Generally, this method has a performance disadvantage. It is prefered to
+ configure your ldap server to map SASL user ID to DN as you want (for example,
+ by adding a new realm and sasl-regexp).
+ The saslbind method is not available when ldap_use_sasl is turned off. In that
+ case the bind method is used.
+
ldap_bind_dn: <none>
Specify DN (distinguished name) to bind to the LDAP directory. Do not
specify this parameter for the anonymous bind.
@@ -236,6 +248,10 @@
Use SASL bind rather than simple bind when connecting to the ldap
server.
+ldap_sasl_username_attr: <cn>
+ Specify what attribute to use for SASL authentication.
+ For example, use sAMAccountName with Active Directory.
+
ldap_version: <3> <2|3>
Specify the LDAP protocol version. If ldap_start_tls and/or
ldap_use_sasl are enabled, ldap_version will be automatiacally set to