diff -urN ../cyrus-sasl-2.1.11.orig/saslauthd/LDAP_SASLAUTHD ./saslauthd/LDAP_SASLAUTHD --- ../cyrus-sasl-2.1.11.orig/saslauthd/LDAP_SASLAUTHD Thu Jan 9 19:45:28 2003 +++ ./saslauthd/LDAP_SASLAUTHD Sun Apr 13 09:20:00 2003 @@ -142,11 +142,21 @@ 2. There is no cost to staying bound as a named user ldap_filter: - Specify a filter. Use the %u and %r tokens for the username and realm - substitution. The %u token has to be used at minimum for the filter to - be useful. If ldap_auth_method is 'bind', the filter will search for - the DN (distinguished name) attribute. Otherwise, the search will look - for the userPassword attribute. + Specify a filter. Use the %u, %r and %s tokens for the username, realm + and service substitution. The %u token has to be used at minimum for + the filter to be useful. If ldap_auth_method is 'bind', the filter will + search for the DN (distinguished name) attribute. Otherwise, the search + will look for the userPassword attribute. + +ldap_group_dn: + Specify a group DN. If specified, the user DN has to be part of the group + in order to authenticate successfully. Use the %u, %r and %s tokens for + the username, realm and service substitution. Per default the user DN + is compared against the attribute 'uniqueMember' of the group. + +ldap_group_attr: + Specify what attribute to compare the user DN against in the group. If + ldap_group_dn is not specified, this parameter is ignored. ldap_debug: <0> Specify a debugging level in the OpenLDAP libraries. See diff -urN ../cyrus-sasl-2.1.11.orig/saslauthd/auth_ldap.c ./saslauthd/auth_ldap.c --- ../cyrus-sasl-2.1.11.orig/saslauthd/auth_ldap.c Fri Oct 18 21:16:29 2002 +++ ./saslauthd/auth_ldap.c Sun Apr 13 09:20:00 2003 @@ -59,7 +59,7 @@ /* PARAMETERS */ const char *login, /* I: plaintext authenticator */ const char *password, /* I: plaintext password */ - const char *service __attribute__((unused)), + const char *service, const char *realm /* END PARAMETERS */ ) @@ -75,7 +75,7 @@ } } - rc = lak_authenticate(lak, login, realm, password); + rc = lak_authenticate(lak, login, service, realm, password); if (rc == LAK_OK) { RETURN("OK"); } else { diff -urN ../cyrus-sasl-2.1.11.orig/saslauthd/lak.c ./saslauthd/lak.c --- ../cyrus-sasl-2.1.11.orig/saslauthd/lak.c Thu Jan 9 19:45:28 2003 +++ ./saslauthd/lak.c Sun Apr 13 09:22:23 2003 @@ -64,13 +64,15 @@ static void lak_config_free(LAK_CONF *); static int lak_config(const char *, LAK_CONF **); static int lak_escape(const char *, char **); -static int lak_filter(LAK *, const char *, const char *, char **); +static int lak_filter(LAK *, const char *, const char *, const char *, char **); +static int lak_group(LAK *, const char *, const char *, const char *, char **); +static int lak_substitute(const char *, const char *, const char *, char **, char *); static int lak_connect(LAK *); static int lak_bind(LAK *, char, const char *, const char *); static int lak_search(LAK *, const char *, const char **, LDAPMessage **); -static int lak_auth_custom(LAK *, const char *, const char *, const char *); -static int lak_auth_bind(LAK *, const char *, const char *, const char *); -static int lak_auth_fastbind(LAK *, const char *, const char *, const char *); +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_result_add(LAK *lak, const char *, const char *, LAK_RESULT **); static int lak_check_password(const char *, const char *, void *); static int lak_check_crypt(const char *, const char *, void *); @@ -104,11 +106,11 @@ static int lak_config_read(LAK_CONF *conf, const char *configfile) { FILE *infile; - int i, lineno = 0; - int alloced = 0; + int /*$$$ i, */lineno = 0; + /*$$$ int alloced = 0; */ char buf[4096]; char *p, *key; - char *result; + /*$$$ char *result; */ infile = fopen(configfile, "r"); if (!infile) { @@ -177,6 +179,18 @@ fclose(infile); return LAK_NOMEM; } + } else if (!strcasecmp(key, "ldap_group_dn")) { + conf->group_dn = strdup(p); + if (conf->group_dn == NULL) { + fclose(infile); + return LAK_NOMEM; + } + } else if (!strcasecmp(key, "ldap_group_attr")) { + conf->group_attr = strdup(p); + if (conf->group_attr == NULL) { + fclose(infile); + return LAK_NOMEM; + } } else if (!strcasecmp(key, "ldap_auth_method")) { if (!strcasecmp(p, "custom")) { conf->auth_method = LAK_AUTH_METHOD_CUSTOM; @@ -281,6 +295,10 @@ free(conf->search_base); if (conf->filter != NULL) free(conf->filter); + if (conf->group_dn != NULL) + free(conf->group_dn); + if (conf->group_attr != NULL) + free(conf->group_attr); if (conf->tls_cacert_file != NULL) free(conf->tls_cacert_file); if (conf->tls_cacert_dir != NULL) @@ -303,7 +321,7 @@ { LAK_CONF *conf; int rc = 0; - char *s; + /*$$$ char *s; */ conf = malloc( sizeof(LAK_CONF) ); if (conf == NULL) { @@ -318,6 +336,8 @@ conf->version = LDAP_VERSION3; conf->search_base = ""; conf->filter = "uid=%u"; + conf->group_dn = ""; + conf->group_attr = "uniquemember"; conf->auth_method = LAK_AUTH_METHOD_BIND; conf->timeout.tv_sec = 5; conf->timeout.tv_usec = 0; @@ -398,48 +418,77 @@ * Parts with the strings provided. * %% = % * %u = user + * %s = service * %r = realm * Note: calling function must free memory. */ -static int lak_filter(LAK *lak, const char *username, const char *realm, char **result) +static int lak_filter(LAK *lak, const char *username, const char *service, const char *realm, char **result) +{ + if (lak->conf->filter == NULL) { + syslog(LOG_WARNING|LOG_AUTH, "filter not setup"); + return LAK_FAIL; + } + + return lak_substitute(username, service, realm, result, lak->conf->filter ); +} + +static int lak_group(LAK *lak, const char *username, const char *service, const char *realm, char **result) +{ + if (lak->conf->group_dn == NULL) { + syslog(LOG_WARNING|LOG_AUTH, "group not setup"); + return LAK_FAIL; + } + + return lak_substitute(username, service, realm, result, lak->conf->group_dn ); +} + +static int lak_substitute(const char *username, const char *service, const char *realm, char **result, char *ptr) { char *buf; - char *end, *ptr, *temp; + char *end, *temp; char *ebuf; int rc; /* to permit multiple occurences of username and/or realm in filter */ /* and avoid memory overflow in filter build [eg: (|(uid=%u)(userid=%u)) ] */ - int percents, realm_len, user_len, maxparamlength; - - if (lak->conf->filter == NULL) { - syslog(LOG_WARNING|LOG_AUTH, "filter not setup"); + int percents, realm_len, user_len, service_len, maxparamlength; + + if (ptr == NULL) { + syslog(LOG_WARNING|LOG_AUTH, "string to substitute is empty"); return LAK_FAIL; } + syslog(LOG_DEBUG|LOG_AUTH, "lak_substitute() ptr: <%s>.", ptr); + /* find the longest param of username and realm */ user_len=strlen(username); realm_len=strlen(realm); + service_len=strlen(service); if( user_len > realm_len ) maxparamlength = user_len; else maxparamlength = realm_len; - /* find the number of occurences of percent sign in filter */ - for( percents=0, buf=lak->conf->filter; *buf; buf++ ) { + if (maxparamlength < service_len) + maxparamlength = service_len; + + syslog(LOG_DEBUG|LOG_AUTH, "lak_substitute() username: <%s>; service: <%s>; realm: <%s>", username, service, realm); + + /* find the number of occurences of percent sign in ptr */ + buf = ptr; + for( percents=0; *buf; buf++ ) { if( *buf == '%' ) percents++; } /* percents * 3 * maxparamlength because we need to account for * an entirely-escaped worst-case-length parameter */ - buf=malloc(strlen(lak->conf->filter) + (percents * 3 * maxparamlength) +1); + buf=malloc(strlen(ptr) + (percents * 3 * maxparamlength) +1); if(buf == NULL) { syslog(LOG_ERR|LOG_AUTH, "Cannot allocate memory"); return LAK_NOMEM; } buf[0] = '\0'; - ptr=lak->conf->filter; end = ptr + strlen(ptr); while ((temp=strchr(ptr,'%'))!=NULL ) { @@ -478,6 +527,17 @@ syslog(LOG_WARNING|LOG_AUTH, "Realm not available."); } break; + case 's': + if (service!=NULL) { + rc = lak_escape(service, &ebuf); + if (rc == LAK_OK) { + strcat(buf,ebuf); + free(ebuf); + } + } else { + syslog(LOG_WARNING|LOG_AUTH, "Service not available."); + } + break; default: break; } @@ -488,6 +548,8 @@ *result = buf; + syslog(LOG_DEBUG|LOG_AUTH, "lak_substitute() buf: <%s>.", buf); + return LAK_OK; } @@ -767,7 +829,7 @@ /* * lak_retrieve - retrieve user@realm values specified by 'attrs' */ -int lak_retrieve(LAK *lak, const char *user, const char *realm, const char **attrs, LAK_RESULT **ret) +int lak_retrieve(LAK *lak, const char *user, const char* service, const char *realm, const char **attrs, LAK_RESULT **ret) { int rc = 0, i; char *filter = NULL; @@ -787,7 +849,7 @@ return LAK_FAIL; } - rc = lak_filter(lak, user, realm, &filter); + rc = lak_filter(lak, user, service, realm, &filter); if (rc != LAK_OK) { return LAK_FAIL; } @@ -844,14 +906,14 @@ } -static int lak_auth_custom(LAK *lak, const char *user, const char *realm, const char *password) +static int lak_auth_custom(LAK *lak, const char *user, const char *service, const char *realm, const char *password) { LAK_RESULT *lres, *ptr; int rc; struct password_check *pc; const char *attrs[] = {"userPassword", NULL}; - rc = lak_retrieve(lak, user, realm, attrs, &lres); + rc = lak_retrieve(lak, user, service, realm, attrs, &lres); if (rc != LAK_OK) { return rc; } @@ -872,14 +934,14 @@ } -static int lak_auth_bind(LAK *lak, const char *user, const char *realm, const char *password) +static int lak_auth_bind(LAK *lak, const char *user, const char *service, const char *realm, const char *password) { char *filter; int rc; char *dn; LDAPMessage *res, *entry; - rc = lak_filter(lak, user, realm, &filter); + rc = lak_filter(lak, user, service, realm, &filter); if (rc != LAK_OK) { syslog(LOG_WARNING|LOG_AUTH, "lak_filter failed."); return LAK_FAIL; @@ -912,6 +974,24 @@ rc = lak_bind(lak, LAK_BIND_AS_USER, dn, password); + if (strlen(lak->conf->group_dn) > 0) + { + int r; + char *group; + rc = lak_group(lak, user, service, realm, &group); + if (rc != LAK_OK) { + syslog(LOG_WARNING|LOG_AUTH, "lak_group failed."); + return LAK_FAIL; + } + r = ldap_compare_s(lak->ld, group, lak->conf->group_attr, dn); + free(group); + if (r != LDAP_COMPARE_TRUE) + { + syslog(LOG_WARNING|LOG_AUTH, "ldap_compare_s() for group failed."); + rc = LAK_FAIL; + } + } + ldap_memfree(dn); lak_bind(lak, LAK_BIND_ANONYMOUS, lak->conf->bind_dn, lak->conf->bind_pw); @@ -920,12 +1000,12 @@ } -static int lak_auth_fastbind(LAK *lak, const char *user, const char *realm, const char *password) +static int lak_auth_fastbind(LAK *lak, const char *user, const char *service, const char *realm, const char *password) { int rc; char *dn = NULL; - rc = lak_filter(lak, user, realm, &dn); + rc = lak_filter(lak, user, service, realm, &dn); if (rc != LAK_OK || dn == NULL) { syslog(LOG_WARNING|LOG_AUTH, "lak_filter failed."); return LAK_FAIL; @@ -938,7 +1018,7 @@ } -int lak_authenticate(LAK *lak, const char *user, const char *realm, const char *password) +int lak_authenticate(LAK *lak, const char *user, const char *service, const char *realm, const char *password) { int rc; @@ -952,11 +1032,11 @@ } if (lak->conf->auth_method == LAK_AUTH_METHOD_BIND) { - rc = lak_auth_bind(lak, user, realm, password); + rc = lak_auth_bind(lak, user, service, realm, password); } else if (lak->conf->auth_method == LAK_AUTH_METHOD_CUSTOM) { - rc = lak_auth_custom(lak, user, realm, password); + rc = lak_auth_custom(lak, user, service, realm, password); } else { - rc = lak_auth_fastbind(lak, user, realm, password); + rc = lak_auth_fastbind(lak, user, service, realm, password); } return rc; diff -urN ../cyrus-sasl-2.1.11.orig/saslauthd/lak.h ./saslauthd/lak.h --- ../cyrus-sasl-2.1.11.orig/saslauthd/lak.h Thu Jan 9 19:45:28 2003 +++ ./saslauthd/lak.h Sun Apr 13 09:20:01 2003 @@ -72,6 +72,8 @@ int scope; char *search_base; char *filter; + char *group_dn; /* %r will be replaced by realm */ + char *group_attr; char auth_method; int tls_check_peer; char *tls_cacert_file; @@ -97,8 +99,8 @@ int lak_init(const char *, LAK **); void lak_close(LAK *); -int lak_authenticate(LAK *, const char *, const char *, const char *); -int lak_retrieve(LAK *, const char *, const char *, const char **, LAK_RESULT **); +int lak_authenticate(LAK *, const char *, const char *, const char *, const char *); +int lak_retrieve(LAK *, const char *, const char *, const char *, const char **, LAK_RESULT **); void lak_result_free(LAK_RESULT *); #endif /* _LAK_H */