Hi, Attached is my patch which implements multiple realm support for saslauthd ldap. I have updated it to work with cyrus-sasl-2.1.26. It also adds error checking & logging to the ldap config file parser. John. -- John Newbigin | ITS Senior Analyst / Programmer Faculty of Information and Communication Technologies ITS | Swinburne University of Technology | Melbourne, Australia O: EN306 | T: +61 3 9214 8185 | M: +61 410 569 362 E: jnewbigin@xxxxxxxxxxx W: http://www.ict.swin.edu.au/staff/jnewbigin
diff -r -u cyrus-sasl-2.1.26.orig/saslauthd/lak.c cyrus-sasl-2.1.26/saslauthd/lak.c --- cyrus-sasl-2.1.26.orig/saslauthd/lak.c 2012-10-13 01:05:48.000000000 +1100 +++ cyrus-sasl-2.1.26/saslauthd/lak.c 2013-01-16 12:02:39.936208639 +1100 @@ -77,7 +77,8 @@ void *rock; } LAK_PASSWORD_SCHEME; -static int lak_config_read(LAK_CONF *, const char *); +static int lak_config_read(LAK_CONF *, const char *, const char *); +static void lak_config_error(const int, const char *, const char *); static int lak_config_int(const char *); static int lak_config_switch(const char *); static void lak_config_free(LAK_CONF *); @@ -137,14 +138,28 @@ #define ISSET(x) ((x != NULL) && (*(x) != '\0')) #define EMPTY(x) ((x == NULL) || (*(x) == '\0')) +static void lak_config_error( + const int lineno, + const char *key, + const char *value) +{ + syslog(LOG_ERR|LOG_AUTH, + "Error in saslauthd config file on line %d: %s is not a valid value for %s", + lineno, + value, + key); +} + static int lak_config_read( LAK_CONF *conf, - const char *configfile) + const char *configfile, + const char *configrealm) { FILE *infile; int lineno = 0; char buf[4096]; char *p, *key; + int in_realm = 1; infile = fopen(configfile, "r"); if (!infile) { @@ -170,6 +185,11 @@ p++; } if (*p != ':') { + syslog(LOG_ERR|LOG_AUTH, + "Error in saslauthd config file on line %d: %s does not have a value", + lineno, + key); + fclose(infile); return LAK_FAIL; } @@ -180,11 +200,28 @@ p++; if (!*p) { + syslog(LOG_ERR|LOG_AUTH, + "Error in saslauthd config file on line %d: %s does not have a value", + lineno, + key); + fclose(infile); return LAK_FAIL; } - if (!strcasecmp(key, "ldap_servers")) + if (!strcasecmp(key, "realm")) { + if(!strcasecmp(p, configrealm)) { + in_realm = 1; + } else { + in_realm = 0; + } + } + if(!in_realm) + continue; + + if (!strcasecmp(key, "realm")) { + + } else if (!strcasecmp(key, "ldap_servers")) strlcpy(conf->servers, p, LAK_URL_LEN); else if (!strcasecmp(key, "ldap_bind_dn")) @@ -223,12 +260,22 @@ conf->group_scope = LDAP_SCOPE_ONELEVEL; } else if (!strcasecmp(p, "base")) { conf->group_scope = LDAP_SCOPE_BASE; + } else if (!strcasecmp(p, "sub")) { + conf->group_scope = LDAP_SCOPE_SUB; + } else { + lak_config_error(lineno, key, p); + fclose(infile); + return LAK_FAIL; } } else if (!strcasecmp(key, "ldap_group_match_method")) { if (!strcasecmp(p, "filter")) { conf->group_match_method = LAK_GROUP_MATCH_METHOD_FILTER; } else if (!strcasecmp(p, "attr")) { conf->group_match_method = LAK_GROUP_MATCH_METHOD_ATTR; + } else { + lak_config_error(lineno, key, p); + fclose(infile); + return LAK_FAIL; } } else if (!strcasecmp(key, "ldap_default_realm") || !strcasecmp(key, "ldap_default_domain")) @@ -239,6 +286,12 @@ conf->auth_method = LAK_AUTH_METHOD_CUSTOM; } else if (!strcasecmp(p, "fastbind")) { conf->auth_method = LAK_AUTH_METHOD_FASTBIND; + } else if (!strcasecmp(p, "bind")) { + conf->auth_method = LAK_AUTH_METHOD_BIND; + } else { + lak_config_error(lineno, key, p); + fclose(infile); + return LAK_FAIL; } } else if (!strcasecmp(key, "ldap_timeout")) { conf->timeout.tv_sec = lak_config_int(p); @@ -258,6 +311,10 @@ conf->deref = LDAP_DEREF_ALWAYS; } else if (!strcasecmp(p, "never")) { conf->deref = LDAP_DEREF_NEVER; + } else { + lak_config_error(lineno, key, p); + fclose(infile); + return LAK_FAIL; } } else if (!strcasecmp(key, "ldap_referrals")) { conf->referrals = lak_config_switch(p); @@ -270,6 +327,12 @@ conf->scope = LDAP_SCOPE_ONELEVEL; } else if (!strcasecmp(p, "base")) { conf->scope = LDAP_SCOPE_BASE; + } else if (!strcasecmp(p, "sub")) { + conf->scope = LDAP_SCOPE_SUB; + } else { + lak_config_error(lineno, key, p); + fclose(infile); + return LAK_FAIL; } } else if (!strcasecmp(key, "ldap_use_sasl")) { conf->use_sasl = lak_config_switch(p); @@ -316,6 +379,14 @@ else if (!strcasecmp(key, "ldap_debug")) conf->debug = lak_config_int(p); + else { + syslog(LOG_ERR|LOG_AUTH, + "Error in saslauthd config file on line %d: Unknown key %s", + lineno, + key); + fclose(infile); + return LAK_FAIL; + } } if (conf->version != LDAP_VERSION3 && @@ -396,7 +467,7 @@ strlcpy(conf->path, configfile, LAK_PATH_LEN); - rc = lak_config_read(conf, conf->path); + rc = lak_config_read(conf, conf->path, ""); if (rc != LAK_OK) { lak_config_free(conf); return rc; @@ -1533,8 +1604,21 @@ if (EMPTY(user)) return LAK_FAIL; - if (EMPTY(realm)) + if (EMPTY(realm)) { realm = lak->conf->default_realm; + } + + + if(strcmp(lak->realm, realm) != 0) { + syslog(LOG_DEBUG|LOG_AUTH, "lak_authenticate for realm %s", realm); + strlcpy(lak->realm, realm, LAK_BUF_LEN); + lak_unbind(lak); + rc = lak_config_read(lak->conf, lak->conf->path, realm); + if (rc != LAK_OK) { + syslog(LOG_ERR|LOG_AUTH, "lak_authenticate error reading config for realm %s", realm); + return LAK_FAIL; + } + } for (i = 0; authenticator[i].method != -1; i++) { if (authenticator[i].method == lak->conf->auth_method) { Only in cyrus-sasl-2.1.26/saslauthd: lak.c.orig diff -r -u cyrus-sasl-2.1.26.orig/saslauthd/lak.h cyrus-sasl-2.1.26/saslauthd/lak.h --- cyrus-sasl-2.1.26.orig/saslauthd/lak.h 2012-01-28 10:31:36.000000000 +1100 +++ cyrus-sasl-2.1.26/saslauthd/lak.h 2013-01-16 12:02:39.940327523 +1100 @@ -122,6 +122,7 @@ char status; LAK_USER *user; LAK_CONF *conf; + char realm[LAK_BUF_LEN]; } LAK; typedef struct lak_result { diff -r -u cyrus-sasl-2.1.26.orig/saslauthd/LDAP_SASLAUTHD cyrus-sasl-2.1.26/saslauthd/LDAP_SASLAUTHD --- cyrus-sasl-2.1.26.orig/saslauthd/LDAP_SASLAUTHD 2012-01-28 10:31:36.000000000 +1100 +++ cyrus-sasl-2.1.26/saslauthd/LDAP_SASLAUTHD 2013-01-16 12:02:53.497208688 +1100 @@ -8,11 +8,11 @@ 2. Start saslauthd with ldap 3. Testing 4. Parameters -5. Examples -6. Notes -7. Todo -8. Feedback +5. Notes +6. Todo +7. Feedback 8. Author +9. Realm specific parameters 1. BUILD SASLAUTHD WITH LDAP SUPPORT @@ -291,3 +291,44 @@ --------- Igor Brezac <igor@xxxxxxxxx>. + + +9. REALM SPECIFIC PARAMETERS +---------------------------- + +This feature was added by John Newbigin <jnewbigin@xxxxxxxxxxxxxx> + +If you wish to use the supplied realm for more than just a search filter +you can use a new configuration parameter called realm to identify the +values that apply for that realm. + +In you config file, first list gloabl options which apply to all realms. + +Then for each realm which needs specific options, add +realm: <realm_name> +and then the parameters which apply. + +For example, if you have an OID and eDirectory which use different servers +and search options you could do this: + +ldap_timeout: 10 + +realm: oid +ldap_servers: ldap://oidserver.company.com/ +ldap_auth_method: fastbind +ldap_filter: cn=%u,cn=Users,dc=company,dc=com +ldap_scope: one +ldap_search_base: cn=Users,dc=company,dc=com + +realm: edirectory +ldap_servers: ldap://ndsserver.company.com/ +ldap_filter: (cn=%u) +# sub is the default and with the new error checking +# it can't be specified like this +#ldap_scope: sub +ldap_search_base: o=company + +I have also added error checking when reading the config file. Invalid lines, +unknown keys and unknown enumerated values are now rejected and an error logged. +If your config file has errors which you never knew about you must now fix them. +