X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_ldap%2Frlm_ldap.c;h=fabe11802831bdf8b8801860d35a1184ad83ecf7;hb=85e88c91a8dac12781b629576829022f1ef044e6;hp=d156161f3438013aecdf0fb509652682351b7dce;hpb=f78bc076bfc4b4a3b92863bdd27f86e0b9f198bc;p=freeradius.git diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index d156161..fabe118 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -13,180 +13,24 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * This module is based on LDAP patch to Cistron radiusd by James Golovich - * , which in turn was based mostly on a Mysql+Cistron patch - * from - * - * 17 Jan 2000, Adrian Pavlykevych - * - OpenLDAP SDK porting, basic TLS support, LDAP authorization, - * fault tolerance with multiple LDAP server support - * 24 May 2000, Adrian Pavlykevych - * - Converting to new configuration file format, futher improvements - * in fault tolerance, threaded operation - * 12 Dec 2000, Adrian Pavlykevych - * - Added preliminary support for multiple instances - * - moved all instance configuration into dynamicly allocated structure - * - Removed connection maintenance thread and all attempts for multihreading - * the module itself. OpenLDAP SDK is not thread safe when used with shared - * LDAP connection. - * - Added configuration option for defining LDAP attribute of user object, - * which controls remote access. - * 16 Feb 2001, Hannu Laurila - * - LDAP<->RADIUS attribute mappings are now read from a file - * - Support for generic RADIUS check and reply attribute. - * Jun 2001, Kostas Kalevras - * - Fix: check and reply attributes from LDAP _replace_ existing ones - * - Added "default_profile" directive, which points to radiusProfile - * object, which contains default values for RADIUS users - * - Added "profile_attribute" directive, which specifies user object - * attribute pointing to radiusProfile object. - * Nov 2001, Kostas Kalevras - * - Added support for adding the user password to the check. Based on - * the password_header directive rlm_ldap will strip the - * password header if needed. This will make support for CHAP much easier. - * - Added module messages when we reject a user. - * - Added ldap_groupcmp to allow searching for user group membership. - * - Added ldap_xlat to allow ldap urls in xlat strings. Something like: - * %{ldap:ldap:///dc=company,dc=com?cn?sub?uid=user} - * Nov 2001, Gordon Tetlow - * - Do an xlat on the access_group attribute. - * Dec 2001, Kostas Kalevras - * - Added ldap caching for the default/regular profiles and group entries. - * - Fixed a memory leak in ldap_xlat. - * - Removed dict_attrbyname from ldap_pairget. They are not needed. - * - Moved the radius_xlat's for filter and basedn in ldap_authenticate() to - * the right place. - * - Made the module thread safe. We create a connection pool and each thread - * will call ldap_get_conn to lock one of the ldap connections and release with - * a call to ldap_release_conn when it has finished. - * - Request only the user attributes that interest us (radius attributes,regular - * profile,user password and access attribute). - * Mar 2002, Kostas Kalevras - * - Fixed a bug where the ldap server will kill the idle connections from the ldap - * connection pool. We now check if ldap_search returns LDAP_SERVER_DOWN and try to - * reconnect if it does. Bug noted by Dan Perik - * May 2002, Kostas Kalevras - * - Instead of the Group attribute we now have the Ldap-Group attribute, to avoid - * collisions with other modules - * - If perform_search fails check the ld != NULL before using it. Based on a bug report - * by John - * Jun 2002, Kostas Kalevras - * - Add the ability to do a paircmp on the check items. Add a compare_check_items boolean - * configuration directive which defaults to no. If it is set then we will do a compare - * - Add another configuration directive. access_attr_used_for_allow. If it is set to yes - * then the access_attr will be used to allow user access. If it is set to no then it will - * be used to deny user access. - * - Remember to free inst->atts in ldap_detach() - * - Add a forgotten ldap_free_urldesc in ldap_xlat() - * - Add a variable locked in the LDAP_CONN structure. We use this to avoid deadlocks. The mutex - * we are using is of type fast and can deadlock if the same thread tries to relock it. That - * could happen in case of calls to xlat. - * - When ldap_search returns NO_SUCH_OBJECT don't return fail but notfound - * Jul 2002, Kostas Kalevras - * - Fix the logic when we get an LDAP_SERVER_DOWN or we have conn->ld == NULL in perform_search - * - Try to minimize the penalty of having the ldap server go down. The comments before - * MAX_FAILED_CONNS_* definitions should explain things. - * - Check for a number of error codes from ldap_search and log corresponding error messages - * We should only reconnect when that can help things. - * - In ldap_groupcmp instead of first searching for the group object and then checking user - * group membership combine them in one ldap search operation. That should make group - * membership checks a lot faster. - * - Remember to do ldap_release_conn and ldap_msgfree when we do paircmp and the result is reject - * Aug 2002, Kostas Kalevras - * - Add support for group membership attribute inside the user entry in ldap_groupcmp. The attribute - * can either contain the name or the DN of the group. Added the groupmembership_attribute - * configuration directive - * - Move the ldap_{get,release}_conn in ldap_groupcmp so that we hold a connection for the minimum time. - * - Now that ldap_groupcmp is complete we really don't need access_group. Removed it. - * - Remember to free groupmembership_attribute in ldap_detach - * - Don't delete existing generic attributes in ldap_pairget when adding new ones. Since generic attributes - * have operators we don't need to try to be cleaver. - * Sep 2002, Kostas Kalevras - * - Fix a crash in ldap_pairget when the attribute value is larger than the buffer size - * Bug report by Stefan Radovanovici - * - If we add a check item then use the == operator. Based on an idea by Allister Maguire - * - Only add a failure message for bind as user failed in ldap_authenticate if the result of ldap_connect was - * RLM_MODULE_REJECT - * - Make tls_mode a configurable option. Patch from John - * - Allow multiple regular profiles for an entry - * Oct 2002, Kostas Kalevras - * - Disable cache after searching for the default profile - * - Use the MAX_FAILED_CONNS_* in ldap_authenticate() when calling ldap_connect() - * Nov 2002, Kostas Kalevras - * - Set LDAP version to V3 before binding. Now freeradius should work with openldap21 - * Dec 2002, Kostas Kalevras - * - Set default values for the server and basedn parameters - * Feb 2003, Kostas Kalevras - * - Add support for ldap_initialize. That way we can specify the server as an ldap url. - * Based on ideas from Derrik Pates - * Mar 2003, Kostas Kalevras - * - Add an ldap_escape_func. Escape the * character from the filter so that we can avoid - * the trivial DoS of username=* - * - Remove the caching code. It does not exist in openldap21. - * Based on a report from Mike Denka - * May 2003, Kostas Kalevras - * - Don't do a double free on the attribute maps. Bug noted by Derrik Pates - * - Apply a patch from Alexander M. Pravking to do an xlat on the - * retrieved attributes. - * Aug 2003, Kostas Kalevras - * - In case of a bad search filter, print out the corresponding filter - * Sep 2003, Kostas Kalevras - * - Compile even if we don't have pthread's - * Oct 2003, Kostas Kalevras - * - Add a new configuration directive, base_filter which is used for base scope searches - * (When searching for the default/regular profiles for example) - * Nov 2003, Kostas Kalevras - * - Add a new configuration directive, do_xlat (default: yes). If set we use pairxlatmove - * on the radius attributes, else we fall back to the plain old pairadd. That way people - * can fall back on the 0.8.1 behaviour without making changes to their ldap database or - * gain a little performance by not using pairxlatmove - * Dec 2003, Kostas Kalevras - * - Add a patch from Jon Miner to add the ability to configure - * various LDAP TLS options - * - Only call pairfree if we are using pairxlatmove not for pairadd - * Mar 2004, Kostas Kalevras - * - If we are passed an empty password log a module failure message not an error message - * Apr 2004, Kostas Kalveras - * - Add a patch from Tarun Bhushan to add a tls_mode boolean - * directive so that we can enable TLS connetions even if port is not set to 636 - * - Add an error message if ldap_initialize() is not available and we are passed a URL like - * 'server' directive. - * - Add a per instance Ldap-Group attribute (of the form -Ldap-Group) and register - * a corresponding ldap_groupcmp function - * - Small change to ldap_get_conn to fix problems on some platforms + * Copyright 2004,2006 The FreeRADIUS Server Project. */ -static const char rcsid[] = "$Id$"; -#include "autoconf.h" +#include +RCSID("$Id$") -#include -#include -#include -#include +#include +#include +#include -#include -#include -#include #include -#include #include -#include #include #include -#include -#include -#include - -#include "libradius.h" -#include "radiusd.h" -#include "conffile.h" -#include "modules.h" -#include "rad_assert.h" - #ifndef HAVE_PTHREAD_H /* * This is a lot simpler than putting ifdef's around @@ -197,6 +41,8 @@ static const char rcsid[] = "$Id$"; #define pthread_mutex_unlock(a) #define pthread_mutex_init(a,b) #define pthread_mutex_destroy(a) +#else +#include #endif @@ -245,10 +91,22 @@ int nmasldap_get_password( #endif +#ifdef NOVELL + +#define REQUEST_ACCEPTED 0 +#define REQUEST_CHALLENGED 1 +#define REQUEST_REJECTED 2 +#define MAX_CHALLENGE_LEN 128 + +int radLdapXtnNMASAuth( LDAP *, char *, char *, char *, char *, size_t *, char *, int * ); + +#endif + /* linked list of mappings between RADIUS attributes and LDAP attributes */ struct TLDAP_RADIUS { char* attr; char* radius_attr; + FR_TOKEN operator; struct TLDAP_RADIUS* next; }; typedef struct TLDAP_RADIUS TLDAP_RADIUS; @@ -267,8 +125,8 @@ typedef struct { char *server; int port; int timelimit; - struct timeval net_timeout; - struct timeval timeout; + int net_timeout; + int timeout; int debug; int tls_mode; int start_tls; @@ -278,6 +136,8 @@ typedef struct { int default_allow; int failed_conns; int is_url; + int chase_referrals; + int rebind; char *login; char *password; char *filter; @@ -286,7 +146,6 @@ typedef struct { char *default_profile; char *profile_attr; char *access_attr; - char *passwd_hdr; char *passwd_attr; char *dictionary_mapping; char *groupname_attr; @@ -301,6 +160,7 @@ typedef struct { #endif int ldap_debug; /* Debug flag for LDAP SDK */ char *xlat_name; /* name used to xlat */ + char *auth_type; char *tls_cacertfile; char *tls_cacertdir; char *tls_certfile; @@ -308,57 +168,177 @@ typedef struct { char *tls_randfile; char *tls_require_cert; #ifdef NOVELL - int edir_account_policy_check; + int edir_account_policy_check; #endif - int set_auth_type; -} ldap_instance; + int set_auth_type; + + /* + * For keep-alives. + */ +#ifdef LDAP_OPT_X_KEEPALIVE_IDLE + int keepalive_idle; +#endif +#ifdef LDAP_OPT_X_KEEPALIVE_PROBES + int keepalive_probes; +#endif +#ifdef LDAP_OPT_ERROR_NUMBER + int keepalive_interval; +#endif + +} ldap_instance; /* The default setting for TLS Certificate Verification */ #define TLS_DEFAULT_VERIFY "allow" -static CONF_PARSER module_config[] = { - {"server", PW_TYPE_STRING_PTR, offsetof(ldap_instance,server), NULL, "localhost"}, - {"port", PW_TYPE_INTEGER, offsetof(ldap_instance,port), NULL, "389"}, +static CONF_PARSER keepalive_config[] = { +#ifdef LDAP_OPT_X_KEEPALIVE_IDLE + {"idle", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_idle), NULL, "60"}, +#endif +#ifdef LDAP_OPT_X_KEEPALIVE_PROBES + {"probes", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_probes), NULL, "3"}, +#endif +#ifdef LDAP_OPT_ERROR_NUMBER + {"interval", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_interval), NULL, "30"}, +#endif + + { NULL, -1, 0, NULL, NULL } +}; + +static CONF_PARSER tls_config[] = { + {"start_tls", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,start_tls), NULL, "no"}, + {"cacertfile", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_cacertfile), NULL, NULL}, + {"cacertdir", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_cacertdir), NULL, NULL}, + {"certfile", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_certfile), NULL, NULL}, + {"keyfile", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_keyfile), NULL, NULL}, + {"randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */ + offsetof(ldap_instance,tls_randfile), NULL, NULL}, + {"require_cert", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY}, + { NULL, -1, 0, NULL, NULL } +}; + +static const CONF_PARSER module_config[] = { + {"server", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,server), NULL, "localhost"}, + {"port", PW_TYPE_INTEGER, + offsetof(ldap_instance,port), NULL, "389"}, + {"password", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,password), NULL, ""}, + {"identity", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,login), NULL, ""}, + + /* + * Timeouts & stuff. + */ /* wait forever on network activity */ - {"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"}, + {"net_timeout", PW_TYPE_INTEGER, + offsetof(ldap_instance,net_timeout), NULL, "10"}, /* wait forever for search results */ - {"timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,timeout.tv_sec), NULL, "20"}, + {"timeout", PW_TYPE_INTEGER, + offsetof(ldap_instance,timeout), NULL, "20"}, /* allow server unlimited time for search (server-side limit) */ - {"timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance,timelimit), NULL, "20"}, - {"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance,login), NULL, ""}, - {"tls_mode", PW_TYPE_BOOLEAN, offsetof(ldap_instance,tls_mode), NULL, "no"}, - {"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance,start_tls), NULL, "no"}, - {"tls_cacertfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertfile), NULL, NULL}, - {"tls_cacertdir", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertdir), NULL, NULL}, - {"tls_certfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_certfile), NULL, NULL}, - {"tls_keyfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_keyfile), NULL, NULL}, - {"tls_randfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_randfile), NULL, NULL}, - {"tls_require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY}, - {"password", PW_TYPE_STRING_PTR, offsetof(ldap_instance,password), NULL, ""}, - {"basedn", PW_TYPE_STRING_PTR, offsetof(ldap_instance,basedn), NULL, "o=notexist"}, - {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,filter), NULL, "(uid=%u)"}, - {"base_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"}, - {"default_profile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,default_profile), NULL, NULL}, - {"profile_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,profile_attr), NULL, NULL}, - {"password_header", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_hdr), NULL, NULL}, - {"password_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_attr), NULL, NULL}, + {"timelimit", PW_TYPE_INTEGER, + offsetof(ldap_instance,timelimit), NULL, "20"}, + + /* + * TLS configuration The first few are here for backwards + * compatibility. The last is the new subsection. + */ + {"tls_mode", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,tls_mode), NULL, "no"}, + + {"start_tls", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,start_tls), NULL, "no"}, + {"tls_cacertfile", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_cacertfile), NULL, NULL}, + {"tls_cacertdir", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_cacertdir), NULL, NULL}, + {"tls_certfile", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_certfile), NULL, NULL}, + {"tls_keyfile", PW_TYPE_FILENAME, + offsetof(ldap_instance,tls_keyfile), NULL, NULL}, + {"tls_randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */ + offsetof(ldap_instance,tls_randfile), NULL, NULL}, + {"tls_require_cert", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY}, + { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config }, + + /* + * DN's and filters. + */ + {"basedn", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,basedn), NULL, "o=notexist"}, + {"filter", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,filter), NULL, "(uid=%u)"}, + {"base_filter", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"}, + {"default_profile", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,default_profile), NULL, NULL}, + {"profile_attribute", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,profile_attr), NULL, NULL}, + + /* + * Getting passwords from the database + */ + {"password_attribute", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,passwd_attr), NULL, NULL}, + + /* + * Access limitations + */ /* LDAP attribute name that controls remote access */ - {"access_attr", PW_TYPE_STRING_PTR, offsetof(ldap_instance,access_attr), NULL, NULL}, + {"access_attr", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,access_attr), NULL, NULL}, + {"access_attr_used_for_allow", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,default_allow), NULL, "yes"}, + {"chase_referrals", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,chase_referrals), NULL, NULL}, + {"rebind", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,rebind), NULL, NULL}, + + /* + * Group checks. These could probably be done + * via dynamic xlat's. + */ + {"groupname_attribute", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,groupname_attr), NULL, "cn"}, + {"groupmembership_filter", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"}, + {"groupmembership_attribute", PW_TYPE_STRING_PTR, + offsetof(ldap_instance,groupmemb_attr), NULL, NULL}, + /* file with mapping between LDAP and RADIUS attributes */ - {"groupname_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupname_attr), NULL, "cn"}, - {"groupmembership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"}, - {"groupmembership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_attr), NULL, NULL}, - {"dictionary_mapping", PW_TYPE_STRING_PTR, offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"}, - {"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance,ldap_debug), NULL, "0x0000"}, - {"ldap_connections_number", PW_TYPE_INTEGER, offsetof(ldap_instance,num_conns), NULL, "5"}, - {"compare_check_items", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_comp), NULL, "no"}, - {"access_attr_used_for_allow", PW_TYPE_BOOLEAN, offsetof(ldap_instance,default_allow), NULL, "yes"}, - {"do_xlat", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_xlat), NULL, "yes"}, + {"dictionary_mapping", PW_TYPE_FILENAME, + offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"}, + + /* + * Debugging flags to the server + */ + {"ldap_debug", PW_TYPE_INTEGER, + offsetof(ldap_instance,ldap_debug), NULL, "0x0000"}, + {"ldap_connections_number", PW_TYPE_INTEGER, + offsetof(ldap_instance,num_conns), NULL, "5"}, + {"compare_check_items", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,do_comp), NULL, "no"}, + {"do_xlat", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,do_xlat), NULL, "yes"}, + #ifdef NOVELL - {"edir_account_policy_check", PW_TYPE_BOOLEAN, offsetof(ldap_instance,edir_account_policy_check), NULL, "yes"}, + /* + * Novell magic. + */ + {"edir_account_policy_check", PW_TYPE_BOOLEAN, + offsetof(ldap_instance,edir_account_policy_check), NULL, "yes"}, #endif {"set_auth_type", PW_TYPE_BOOLEAN, offsetof(ldap_instance,set_auth_type), NULL, "yes"}, + + { "keepalive", PW_TYPE_SUBSECTION, 0, NULL, (const void *) keepalive_config }, {NULL, -1, 0, NULL, NULL} }; @@ -369,23 +349,31 @@ static CONF_PARSER module_config[] = { #ifdef FIELDCPY static void fieldcpy(char *, char **); #endif -static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,char); +static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,int, ldap_instance *); static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **); -static int ldap_xlat(void *, REQUEST *, char *, char *, size_t, RADIUS_ESCAPE_STRING); +static size_t ldap_xlat(void *, REQUEST *, char *, char *, size_t, RADIUS_ESCAPE_STRING); static LDAP *ldap_connect(void *instance, const char *, const char *, int, int *, char **); static int read_mappings(ldap_instance* inst); -static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance) +static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret, + ldap_instance *inst) { - ldap_instance *inst = instance; register int i = 0; for(i=0;inum_conns;i++){ - DEBUG("rlm_ldap: ldap_get_conn: Checking Id: %d",i); - if (conns[i].locked == 0 && pthread_mutex_trylock(&(conns[i].mutex)) == 0){ + DEBUG(" [%s] ldap_get_conn: Checking Id: %d", + inst->xlat_name, i); + if ((pthread_mutex_trylock(&conns[i].mutex) == 0)) { + if (conns[i].locked == 1) { + /* connection is already being used */ + pthread_mutex_unlock(&(conns[i].mutex)); + continue; + } + /* found an unused connection */ *ret = &conns[i]; conns[i].locked = 1; - DEBUG("rlm_ldap: ldap_get_conn: Got Id: %d",i); + DEBUG(" [%s] ldap_get_conn: Got Id: %d", + inst->xlat_name, i); return i; } } @@ -393,12 +381,27 @@ static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance) return -1; } -static inline void ldap_release_conn(int i, LDAP_CONN *conns) +static inline void ldap_release_conn(int i, ldap_instance *inst) + +{ + LDAP_CONN *conns = inst->conns; + + DEBUG(" [%s] ldap_release_conn: Release Id: %d", inst->xlat_name, i); + conns[i].locked = 0; + pthread_mutex_unlock(&(conns[i].mutex)); +} + +#ifdef NOVELL +static inline void ldap_release_apc_conn(int i, ldap_instance *inst) + { - DEBUG("rlm_ldap: ldap_release_conn: Release Id: %d",i); + LDAP_CONN *conns = inst->apc_conns; + + DEBUG(" [%s] ldap_release_conn: Release Id: %d", inst->xlat_name, i); conns[i].locked = 0; pthread_mutex_unlock(&(conns[i].mutex)); } +#endif /************************************************************************* * @@ -419,14 +422,15 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) int att_map[3] = {0,0,0}; TLDAP_RADIUS *pair; ATTR_FLAGS flags; - char *xlat_name; - DICT_VALUE *dv; + const char *xlat_name; inst = rad_malloc(sizeof *inst); if (!inst) { return -1; } memset(inst, 0, sizeof(*inst)); + inst->chase_referrals = 2; /* use OpenLDAP defaults */ + inst->rebind = 2; if (cf_section_parse(conf, inst, module_config) < 0) { free(inst); @@ -435,7 +439,7 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) if (inst->server == NULL) { radlog(L_ERR, "rlm_ldap: missing 'server' directive."); - free(inst); + free(inst); /* FIXME: detach */ return -1; } inst->is_url = 0; @@ -445,13 +449,11 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) inst->port = 0; #else radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but ldap_initialize() is not available."); - free(inst); + free(inst); /* FIXME: detach */ return -1; #endif } - inst->timeout.tv_usec = 0; - inst->net_timeout.tv_usec = 0; /* workaround for servers which support LDAPS but not START TLS */ if(inst->port == LDAPS_PORT || inst->tls_mode) inst->tls_mode = LDAP_OPT_X_TLS_HARD; @@ -462,6 +464,19 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) inst->conns = NULL; inst->failed_conns = 0; +#if LDAP_SET_REBIND_PROC_ARGS != 3 + /* + * The 2-argument rebind doesn't take an instance + * variable. Our rebind function needs the instance + * variable for the username, password, etc. + */ + if (inst->rebind == 1) { + radlog(L_ERR, "rlm_ldap: Cannot use 'rebind' directive as this version of libldap does not support the API that we need."); + free(inst); + return -1; + } +#endif + DEBUG("rlm_ldap: Registering ldap_groupcmp for Ldap-Group"); paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst); memset(&flags, 0, sizeof(flags)); @@ -474,19 +489,20 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) /* * Allocate room for -Ldap-Group */ - group_name = malloc((strlen(xlat_name) + 1 + 11) * sizeof(char)); - rad_assert(group_name != NULL); + group_name = rad_malloc((strlen(xlat_name) + 1 + 11) * sizeof(char)); sprintf(group_name,"%s-Ldap-Group",xlat_name); DEBUG("rlm_ldap: Creating new attribute %s",group_name); - dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags); + dict_addattr(group_name, -1, 0, PW_TYPE_STRING, flags); dattr = dict_attrbyname(group_name); if (dattr == NULL){ radlog(L_ERR, "rlm_ldap: Failed to create attribute %s",group_name); - free(inst); + free(group_name); + free(inst); /* FIXME: detach */ return -1; } DEBUG("rlm_ldap: Registering ldap_groupcmp for %s",group_name); paircompare_register(dattr->attr, PW_USER_NAME, ldap_groupcmp, inst); + free(group_name); } else { xlat_name = cf_section_name1(conf); @@ -501,42 +517,60 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) * This automagically catches the case where LDAP is listed * in "authorize", but not "authenticate". */ - dv = dict_valbyname(PW_AUTH_TYPE, xlat_name); - if (!dv) { - if (inst->set_auth_type) { - DEBUG2("rlm_ldap: Over-riding set_auth_type, as we're not listed in the \"authenticate\" section."); + if (inst->set_auth_type) { + DICT_VALUE *dv = dict_valbyname(PW_AUTH_TYPE, 0, xlat_name); + + /* + * No section of *my* name, but maybe there's an + * LDAP section... + */ + if (!dv) dv = dict_valbyname(PW_AUTH_TYPE, 0, "LDAP"); + if (!dv) { + DEBUG2("rlm_ldap: Over-riding set_auth_type, as there is no module %s listed in the \"authenticate\" section.", xlat_name); + inst->set_auth_type = 0; + } else { + inst->auth_type = dv->name; /* doesn't change on HUP */ } - inst->set_auth_type = 0; - } + } /* else no need to look up the value */ #ifdef NOVELL /* - * (LDAP_Instance, V1) attribute-value pair in the config items list means - * that the 'authorize' method of the instance 'V1' of the LDAP module has - * processed this request. + * (LDAP_Instance, V1) attribute-value pair in the config + * items list means that the 'authorize' method of the + * instance 'V1' of the LDAP module has processed this + * request. + */ + dict_addattr("LDAP-Instance", -1, 0, PW_TYPE_STRING, flags); + + /* + * ('eDir-APC', '1') in config items list + * Do not perform eDirectory account policy check (APC) + * + * ('eDir-APC', '2') in config items list + * Perform eDirectory APC + * + * ('eDir-APC', '3') in config items list + * eDirectory APC has been completed */ - dict_addattr("LDAP-Instance", 0, PW_TYPE_STRING, -1, flags); + dict_addattr("eDir-APC", -1, 0, PW_TYPE_STRING, flags); /* - * ('eDir-APC', '1') in config items list => Do not perform eDirectory account - * policy check (APC) - * ('eDir-APC', '2') in config items list => Perform eDirectory APC - * ('eDir-APC', '3') in config items list => eDirectory APC has been completed + * eDir-Auth-Option allows for a different NMAS Authentication method to be used instead of password */ - dict_addattr("eDir-APC", 0, PW_TYPE_STRING, -1, flags); + dict_addattr("eDir-Auth-Option", -1, 0, PW_TYPE_STRING, flags); #endif if (inst->num_conns <= 0){ radlog(L_ERR, "rlm_ldap: Invalid ldap connections number passed."); - free(inst); + free(inst); /* FIXME: detach */ return -1; } - inst->conns = (LDAP_CONN *)malloc(sizeof(LDAP_CONN)*inst->num_conns); + inst->conns = malloc(sizeof(*(inst->conns))*inst->num_conns); if (inst->conns == NULL){ radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); - free(inst); + free(inst); /* FIXME: detach */ return -1; } - for(;inum_conns;i++){ + for(i = 0; i < inst->num_conns; i++){ inst->conns[i].bound = 0; inst->conns[i].locked = 0; inst->conns[i].failed_conns = 0; @@ -546,15 +580,16 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) #ifdef NOVELL /* - * 'inst->apc_conns' is a separate connection pool to be used for performing - * eDirectory account policy check in the 'postauth' method. This avoids - * changing the (RADIUS server) credentials associated with the 'inst->conns' - * connection pool. + * 'inst->apc_conns' is a separate connection pool to be + * used for performing eDirectory account policy check in + * the 'postauth' method. This avoids changing the + * (RADIUS server) credentials associated with the + * 'inst->conns' connection pool. */ - inst->apc_conns = (LDAP_CONN *)malloc(sizeof(LDAP_CONN)*inst->num_conns); + inst->apc_conns = malloc(sizeof(*(inst->apc_conns))*inst->num_conns); if (inst->apc_conns == NULL){ radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); - free(inst); + free(inst); /* FIXME: detach */ return -1; } for(i = 0; i < inst->num_conns; i++){ @@ -569,13 +604,14 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) if (read_mappings(inst) != 0) { radlog(L_ERR, "rlm_ldap: Reading dictionary mappings from file %s failed", inst->dictionary_mapping); - free(inst); + free(inst); /* FIXME: detach */ return -1; } - if (inst->check_item_map == NULL && inst->reply_item_map == NULL){ + if ((inst->check_item_map == NULL) && + (inst->reply_item_map == NULL)) { radlog(L_ERR, "rlm_ldap: dictionary mappings file %s did not contain any mappings", inst->dictionary_mapping); - free(inst); + free(inst); /* FIXME: detach */ return -1; } @@ -597,16 +633,23 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) atts_num++; if (inst->access_attr) atts_num++; +#ifdef NOVELL + atts_num++; /* eDirectory Authentication Option attribute */ +#endif inst->atts = (char **)malloc(sizeof(char *)*(atts_num + 1)); if (inst->atts == NULL){ radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); - free(inst); + free(inst); /* FIXME: detach */ return -1; } pair = inst->check_item_map; if (pair == NULL) pair = inst->reply_item_map; - for(i=0;iatts[i] = pair->attr; if (i == check_map_num) @@ -633,6 +676,9 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) } } } +#ifdef NOVELL + inst->atts[atts_num - 1] = "sasdefaultloginsequence"; +#endif inst->atts[atts_num] = NULL; DEBUG("conns: %p",inst->conns); @@ -645,9 +691,9 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) /* - * read_mappings(...) reads a ldap<->radius mappings file to inst->reply_item_map and inst->check_item_map + * read_mappings(...) reads a ldap<->radius mappings file to + * inst->reply_item_map and inst->check_item_map */ - #define MAX_LINE_LEN 160 #define GENERIC_ATTRIBUTE_ID "$GENERIC$" @@ -656,9 +702,16 @@ read_mappings(ldap_instance* inst) { FILE* mapfile; char *filename; - /* all buffers are of MAX_LINE_LEN so we can use sscanf without being afraid of buffer overflows */ - char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN], radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN]; + + /* + * All buffers are of MAX_LINE_LEN so we can use sscanf + * without being afraid of buffer overflows + */ + char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN]; + char radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN]; int linenumber; + FR_TOKEN operator; + char opstring[MAX_LINE_LEN]; /* open the mappings file for reading */ @@ -667,12 +720,15 @@ read_mappings(ldap_instance* inst) mapfile = fopen(filename, "r"); if (mapfile == NULL) { - radlog(L_ERR, "rlm_ldap: Opening file %s failed", filename); + radlog(L_ERR, "rlm_ldap: Opening file %s failed: %s", + filename, strerror(errno)); return -1; /* error */ } - /* read file line by line. Note that if line length exceed MAX_LINE_LEN, line numbers will be mixed up */ - + /* + * read file line by line. Note that if line length + * exceeds MAX_LINE_LEN, line numbers will be mixed up + */ linenumber = 0; while (fgets(buf, sizeof buf, mapfile)!=NULL) { @@ -690,23 +746,39 @@ read_mappings(ldap_instance* inst) if (buf[0] == 0) continue; /* extract tokens from the string */ - token_count = sscanf(buf, "%s %s %s", itemType, radiusAttribute, ldapAttribute); + token_count = sscanf(buf, "%s %s %s %s", + itemType, radiusAttribute, + ldapAttribute, opstring); if (token_count <= 0) /* no tokens */ continue; - if (token_count != 3) { - radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s", filename, linenumber, buf); - radlog(L_ERR, "rlm_ldap: Expected 3 tokens " + if ((token_count < 3) || (token_count > 4)) { + radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s", + filename, linenumber, buf); + radlog(L_ERR, "rlm_ldap: Expected 3 to 4 tokens " "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count); continue; } + if (token_count == 3) { + operator = T_OP_INVALID; /* use defaults */ + } else { + ptr = opstring; + operator = gettoken(&ptr, buf, sizeof(buf)); + if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) { + radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown or invalid operator %s", + filename, linenumber, opstring); + continue; + } + } + /* create new TLDAP_RADIUS list node */ - pair = rad_malloc(sizeof(TLDAP_RADIUS)); + pair = rad_malloc(sizeof(*pair)); pair->attr = strdup(ldapAttribute); pair->radius_attr = strdup(radiusAttribute); + pair->operator = operator; if ( (pair->attr == NULL) || (pair->radius_attr == NULL) ) { radlog(L_ERR, "rlm_ldap: Out of memory"); @@ -742,19 +814,21 @@ read_mappings(ldap_instance* inst) return 0; /* success */ } -static int -perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, char *filter, - char **attrs, LDAPMessage ** result) +static int perform_search(void *instance, LDAP_CONN *conn, + char *search_basedn, int scope, char *filter, + char **attrs, LDAPMessage ** result) { int res = RLM_MODULE_OK; int ldap_errno = 0; ldap_instance *inst = instance; int search_retry = 0; + struct timeval tv; *result = NULL; if (!conn){ - radlog(L_ERR, "rlm_ldap: NULL connection handle passed"); + radlog(L_ERR, " [%s] NULL connection handle passed", + inst->xlat_name); return RLM_MODULE_FAIL; } if (conn->failed_conns > MAX_FAILED_CONNS_START){ @@ -766,14 +840,16 @@ perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, } retry: if (!conn->bound || conn->ld == NULL) { - DEBUG2("rlm_ldap: attempting LDAP reconnection"); + DEBUG2(" [%s] attempting LDAP reconnection", inst->xlat_name); if (conn->ld){ - DEBUG2("rlm_ldap: closing existing LDAP connection"); + DEBUG2(" [%s] closing existing LDAP connection", + inst->xlat_name); ldap_unbind_s(conn->ld); } if ((conn->ld = ldap_connect(instance, inst->login, inst->password, 0, &res, NULL)) == NULL) { - radlog(L_ERR, "rlm_ldap: (re)connection attempt failed"); + radlog(L_ERR, " [%s] (re)connection attempt failed", + inst->xlat_name); if (search_retry == 0) conn->failed_conns++; return (RLM_MODULE_FAIL); @@ -781,17 +857,22 @@ retry: conn->bound = 1; conn->failed_conns = 0; } - DEBUG2("rlm_ldap: performing search in %s, with filter %s", search_basedn ? search_basedn : "(null)" , filter); - switch (ldap_search_st(conn->ld, search_basedn, scope, filter, attrs, 0, &(inst->timeout), result)) { + + tv.tv_sec = inst->timeout; + tv.tv_usec = 0; + DEBUG2(" [%s] performing search in %s, with filter %s", inst->xlat_name, + search_basedn ? search_basedn : "(null)" , filter); + switch (ldap_search_st(conn->ld, search_basedn, scope, filter, + attrs, 0, &tv, result)) { case LDAP_SUCCESS: case LDAP_NO_SUCH_OBJECT: break; case LDAP_SERVER_DOWN: - radlog(L_ERR, "rlm_ldap: ldap_search() failed: LDAP connection lost."); + radlog(L_ERR, " [%s] ldap_search() failed: LDAP connection lost.", inst->xlat_name); conn->failed_conns++; if (search_retry == 0){ if (conn->failed_conns <= MAX_FAILED_CONNS_START){ - radlog(L_INFO, "rlm_ldap: Attempting reconnect"); + radlog(L_INFO, " [%s] Attempting reconnect", inst->xlat_name); search_retry = 1; conn->bound = 0; ldap_msgfree(*result); @@ -801,15 +882,15 @@ retry: ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_INSUFFICIENT_ACCESS: - radlog(L_ERR, "rlm_ldap: ldap_search() failed: Insufficient access. Check the identity and password configuration directives."); + radlog(L_ERR, " [%s] ldap_search() failed: Insufficient access. Check the identity and password configuration directives.", inst->xlat_name); ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_TIMEOUT: - radlog(L_ERR, "rlm_ldap: ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout."); + radlog(L_ERR, " [%s] ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.", inst->xlat_name); ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_FILTER_ERROR: - radlog(L_ERR, "rlm_ldap: ldap_search() failed: Bad search filter: %s",filter); + radlog(L_ERR, " [%s] ldap_search() failed: Bad search filter: %s", inst->xlat_name,filter); ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_TIMELIMIT_EXCEEDED: @@ -817,19 +898,26 @@ retry: case LDAP_UNAVAILABLE: /* We don't need to reconnect in these cases so we don't set conn->bound */ ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); - radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno)); + radlog(L_ERR, " [%s] ldap_search() failed: %s", inst->xlat_name, + ldap_err2string(ldap_errno)); ldap_msgfree(*result); return (RLM_MODULE_FAIL); default: ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); - radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno)); + radlog(L_ERR, " [%s] ldap_search() failed: %s", inst->xlat_name, + ldap_err2string(ldap_errno)); conn->bound = 0; ldap_msgfree(*result); return (RLM_MODULE_FAIL); } - if ((ldap_count_entries(conn->ld, *result)) != 1) { - DEBUG("rlm_ldap: object not found or got ambiguous search result"); + ldap_errno = ldap_count_entries(conn->ld, *result); + if (ldap_errno != 1) { + if (ldap_errno == 0) { + DEBUG(" [%s] object not found", inst->xlat_name); + } else { + DEBUG(" [%s] got ambiguous search result (%d results)", inst->xlat_name, ldap_errno); + } res = RLM_MODULE_NOTFOUND; ldap_msgfree(*result); } @@ -840,9 +928,9 @@ retry: /* * Translate the LDAP queries. */ -static int ldap_escape_func(char *out, int outlen, const char *in) +static size_t ldap_escape_func(char *out, size_t outlen, const char *in) { - int len = 0; + size_t len = 0; while (in[0]) { /* @@ -888,11 +976,12 @@ static int ldap_escape_func(char *out, int outlen, const char *in) } /* - * ldap_groupcmp(). Implement the Ldap-Group == "group" filter + * ldap_groupcmp(). Implement the Ldap-Group == "group" filter */ - -static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, - VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs) +static int ldap_groupcmp(void *instance, REQUEST *req, + UNUSED VALUE_PAIR *request, VALUE_PAIR *check, + UNUSED VALUE_PAIR *check_pairs, + UNUSED VALUE_PAIR **reply_pairs) { char filter[MAX_FILTER_STR_LEN]; char gr_filter[MAX_FILTER_STR_LEN]; @@ -909,11 +998,11 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALU VALUE_PAIR *vp_user_dn; VALUE_PAIR **request_pairs; - request_pairs = &req->packet->vps; + request_pairs = &req->config_items; - DEBUG("rlm_ldap: Entering ldap_groupcmp()"); + DEBUG(" [%s] Entering ldap_groupcmp()", inst->xlat_name); - if (check->strvalue == NULL || check->length == 0){ + if (check->vp_strvalue == NULL || check->length == 0){ DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name"); return 1; } @@ -928,7 +1017,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALU return 1; } - while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN)) == NULL){ + while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN, 0)) == NULL){ char *user_dn = NULL; if (!radius_xlat(filter, sizeof(filter), inst->filter, @@ -937,64 +1026,69 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALU return 1; } if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ - radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); return 1; } if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK){ DEBUG("rlm_ldap::ldap_groupcmp: search failed"); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 1; } if ((msg = ldap_first_entry(conn->ld, result)) == NULL) { DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed"); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); ldap_msgfree(result); return 1; } if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) { DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed"); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); ldap_msgfree(result); return 1; } - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); + /* - * Adding new attribute containing DN for LDAP object associated with - * given username - */ - pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ)); + * Adding new attribute containing DN for LDAP + * object associated with given username + */ + pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn, + T_OP_EQ)); ldap_memfree(user_dn); ldap_msgfree(result); } - if(!radius_xlat(gr_filter, sizeof(gr_filter), inst->groupmemb_filt, req, ldap_escape_func)){ + if(!radius_xlat(gr_filter, sizeof(gr_filter), + inst->groupmemb_filt, req, ldap_escape_func)) { DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter."); return 1; } - if (strchr((char *)check->strvalue,',') != NULL) { + if (strchr((char *)check->vp_strvalue,',') != NULL) { /* This looks like a DN */ snprintf(filter,sizeof(filter), "%s",gr_filter); - snprintf(basedn,sizeof(basedn), "%s",(char *)check->strvalue); + snprintf(basedn,sizeof(basedn), "%s",(char *)check->vp_strvalue); } else - snprintf(filter,sizeof(filter), "(&(%s=%s)%s)",inst->groupname_attr,(char *)check->strvalue,gr_filter); + snprintf(filter,sizeof(filter), "(&(%s=%s)%s)", + inst->groupname_attr, + (char *)check->vp_strvalue,gr_filter); - if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ - radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); + if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1) { + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); return 1; } if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, - filter, attrs, &result)) == RLM_MODULE_OK){ + filter, attrs, &result)) == RLM_MODULE_OK) { DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s", - (char *)check->strvalue); + (char *)check->vp_strvalue); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 0; } - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); if (res != RLM_MODULE_NOTFOUND ) { DEBUG("rlm_ldap::ldap_groupcmp: Search returned error"); @@ -1002,51 +1096,54 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALU } if (inst->groupmemb_attr == NULL){ - /* search returned NOTFOUND and searching for membership - * using user object attributes is not specified in config - * file + /* + * Search returned NOTFOUND and searching for + * membership using user object attributes is not + * specified in config file */ - DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->strvalue); + DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->vp_strvalue); return 1; } snprintf(filter,sizeof(filter), "(objectclass=*)"); if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ - radlog(L_ERR, "rlm_ldap: Add ldap connections are in use"); + radlog(L_ERR, " [%s] Add ldap connections are in use", inst->xlat_name); return 1; } - if ((res = perform_search(inst, conn, vp_user_dn->strvalue, LDAP_SCOPE_BASE, - filter, group_attrs,&result)) != RLM_MODULE_OK){ + if ((res = perform_search(inst, conn, vp_user_dn->vp_strvalue, + LDAP_SCOPE_BASE, filter, group_attrs, + &result)) != RLM_MODULE_OK) { DEBUG("rlm_ldap::ldap_groupcmp: Search returned error"); - ldap_release_conn(conn_id, inst->conns); + ldap_release_conn(conn_id, inst); return 1; } if ((msg = ldap_first_entry(conn->ld, result)) == NULL) { DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed"); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); ldap_msgfree(result); return 1; } - if ((vals = ldap_get_values(conn->ld, msg, inst->groupmemb_attr)) != NULL) { - unsigned int i = 0; + if ((vals = ldap_get_values(conn->ld, msg, + inst->groupmemb_attr)) != NULL) { + int i = 0; char found = 0; + for (;i < ldap_count_values(vals);i++){ if (strchr(vals[i],',') != NULL){ /* This looks like a DN */ LDAPMessage *gr_result = NULL; snprintf(filter,sizeof(filter), "(%s=%s)", inst->groupname_attr, - (char *)check->strvalue); + (char *)check->vp_strvalue); if ((res = perform_search(inst, conn, vals[i], LDAP_SCOPE_BASE, filter, attrs, &gr_result)) != RLM_MODULE_OK){ - if (res != RLM_MODULE_NOTFOUND){ - DEBUG("rlm_ldap::ldap_groupcmp: \ - Search returned error"); + if (res != RLM_MODULE_NOTFOUND) { + DEBUG("rlm_ldap::ldap_groupcmp: Search returned error"); ldap_value_free(vals); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 1; } } else { @@ -1055,7 +1152,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALU break; } } else { - if (strcmp(vals[i],(char *)check->strvalue) == 0){ + if (strcmp(vals[i],(char *)check->vp_strvalue) == 0){ found = 1; break; } @@ -1064,21 +1161,20 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALU ldap_value_free(vals); ldap_msgfree(result); if (found == 0){ - DEBUG("rlm_ldap::groupcmp: Group %s not found \ - or user not a member", - (char *)check->strvalue); - ldap_release_conn(conn_id,inst->conns); + DEBUG("rlm_ldap::groupcmp: Group %s not found or user not a member", + (char *)check->vp_strvalue); + ldap_release_conn(conn_id,inst); return 1; } } else { DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed"); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 1; } - DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue); - ldap_release_conn(conn_id,inst->conns); + DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->vp_strvalue); + ldap_release_conn(conn_id,inst); return 0; } @@ -1087,13 +1183,12 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALU * ldap_xlat() * Do an xlat on an LDAP URL */ - -static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out, - size_t freespace, RADIUS_ESCAPE_STRING func) +static size_t ldap_xlat(void *instance, REQUEST *request, char *fmt, + char *out, size_t freespace, RADIUS_ESCAPE_STRING func) { char url[MAX_FILTER_STR_LEN]; int res; - int ret = 0; + size_t ret = 0; ldap_instance *inst = instance; LDAPURLDesc *ldap_url; LDAPMessage *result = NULL; @@ -1102,70 +1197,72 @@ static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out, int conn_id = -1; LDAP_CONN *conn; - DEBUG("rlm_ldap: - ldap_xlat"); + DEBUG(" [%s] - ldap_xlat", inst->xlat_name); if (!radius_xlat(url, sizeof(url), fmt, request, func)) { - radlog (L_ERR, "rlm_ldap: Unable to create LDAP URL.\n"); + radlog (L_ERR, " [%s] Unable to create LDAP URL.\n", inst->xlat_name); return 0; } if (!ldap_is_ldap_url(url)){ - radlog (L_ERR, "rlm_ldap: String passed does not look like an LDAP URL.\n"); + radlog (L_ERR, " [%s] String passed does not look like an LDAP URL.\n", inst->xlat_name); return 0; } if (ldap_url_parse(url,&ldap_url)){ - radlog (L_ERR, "rlm_ldap: LDAP URL parse failed.\n"); + radlog (L_ERR, " [%s] LDAP URL parse failed.\n", inst->xlat_name); return 0; } - if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL || \ - ( ldap_url->lud_attrs[1] != NULL || ( ! strlen(ldap_url->lud_attrs[0]) || \ + if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL || + ( ldap_url->lud_attrs[1] != NULL || + ( ! strlen(ldap_url->lud_attrs[0]) || ! strcmp(ldap_url->lud_attrs[0],"*") ) ) ){ - radlog (L_ERR, "rlm_ldap: Invalid Attribute(s) request.\n"); + radlog (L_ERR, " [%s] Invalid Attribute(s) request.\n", inst->xlat_name); ldap_free_urldesc(ldap_url); return 0; } if (ldap_url->lud_host){ - if (strncmp(inst->server,ldap_url->lud_host,strlen(inst->server)) != 0 || \ - ldap_url->lud_port != inst->port){ - DEBUG("rlm_ldap: Requested server/port is not known to this module instance."); + if (strncmp(inst->server,ldap_url->lud_host, + strlen(inst->server)) != 0 || + ldap_url->lud_port != inst->port) { + DEBUG(" [%s] Requested server/port is not known to this module instance.", inst->xlat_name); ldap_free_urldesc(ldap_url); return 0; } } if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ - radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); ldap_free_urldesc(ldap_url); return 0; } if ((res = perform_search(inst, conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, ldap_url->lud_attrs, &result)) != RLM_MODULE_OK){ if (res == RLM_MODULE_NOTFOUND){ - DEBUG("rlm_ldap: Search returned not found"); + DEBUG(" [%s] Search returned not found", inst->xlat_name); ldap_free_urldesc(ldap_url); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 0; } - DEBUG("rlm_ldap: Search returned error"); + DEBUG(" [%s] Search returned error", inst->xlat_name); ldap_free_urldesc(ldap_url); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 0; } if ((msg = ldap_first_entry(conn->ld, result)) == NULL){ - DEBUG("rlm_ldap: ldap_first_entry() failed"); + DEBUG(" [%s] ldap_first_entry() failed", inst->xlat_name); ldap_msgfree(result); ldap_free_urldesc(ldap_url); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 0; } if ((vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0])) != NULL) { ret = strlen(vals[0]); - if (ret > freespace){ - DEBUG("rlm_ldap: Insufficient string space"); + if (ret >= freespace){ + DEBUG(" [%s] Insufficient string space", inst->xlat_name); ldap_free_urldesc(ldap_url); ldap_value_free(vals); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 0; } - DEBUG("rlm_ldap: Adding attribute %s, value: %s",ldap_url->lud_attrs[0],vals[0]); - strncpy(out,vals[0],ret); + DEBUG(" [%s] Adding attribute %s, value: %s", inst->xlat_name,ldap_url->lud_attrs[0],vals[0]); + strlcpy(out,vals[0],freespace); ldap_value_free(vals); } else @@ -1173,14 +1270,31 @@ static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out, ldap_msgfree(result); ldap_free_urldesc(ldap_url); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); - DEBUG("rlm_ldap: - ldap_xlat end"); + DEBUG(" [%s] - ldap_xlat end", inst->xlat_name); return ret; } +/* + * For auto-header discovery. + */ +static const FR_NAME_NUMBER header_names[] = { + { "{clear}", PW_CLEARTEXT_PASSWORD }, + { "{cleartext}", PW_CLEARTEXT_PASSWORD }, + { "{md5}", PW_MD5_PASSWORD }, + { "{smd5}", PW_SMD5_PASSWORD }, + { "{crypt}", PW_CRYPT_PASSWORD }, + { "{sha}", PW_SHA_PASSWORD }, + { "{ssha}", PW_SSHA_PASSWORD }, + { "{nt}", PW_NT_PASSWORD }, + { "{ns-mta-md5}", PW_NS_MTA_MD5_PASSWORD }, + { NULL, 0 } +}; + + /****************************************************************************** * * Function: rlm_ldap_authorize @@ -1188,8 +1302,7 @@ static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out, * Purpose: Check if user is authorized for remote access * ******************************************************************************/ -static int -ldap_authorize(void *instance, REQUEST * request) +static int ldap_authorize(void *instance, REQUEST * request) { LDAPMessage *result = NULL; LDAPMessage *msg = NULL; @@ -1213,11 +1326,9 @@ ldap_authorize(void *instance, REQUEST * request) int conn_id = -1; int added_known_password = 0; - DEBUG("rlm_ldap: - authorize"); - if (!request->username){ - radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n"); - return RLM_MODULE_INVALID; + RDEBUG2("Attribute \"User-Name\" is required for authorization.\n"); + return RLM_MODULE_NOOP; } check_pairs = &request->config_items; @@ -1226,56 +1337,56 @@ ldap_authorize(void *instance, REQUEST * request) /* * Check for valid input, zero length names not permitted */ - if (request->username->strvalue == 0) { - radlog(L_ERR, "rlm_ldap: zero length username not permitted\n"); + if (request->username->vp_strvalue == 0) { + DEBUG2("zero length username not permitted\n"); return RLM_MODULE_INVALID; } - DEBUG("rlm_ldap: performing user authorization for %s", - request->username->strvalue); + RDEBUG("performing user authorization for %s", + request->username->vp_strvalue); if (!radius_xlat(filter, sizeof(filter), inst->filter, request, ldap_escape_func)) { - radlog (L_ERR, "rlm_ldap: unable to create filter.\n"); + radlog(L_ERR, " [%s] unable to create filter.\n", inst->xlat_name); return RLM_MODULE_INVALID; } if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, request, ldap_escape_func)) { - radlog (L_ERR, "rlm_ldap: unable to create basedn.\n"); + radlog(L_ERR, " [%s] unable to create basedn.\n", inst->xlat_name); return RLM_MODULE_INVALID; } if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ - radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); return RLM_MODULE_FAIL; } if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) { - DEBUG("rlm_ldap: search failed"); + RDEBUG("search failed"); if (res == RLM_MODULE_NOTFOUND){ - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found"); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] User not found", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); } - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return (res); } if ((msg = ldap_first_entry(conn->ld, result)) == NULL) { - DEBUG("rlm_ldap: ldap_first_entry() failed"); + RDEBUG("ldap_first_entry() failed"); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_FAIL; } if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) { - DEBUG("rlm_ldap: ldap_get_dn() failed"); + RDEBUG("ldap_get_dn() failed"); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_FAIL; } /* * Adding new attribute containing DN for LDAP object associated with * given username */ - pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ)); + pairadd(check_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ)); ldap_memfree(user_dn); @@ -1283,37 +1394,37 @@ ldap_authorize(void *instance, REQUEST * request) if (inst->access_attr) { if ((vals = ldap_get_values(conn->ld, msg, inst->access_attr)) != NULL) { if (inst->default_allow){ - DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", request->username->strvalue, inst->access_attr); + RDEBUG("checking if remote access for %s is allowed by %s", request->username->vp_strvalue, inst->access_attr); if (!strncmp(vals[0], "FALSE", 5)) { - DEBUG("rlm_ldap: dialup access disabled"); - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access"); + RDEBUG("dialup access disabled"); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] Access Attribute denies access", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); ldap_msgfree(result); ldap_value_free(vals); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_USERLOCK; } ldap_value_free(vals); } else{ - DEBUG("rlm_ldap: %s attribute exists - access denied by default", inst->access_attr); - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access"); + RDEBUG("%s attribute exists - access denied by default", inst->access_attr); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] Access Attribute denies access", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); ldap_msgfree(result); ldap_value_free(vals); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_USERLOCK; } } else { if (inst->default_allow){ - DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr); - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access"); + RDEBUG("no %s attribute - access denied by default", inst->access_attr); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] Access Attribute denies access", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_USERLOCK; } } @@ -1324,19 +1435,19 @@ ldap_authorize(void *instance, REQUEST * request) * attributes it contains in the check and reply pairs */ - user_profile = pairfind(request->config_items, PW_USER_PROFILE); + user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0); if (inst->default_profile || user_profile){ char *profile = inst->default_profile; - strNcpy(filter,inst->base_filter,sizeof(filter)); + strlcpy(filter,inst->base_filter,sizeof(filter)); if (user_profile) - profile = user_profile->strvalue; + profile = user_profile->vp_strvalue; if (profile && strlen(profile)){ if ((res = perform_search(instance, conn, profile, LDAP_SCOPE_BASE, filter, inst->atts, &def_result)) == RLM_MODULE_OK){ if ((def_msg = ldap_first_entry(conn->ld,def_result))){ - if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1))) { + if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1, inst))) { if (inst->do_xlat){ pairxlatmove(request, check_pairs, &check_tmp); pairfree(&check_tmp); @@ -1344,7 +1455,7 @@ ldap_authorize(void *instance, REQUEST * request) else pairadd(check_pairs,check_tmp); } - if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs,0))) { + if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs,0, inst))) { if (inst->do_xlat){ pairxlatmove(request, reply_pairs, &reply_tmp); pairfree(&reply_tmp); @@ -1355,7 +1466,7 @@ ldap_authorize(void *instance, REQUEST * request) } ldap_msgfree(def_result); } else - DEBUG("rlm_ldap: default_profile/user-profile search failed"); + RDEBUG("default_profile/user-profile search failed"); } } @@ -1369,13 +1480,13 @@ ldap_authorize(void *instance, REQUEST * request) if (inst->profile_attr){ if ((vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) { unsigned int i=0; - strNcpy(filter,inst->base_filter,sizeof(filter)); + strlcpy(filter,inst->base_filter,sizeof(filter)); while(vals[i] != NULL && strlen(vals[i])){ if ((res = perform_search(instance, conn, vals[i], LDAP_SCOPE_BASE, filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){ if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){ - if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1))) { + if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1, inst))) { if (inst->do_xlat){ pairxlatmove(request, check_pairs, &check_tmp); pairfree(&check_tmp); @@ -1383,7 +1494,7 @@ ldap_authorize(void *instance, REQUEST * request) else pairadd(check_pairs,check_tmp); } - if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs,0))) { + if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs,0, inst))) { if (inst->do_xlat){ pairxlatmove(request, reply_pairs, &reply_tmp); pairfree(&reply_tmp); @@ -1394,57 +1505,56 @@ ldap_authorize(void *instance, REQUEST * request) } ldap_msgfree(def_attr_result); } else - DEBUG("rlm_ldap: profile_attribute search failed"); + RDEBUG("profile_attribute search failed"); i++; } ldap_value_free(vals); } } - if (inst->passwd_attr && strlen(inst->passwd_attr)){ + if (inst->passwd_attr && strlen(inst->passwd_attr)) { #ifdef NOVELL_UNIVERSAL_PASSWORD - if(strcasecmp(inst->passwd_attr,"nspmPassword")!= 0){ + if (strcasecmp(inst->passwd_attr,"nspmPassword") != 0) { #endif - VALUE_PAIR *passwd_item; - - if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){ + VALUE_PAIR *passwd_item; char **passwd_vals; - char *passwd_val = NULL; - int passwd_len; - - if ((passwd_vals = ldap_get_values(conn->ld,msg,inst->passwd_attr)) != NULL){ - unsigned int i=0; - while(passwd_vals[i] != NULL){ - if (strlen(passwd_vals[i])){ - passwd_val = passwd_vals[i]; - - if (inst->passwd_hdr && strlen(inst->passwd_hdr)){ - passwd_val = strstr(passwd_val,inst->passwd_hdr); - if (passwd_val != NULL) - passwd_val += strlen(inst->passwd_hdr); - else - DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0],request->username->strvalue); - } - if (passwd_val){ - if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){ - radlog(L_ERR|L_CONS, "no memory"); - ldap_value_free(passwd_vals); - ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); - return RLM_MODULE_FAIL; - } - added_known_password = 1; - passwd_len = strlen(passwd_val); - strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1); - passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len; - pairadd(&request->config_items,passwd_item); - DEBUG("rlm_ldap: Added password %s in check items",passwd_item->strvalue); - } - } - i++; - } - ldap_value_free(passwd_vals); + char *value = NULL; + int i; + + /* + * Read the password from the DB, and + * add it to the request. + */ + passwd_vals = ldap_get_values(conn->ld,msg, + inst->passwd_attr); + + /* + * Loop over what we received, and parse it. + */ + if (passwd_vals) for (i = 0; + passwd_vals[i] != NULL; + i++) { + int attr = PW_USER_PASSWORD; + + if (strlen(passwd_vals[i]) == 0) + continue; + + value = passwd_vals[i]; + if (!value) continue; + + create_attr: + passwd_item = radius_paircreate(request, + &request->config_items, + attr, 0, + PW_TYPE_STRING); + strlcpy(passwd_item->vp_strvalue, value, + sizeof(passwd_item->vp_strvalue)); + passwd_item->length = strlen(passwd_item->vp_strvalue); + RDEBUG("Added %s = %s in check items", + passwd_item->name, + passwd_item->vp_strvalue); + added_known_password = 1; } - } + ldap_value_free(passwd_vals); #ifdef NOVELL_UNIVERSAL_PASSWORD } else{ @@ -1453,48 +1563,27 @@ ldap_authorize(void *instance, REQUEST * request) */ VALUE_PAIR *passwd_item; VALUE_PAIR *vp_user_dn; - int passwd_len; char *universal_password = NULL; - int universal_password_len = UNIVERSAL_PASS_LEN; + size_t universal_password_len = UNIVERSAL_PASS_LEN; char *passwd_val = NULL; res = 0; - if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){ - + if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0)) == NULL){ + universal_password = rad_malloc(universal_password_len); memset(universal_password, 0, universal_password_len); - vp_user_dn = pairfind(request->packet->vps,PW_LDAP_USERDN); - res = nmasldap_get_password(conn->ld,vp_user_dn->strvalue,&universal_password_len,universal_password); + vp_user_dn = pairfind(request->config_items,PW_LDAP_USERDN, 0); + res = nmasldap_get_password(conn->ld,vp_user_dn->vp_strvalue,&universal_password_len,universal_password); if (res == 0){ passwd_val = universal_password; - - if (inst->passwd_hdr && strlen(inst->passwd_hdr)){ - passwd_val = strstr(passwd_val,inst->passwd_hdr); - - if (passwd_val != NULL) - passwd_val += strlen((char*)inst->passwd_hdr); - else - DEBUG("rlm_ldap: Password header not found in password %s for user %s ",passwd_val,request->username->strvalue); - } - if (passwd_val){ - if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){ - radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); - ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); - memset(universal_password, 0, universal_password_len); - free(universal_password); - return RLM_MODULE_FAIL; - } - + passwd_item = radius_paircreate(request, &request->config_items, PW_CLEARTEXT_PASSWORD, PW_TYPE_STRING); + strlcpy(passwd_item->vp_strvalue,passwd_val,sizeof(passwd_item->vp_strvalue)); + passwd_item->length = strlen(passwd_item->vp_strvalue); added_known_password = 1; - passwd_len = strlen(passwd_val); - strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1); - passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len; - pairadd(&request->config_items,passwd_item); #ifdef NOVELL { @@ -1513,65 +1602,71 @@ ldap_authorize(void *instance, REQUEST * request) * The authorize method of no other LDAP module instance has * processed this request. */ - if ((vp_inst = paircreate(inst_attr, PW_TYPE_STRING)) == NULL){ - radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); - ldap_msgfree(result); - ldap_release_conn(conn_id, inst->conns); - memset(universal_password, 0, universal_password_len); - free(universal_password); - return RLM_MODULE_FAIL; - } - strcpy(vp_inst->strvalue, inst->xlat_name); - vp_inst->length = strlen(vp_inst->strvalue); - pairadd(&request->config_items, vp_inst); + vp_inst = radius_paircreate(request, &request->config_items, inst_attr, PW_TYPE_STRING); + strlcpy(vp_inst->vp_strvalue, inst->xlat_name, sizeof(vp_inst->vp_strvalue)); + vp_inst->length = strlen(vp_inst->vp_strvalue); /* * Inform the authenticate / post-auth method about the presence * of UP in the config items list and whether eDirectory account * policy check is to be performed or not. */ - if ((vp_apc = paircreate(apc_attr, PW_TYPE_STRING)) == NULL){ - radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); - ldap_msgfree(result); - ldap_release_conn(conn_id, inst->conns); - memset(universal_password, 0, universal_password_len); - free(universal_password); - return RLM_MODULE_FAIL; - } - + vp_apc = radius_paircreate(request, &request->config_items, apc_attr, PW_TYPE_STRING); if(!inst->edir_account_policy_check){ /* Do nothing */ - strcpy(vp_apc->strvalue, "1"); + strcpy(vp_apc->vp_strvalue, "1"); }else{ /* Perform eDirectory account-policy check */ - strcpy(vp_apc->strvalue, "2"); + strcpy(vp_apc->vp_strvalue, "2"); } vp_apc->length = 1; - pairadd(&request->config_items, vp_apc); } } #endif - DEBUG("rlm_ldap: Added the eDirectory password in check items"); + RDEBUG("Added the eDirectory password %s in check items as %s",passwd_item->vp_strvalue,passwd_item->name); } } else { - DEBUG("rlm_ldap: Error reading Universal Password.Return Code = %d",res); + RDEBUG("Error reading Universal Password.Return Code = %d",res); } memset(universal_password, 0, universal_password_len); free(universal_password); } - } + } #endif - } +#ifdef NOVELL + { + VALUE_PAIR *vp_auth_opt; + DICT_ATTR *dattr; + char **auth_option; + int auth_opt_attr; + + dattr = dict_attrbyname("eDir-Auth-Option"); + auth_opt_attr = dattr->attr; + if(pairfind(*check_pairs, auth_opt_attr) == NULL){ + if ((auth_option = ldap_get_values(conn->ld, msg, "sasDefaultLoginSequence")) != NULL) { + if ((vp_auth_opt = paircreate(auth_opt_attr, PW_TYPE_STRING)) == NULL){ + radlog(L_ERR, " [%s] Could not allocate memory. Aborting.", inst->xlat_name); + ldap_msgfree(result); + ldap_release_conn(conn_id, inst); + } + strcpy(vp_auth_opt->vp_strvalue, auth_option[0]); + vp_auth_opt->length = strlen(auth_option[0]); + pairadd(&request->config_items, vp_auth_opt); + }else{ + RDEBUG("No default NMAS login sequence"); + } + } + } +#endif + RDEBUG("looking for check items in directory..."); - DEBUG("rlm_ldap: looking for check items in directory..."); - - if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs,1)) != NULL) { + if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs,1, inst)) != NULL) { if (inst->do_xlat){ pairxlatmove(request, check_pairs, &check_tmp); pairfree(&check_tmp); @@ -1581,10 +1676,10 @@ ldap_authorize(void *instance, REQUEST * request) } - DEBUG("rlm_ldap: looking for reply items in directory..."); + RDEBUG("looking for reply items in directory..."); - if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs,0)) != NULL) { + if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs,0, inst)) != NULL) { if (inst->do_xlat){ pairxlatmove(request, reply_pairs, &reply_tmp); pairfree(&reply_tmp); @@ -1593,7 +1688,7 @@ ldap_authorize(void *instance, REQUEST * request) pairadd(reply_pairs,reply_tmp); } - if (inst->do_comp && paircmp(request,request->packet->vps,*check_pairs,reply_pairs) != 0){ + if (inst->do_comp && paircompare(request,request->packet->vps,*check_pairs,reply_pairs) != 0){ #ifdef NOVELL /* Don't perform eDirectory APC if RADIUS authorize fails */ int apc_attr; @@ -1605,18 +1700,31 @@ ldap_authorize(void *instance, REQUEST * request) vp_apc = pairfind(request->config_items, apc_attr); if(vp_apc) - vp_apc->strvalue[0] = '1'; + vp_apc->vp_strvalue[0] = '1'; #endif - DEBUG("rlm_ldap: Pairs do not match. Rejecting user."); - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Pairs do not match"); + RDEBUG("Pairs do not match. Rejecting user."); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] Pairs do not match", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_REJECT; } + + /* + * More warning messages for people who can't be bothered + * to read the documentation. + */ + if (debug_flag > 1) { + if (!pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0) && + !pairfind(request->config_items, PW_USER_PASSWORD, 0) && + !pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0) && + !pairfind(request->config_items, PW_CRYPT_PASSWORD, 0)) { + DEBUG("WARNING: No \"known good\" password was found in LDAP. Are you sure that the user is configured correctly?"); + } + } /* * Module should default to LDAP authentication if no Auth-Type @@ -1625,18 +1733,18 @@ ldap_authorize(void *instance, REQUEST * request) * ldap instances to work. */ if (inst->set_auth_type && - (pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) && + (pairfind(*check_pairs, PW_AUTH_TYPE, 0) == NULL) && request->password && (request->password->attribute == PW_USER_PASSWORD) && !added_known_password) { - pairadd(check_pairs, pairmake("Auth-Type", inst->xlat_name, T_OP_EQ)); - DEBUG("rlm_ldap: Setting Auth-Type = %s", inst->xlat_name); + pairadd(check_pairs, pairmake("Auth-Type", inst->auth_type, T_OP_EQ)); + RDEBUG("Setting Auth-Type = %s", inst->auth_type); } - DEBUG("rlm_ldap: user %s authorized to use remote access", - request->username->strvalue); + RDEBUG("user %s authorized to use remote access", + request->username->vp_strvalue); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_OK; } @@ -1648,8 +1756,7 @@ ldap_authorize(void *instance, REQUEST * request) * Purpose: Check the user's password against ldap database * *****************************************************************************/ -static int -ldap_authenticate(void *instance, REQUEST * request) +static int ldap_authenticate(void *instance, REQUEST * request) { LDAP *ld_user; LDAPMessage *result, *msg; @@ -1657,7 +1764,7 @@ ldap_authenticate(void *instance, REQUEST * request) char *user_dn, *attrs[] = {"uid", NULL}; char filter[MAX_FILTER_STR_LEN]; char basedn[MAX_FILTER_STR_LEN]; - int res; + int res; VALUE_PAIR *vp_user_dn; VALUE_PAIR *module_fmsg_vp; char module_fmsg[MAX_STRING_LEN]; @@ -1667,30 +1774,31 @@ ldap_authenticate(void *instance, REQUEST * request) char *err = NULL; #endif - DEBUG("rlm_ldap: - authenticate"); - /* * Ensure that we're being passed a plain-text password, and not * anything else. */ if (!request->username) { - radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n"); + radlog(L_AUTH, " [%s] Attribute \"User-Name\" is required for authentication.\n", inst->xlat_name); return RLM_MODULE_INVALID; } if (!request->password){ - radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication."); + radlog(L_AUTH, " [%s] Attribute \"User-Password\" is required for authentication.", inst->xlat_name); + DEBUG2(" You seem to have set \"Auth-Type := LDAP\" somewhere."); + DEBUG2(" THAT CONFIGURATION IS WRONG. DELETE IT."); + DEBUG2(" YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY."); return RLM_MODULE_INVALID; } - if(request->password->attribute != PW_PASSWORD) { - radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name); + if(request->password->attribute != PW_USER_PASSWORD) { + radlog(L_AUTH, " [%s] Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", inst->xlat_name, request->password->name); return RLM_MODULE_INVALID; } if (request->password->length == 0) { - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: empty password supplied"); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] empty password supplied", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); return RLM_MODULE_INVALID; @@ -1708,101 +1816,229 @@ ldap_authenticate(void *instance, REQUEST * request) } - DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"", - request->username->strvalue, request->password->strvalue); + RDEBUG("login attempt by \"%s\" with password \"%s\"", + request->username->vp_strvalue, request->password->vp_strvalue); - while((vp_user_dn = pairfind(request->packet->vps, PW_LDAP_USERDN)) == NULL) { + while ((vp_user_dn = pairfind(request->config_items, + PW_LDAP_USERDN, 0)) == NULL) { if (!radius_xlat(filter, sizeof(filter), inst->filter, request, ldap_escape_func)) { - radlog (L_ERR, "rlm_ldap: unable to create filter.\n"); + radlog(L_ERR, " [%s] unable to create filter.\n", inst->xlat_name); return RLM_MODULE_INVALID; } if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, request, ldap_escape_func)) { - radlog (L_ERR, "rlm_ldap: unable to create basedn.\n"); + radlog(L_ERR, " [%s] unable to create basedn.\n", inst->xlat_name); return RLM_MODULE_INVALID; } if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ - radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); return RLM_MODULE_FAIL; } if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) { if (res == RLM_MODULE_NOTFOUND){ - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found"); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] User not found", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); } - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return (res); } if ((msg = ldap_first_entry(conn->ld, result)) == NULL) { ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_FAIL; } if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) { - DEBUG("rlm_ldap: ldap_get_dn() failed"); + RDEBUG("ldap_get_dn() failed"); ldap_msgfree(result); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return RLM_MODULE_FAIL; } - ldap_release_conn(conn_id,inst->conns); - pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ)); + ldap_release_conn(conn_id,inst); + pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ)); ldap_memfree(user_dn); ldap_msgfree(result); } - user_dn = vp_user_dn->strvalue; + user_dn = vp_user_dn->vp_strvalue; - DEBUG("rlm_ldap: user DN: %s", user_dn); + RDEBUG("user DN: %s", user_dn); #ifndef NOVELL - ld_user = ldap_connect(instance, user_dn, request->password->strvalue, + ld_user = ldap_connect(instance, user_dn, request->password->vp_strvalue, 1, &res, NULL); #else - - ld_user = ldap_connect(instance, user_dn, request->password->strvalue, - 1, &res, &err); - - if(err != NULL){ - /* 'err' contains the LDAP connection error description */ - DEBUG("rlm_ldap: %s", err); - pairadd(&request->reply->vps, pairmake("Reply-Message", err, T_OP_EQ)); - ldap_memfree((void *)err); - } - /* Don't perform eDirectory APC again after attempting to bind here. */ { int apc_attr; DICT_ATTR *dattr; VALUE_PAIR *vp_apc; + VALUE_PAIR *vp_auth_opt, *vp_state; + int auth_opt_attr; + char seq[256]; + char host_ipaddr[32]; + LDAP_CONN *conn1; + int auth_state = -1; + char *challenge = NULL; + size_t challenge_len = MAX_CHALLENGE_LEN; + char *state = NULL; dattr = dict_attrbyname("eDir-APC"); apc_attr = dattr->attr; vp_apc = pairfind(request->config_items, apc_attr); - if(vp_apc && vp_apc->strvalue[0] == '2') - vp_apc->strvalue[0] = '3'; + if(vp_apc && vp_apc->vp_strvalue[0] == '2') + vp_apc->vp_strvalue[0] = '3'; + + res = 0; + + dattr = dict_attrbyname("eDir-Auth-Option"); + auth_opt_attr = dattr->attr; + + vp_auth_opt = pairfind(request->config_items, auth_opt_attr); + + if(vp_auth_opt ) + { + RDEBUG("ldap auth option = %s", vp_auth_opt->vp_strvalue); + strncpy(seq, vp_auth_opt->vp_strvalue, vp_auth_opt->length); + seq[vp_auth_opt->length] = '\0'; + if( strcasecmp(seq, "") ){ + + /* Get the client IP address to check for packet validity */ + inet_ntop(AF_INET, &request->packet->src_ipaddr, host_ipaddr, sizeof(host_ipaddr)); + + /* challenge variable is used to receive the challenge from the + * Token method (if any) and also to send the state attribute + * in case the request packet is a reply to a challenge + */ + challenge = rad_malloc(MAX_CHALLENGE_LEN); + + /* If state attribute present in request it is a reply to challenge. */ + if((vp_state = pairfind(request->packet->vps, PW_STATE, 0))!= NULL ){ + RDEBUG("Response to Access-Challenge"); + strncpy(challenge, vp_state->vp_strvalue, sizeof(challenge)); + challenge_len = vp_state->length; + challenge[challenge_len] = 0; + auth_state = -2; + } + + if ((conn_id = ldap_get_conn(inst->conns, &conn1, inst)) == -1){ + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); + res = RLM_MODULE_FAIL; + } + + if(!conn1){ + radlog(L_ERR, " [%s] NULL connection handle passed", inst->xlat_name); + return RLM_MODULE_FAIL; + } + + if (conn1->failed_conns > MAX_FAILED_CONNS_START){ + conn1->failed_conns++; + if (conn1->failed_conns >= MAX_FAILED_CONNS_END){ + conn1->failed_conns = MAX_FAILED_CONNS_RESTART; + conn1->bound = 0; + } + } +retry: + if (!conn1->bound || conn1->ld == NULL) { + DEBUG2(" [%s] attempting LDAP reconnection", inst->xlat_name); + if (conn1->ld){ + DEBUG2(" [%s] closing existing LDAP connection", inst->xlat_name); + ldap_unbind_s(conn1->ld); + } + if ((conn1->ld = ldap_connect(instance, inst->login,inst->password, 0, &res, NULL)) == NULL) { + radlog(L_ERR, " [%s] (re)connection attempt failed", inst->xlat_name); + conn1->failed_conns++; + return (RLM_MODULE_FAIL); + } + conn1->bound = 1; + conn1->failed_conns = 0; + } + RDEBUG("Performing NMAS Authentication for user: %s, seq: %s \n", user_dn,seq); + + res = radLdapXtnNMASAuth(conn1->ld, user_dn, request->password->vp_strvalue, seq, host_ipaddr, &challenge_len, challenge, &auth_state ); + + switch(res){ + case LDAP_SUCCESS: + ldap_release_conn(conn_id,inst); + if ( auth_state == -1) + res = RLM_MODULE_FAIL; + if ( auth_state != REQUEST_CHALLENGED){ + if (auth_state == REQUEST_ACCEPTED){ + RDEBUG("user %s authenticated succesfully",request->username->vp_strvalue); + res = RLM_MODULE_OK; + }else if(auth_state == REQUEST_REJECTED){ + RDEBUG("user %s authentication failed",request->username->vp_strvalue); + res = RLM_MODULE_REJECT; + } + }else{ + /* Request challenged. Generate Reply-Message attribute with challenge data */ + pairadd(&request->reply->vps,pairmake("Reply-Message", challenge, T_OP_EQ)); + /* Generate state attribute */ + state = rad_malloc(MAX_CHALLENGE_LEN); + (void) sprintf(state, "%s%s", challenge, challenge); + vp_state = paircreate(PW_STATE, PW_TYPE_OCTETS); + memcpy(vp_state->vp_strvalue, state, strlen(state)); + vp_state->length = strlen(state); + pairadd(&request->reply->vps, vp_state); + free(state); + /* Mark the packet as a Acceess-Challenge Packet */ + request->reply->code = PW_ACCESS_CHALLENGE; + RDEBUG("Sending Access-Challenge."); + res = RLM_MODULE_HANDLED; + } + if(challenge) + free(challenge); + return res; + case LDAP_SERVER_DOWN: + radlog(L_ERR, " [%s] nmas authentication failed: LDAP connection lost.", inst->xlat_name); conn->failed_conns++; + if (conn->failed_conns <= MAX_FAILED_CONNS_START){ + radlog(L_INFO, " [%s] Attempting reconnect", inst->xlat_name); + conn->bound = 0; + goto retry; + } + if(challenge) + free(challenge); + return RLM_MODULE_FAIL; + default: + ldap_release_conn(conn_id,inst); + if(challenge) + free(challenge); + return RLM_MODULE_FAIL; + } + } + } + } + + ld_user = ldap_connect(instance, user_dn, request->password->vp_strvalue, + 1, &res, &err); + + if(err != NULL){ + /* 'err' contains the LDAP connection error description */ + RDEBUG("%s", err); + pairadd(&request->reply->vps, pairmake("Reply-Message", err, T_OP_EQ)); + ldap_memfree((void *)err); } #endif if (ld_user == NULL){ if (res == RLM_MODULE_REJECT){ inst->failed_conns = 0; - snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed"); + snprintf(module_fmsg,sizeof(module_fmsg)," [%s] Bind as user failed", inst->xlat_name); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); } if (res == RLM_MODULE_FAIL){ - DEBUG("rlm_ldap: ldap_connect() failed"); + RDEBUG("ldap_connect() failed"); inst->failed_conns++; } return (res); } - DEBUG("rlm_ldap: user %s authenticated succesfully", - request->username->strvalue); + RDEBUG("user %s authenticated succesfully", + request->username->vp_strvalue); ldap_unbind_s(ld_user); inst->failed_conns = 0; @@ -1818,8 +2054,7 @@ ldap_authenticate(void *instance, REQUEST * request) * to eDirectory. * *****************************************************************************/ -static int -ldap_postauth(void *instance, REQUEST * request) +static int ldap_postauth(void *instance, REQUEST * request) { int res = RLM_MODULE_FAIL; int inst_attr, apc_attr; @@ -1840,12 +2075,12 @@ ldap_postauth(void *instance, REQUEST * request) * Check if the password in the config items list is the user's UP which has * been read in the authorize method of this instance of the LDAP module. */ - if((vp_inst == NULL) || strcmp(vp_inst->strvalue, inst->xlat_name)) + if((vp_inst == NULL) || strcmp(vp_inst->vp_strvalue, inst->xlat_name)) return RLM_MODULE_NOOP; vp_apc = pairfind(request->config_items, apc_attr); - switch(vp_apc->strvalue[0]){ + switch(vp_apc->vp_strvalue[0]){ case '1': /* Account policy check not enabled */ case '3': @@ -1859,89 +2094,91 @@ ldap_postauth(void *instance, REQUEST * request) VALUE_PAIR *vp_fdn, *vp_pwd; DICT_ATTR *da; - if(request->reply->code == PW_AUTHENTICATION_REJECT){ - /* Bind to eDirectory as the RADIUS user with a wrong password. */ - vp_pwd = pairfind(request->config_items, PW_PASSWORD); - strcpy(password, vp_pwd->strvalue); - if(strlen(password) > 0){ - if(password[0] != 'a'){ - password[0] = 'a'; - }else{ - password[0] = 'b'; - } - }else{ - strcpy(password, "dummy_password"); - } - res = RLM_MODULE_REJECT; - }else{ + if (request->reply->code == PW_AUTHENTICATION_REJECT) { + /* Bind to eDirectory as the RADIUS user with a wrong password. */ + vp_pwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); + strcpy(password, vp_pwd->vp_strvalue); + if (strlen(password) > 0) { + if (password[0] != 'a') { + password[0] = 'a'; + } else { + password[0] = 'b'; + } + } else { + strcpy(password, "dummy_password"); + } + res = RLM_MODULE_REJECT; + } else { /* Bind to eDirectory as the RADIUS user using the user's UP */ - vp_pwd = pairfind(request->config_items, PW_PASSWORD); - if(vp_pwd == NULL){ - DEBUG("rlm_ldap: User's Universal Password not in config items list."); + vp_pwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); + if (vp_pwd == NULL) { + RDEBUG("User's Universal Password not in config items list."); return RLM_MODULE_FAIL; } - strcpy(password, vp_pwd->strvalue); + strcpy(password, vp_pwd->vp_strvalue); } if ((da = dict_attrbyname("Ldap-UserDn")) == NULL) { - DEBUG("rlm_ldap: Attribute for user FDN not found in dictionary. Unable to proceed"); + RDEBUG("Attribute for user FDN not found in dictionary. Unable to proceed"); return RLM_MODULE_FAIL; } - vp_fdn = pairfind(request->packet->vps, da->attr); - if(vp_fdn == NULL){ - DEBUG("rlm_ldap: User's FQDN not in config items list."); + vp_fdn = pairfind(request->config_items, da->attr); + if (vp_fdn == NULL) { + RDEBUG("User's FQDN not in config items list."); return RLM_MODULE_FAIL; } if ((conn_id = ldap_get_conn(inst->apc_conns, &conn, inst)) == -1){ - radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); return RLM_MODULE_FAIL; } /* - * If there is an existing LDAP connection to the directory, bind over - * it. Otherwise, establish a new connection. + * If there is an existing LDAP + * connection to the directory, + * bind over it. Otherwise, + * establish a new connection. */ -postauth_reconnect: + postauth_reconnect: if (!conn->bound || conn->ld == NULL) { - DEBUG2("rlm_ldap: attempting LDAP reconnection"); + DEBUG2(" [%s] attempting LDAP reconnection", inst->xlat_name); if (conn->ld){ - DEBUG2("rlm_ldap: closing existing LDAP connection"); + DEBUG2(" [%s] closing existing LDAP connection", inst->xlat_name); ldap_unbind_s(conn->ld); } - if ((conn->ld = ldap_connect(instance, (char *)vp_fdn->strvalue, password, 0, &res, &error_msg)) == NULL) { - radlog(L_ERR, "rlm_ldap: eDirectory account policy check failed."); + if ((conn->ld = ldap_connect(instance, (char *)vp_fdn->vp_strvalue, password, 0, &res, &error_msg)) == NULL) { + radlog(L_ERR, " [%s] eDirectory account policy check failed.", inst->xlat_name); - if(error_msg != NULL){ - DEBUG("rlm_ldap: %s", error_msg); + if (error_msg != NULL) { + RDEBUG("%s", error_msg); pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ)); ldap_memfree((void *)error_msg); } - vp_apc->strvalue[0] = '3'; - ldap_release_conn(conn_id, inst->apc_conns); + vp_apc->vp_strvalue[0] = '3'; + ldap_release_apc_conn(conn_id, inst); return RLM_MODULE_REJECT; } conn->bound = 1; - }else if((err = ldap_simple_bind_s(conn->ld, (char *)vp_fdn->strvalue, password)) != LDAP_SUCCESS){ - if(err == LDAP_SERVER_DOWN){ + } else if((err = ldap_simple_bind_s(conn->ld, (char *)vp_fdn->vp_strvalue, password)) != LDAP_SUCCESS) { + if (err == LDAP_SERVER_DOWN) { conn->bound = 0; goto postauth_reconnect; } - DEBUG("rlm_ldap: eDirectory account policy check failed."); + RDEBUG("eDirectory account policy check failed."); ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, &error_msg); - if(error_msg != NULL){ - DEBUG("rlm_ldap: %s", error_msg); + if (error_msg != NULL) { + RDEBUG("%s", error_msg); pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ)); ldap_memfree((void *)error_msg); } - vp_apc->strvalue[0] = '3'; - ldap_release_conn(conn_id, inst->apc_conns); + vp_apc->vp_strvalue[0] = '3'; + ldap_release_apc_conn(conn_id, inst); return RLM_MODULE_REJECT; } - vp_apc->strvalue[0] = '3'; - ldap_release_conn(conn_id, inst->apc_conns); + vp_apc->vp_strvalue[0] = '3'; + ldap_release_apc_conn(conn_id, inst); return RLM_MODULE_OK; } } @@ -1949,138 +2186,232 @@ postauth_reconnect: } #endif -static LDAP * -ldap_connect(void *instance, const char *dn, const char *password, int auth, int *result, char **err) +#if LDAP_SET_REBIND_PROC_ARGS == 3 +static int ldap_rebind(LDAP *ld, LDAP_CONST char *url, + UNUSED ber_tag_t request, UNUSED ber_int_t msgid, + void *params ) +{ + ldap_instance *inst = params; + + DEBUG(" [%s] rebind to URL %s", inst->xlat_name,url); + return ldap_bind_s(ld, inst->login, inst->password, LDAP_AUTH_SIMPLE); +} +#endif + +static LDAP *ldap_connect(void *instance, const char *dn, const char *password, + int auth, int *result, char **err) { ldap_instance *inst = instance; LDAP *ld = NULL; int msgid, rc, ldap_version; int ldap_errno = 0; LDAPMessage *res; + struct timeval tv; if (inst->is_url){ #ifdef HAVE_LDAP_INITIALIZE - DEBUG("rlm_ldap: (re)connect to %s, authentication %d", inst->server, auth); + DEBUG(" [%s] (re)connect to %s, authentication %d", inst->xlat_name, inst->server, auth); if (ldap_initialize(&ld, inst->server) != LDAP_SUCCESS) { - radlog(L_ERR, "rlm_ldap: ldap_initialize() failed"); + radlog(L_ERR, " [%s] ldap_initialize() failed", inst->xlat_name); *result = RLM_MODULE_FAIL; return (NULL); } #endif - } - else{ - DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth); + } else { + DEBUG(" [%s] (re)connect to %s:%d, authentication %d", inst->xlat_name, inst->server, inst->port, auth); if ((ld = ldap_init(inst->server, inst->port)) == NULL) { - radlog(L_ERR, "rlm_ldap: ldap_init() failed"); + radlog(L_ERR, " [%s] ldap_init() failed", inst->xlat_name); *result = RLM_MODULE_FAIL; return (NULL); } } - if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *) &(inst->net_timeout)) != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", inst->net_timeout.tv_sec, inst->net_timeout.tv_usec); + tv.tv_sec = inst->net_timeout; + tv.tv_usec = 0; + if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, + (void *) &tv) != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP_OPT_NETWORK_TIMEOUT %d: %s", inst->xlat_name, inst->net_timeout, ldap_err2string(ldap_errno)); } - if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit); + + /* + * Leave "chase_referrals" unset to use the OpenLDAP + * default. + */ + if (inst->chase_referrals != 2) { + if (inst->chase_referrals) { + rc=ldap_set_option(ld, LDAP_OPT_REFERRALS, + LDAP_OPT_ON); + +#if LDAP_SET_REBIND_PROC_ARGS == 3 + if (inst->rebind == 1) { + ldap_set_rebind_proc(ld, ldap_rebind, + inst); + } +#endif + } else { + rc=ldap_set_option(ld, LDAP_OPT_REFERRALS, + LDAP_OPT_OFF); + } + if (rc != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP_OPT_REFERRALS=%d %s", inst->xlat_name, inst->chase_referrals, ldap_err2string(ldap_errno)); + } + } + + if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, + (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP_OPT_TIMELIMIT %d: %s", inst->xlat_name, inst->timelimit, ldap_err2string(ldap_errno)); } + if (inst->ldap_debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->ldap_debug)) != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->ldap_debug); + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP_OPT_DEBUG_LEVEL %d: %s", inst->xlat_name, inst->ldap_debug, ldap_err2string(ldap_errno)); } + ldap_version = LDAP_VERSION3; - if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version) != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: Could not set LDAP version to V3"); + if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, + &ldap_version) != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP version to V3: %s", inst->xlat_name, ldap_err2string(ldap_errno)); } + +#ifdef LDAP_OPT_X_KEEPALIVE_IDLE + if (ldap_set_option(ld, LDAP_OPT_X_KEEPALIVE_IDLE, + (void *) &(inst->keepalive_idle)) != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP_OPT_X_KEEPALIVE_IDLE %d: %s", inst->xlat_name, inst->keepalive_idle, ldap_err2string(ldap_errno)); + } +#endif + +#ifdef LDAP_OPT_X_KEEPALIVE_PROBES + if (ldap_set_option(ld, LDAP_OPT_X_KEEPALIVE_PROBES, + (void *) &(inst->keepalive_probes)) != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP_OPT_X_KEEPALIVE_PROBES %d: %s", inst->xlat_name, inst->keepalive_probes, ldap_err2string(ldap_errno)); + } +#endif + +#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL + if (ldap_set_option(ld, LDAP_OPT_X_KEEPALIVE_INTERVAL, + (void *) &(inst->keepalive_interval)) != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] Could not set LDAP_OPT_X_KEEPALIVE_INTERVAL %d: %s", inst->xlat_name, inst->keepalive_interval, ldap_err2string(ldap_errno)); + } +#endif + #ifdef HAVE_LDAP_START_TLS - if(inst->tls_mode) { - DEBUG("rlm_ldap: setting TLS mode to %d", inst->tls_mode); - if(ldap_set_option(ld, LDAP_OPT_X_TLS, - (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) { + if (inst->tls_mode) { + DEBUG(" [%s] setting TLS mode to %d", inst->xlat_name, inst->tls_mode); + if (ldap_set_option(ld, LDAP_OPT_X_TLS, + (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) { ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); - radlog(L_ERR, "rlm_ldap: could not set LDAP_OPT_X_TLS option %s", ldap_err2string(ldap_errno)); + radlog(L_ERR, " [%s] could not set LDAP_OPT_X_TLS option %s:", inst->xlat_name, ldap_err2string(ldap_errno)); } } - if(inst->tls_cacertfile != NULL) { - DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertfile); + if (inst->tls_cacertfile != NULL) { + DEBUG(" [%s] setting TLS CACert File to %s", inst->xlat_name, inst->tls_cacertfile); if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTFILE, - (void *) inst->tls_cacertfile ) - != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: could not set " - "LDAP_OPT_X_TLS_CACERTFILE option to %s", inst->tls_cacertfile); + (void *) inst->tls_cacertfile ) + != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] could not set " + "LDAP_OPT_X_TLS_CACERTFILE option to %s: %s", + inst->xlat_name, + inst->tls_cacertfile, + ldap_err2string(ldap_errno)); } } - if(inst->tls_cacertdir != NULL) { - DEBUG("rlm_ldap: setting TLS CACert Directory to %s", inst->tls_cacertdir); + if (inst->tls_cacertdir != NULL) { + DEBUG(" [%s] setting TLS CACert Directory to %s", inst->xlat_name, inst->tls_cacertdir); if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTDIR, - (void *) inst->tls_cacertdir ) - != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: could not set " - "LDAP_OPT_X_TLS_CACERTDIR option to %s", inst->tls_cacertdir); + (void *) inst->tls_cacertdir ) + != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] could not set " + "LDAP_OPT_X_TLS_CACERTDIR option to %s: %s", + inst->xlat_name, + inst->tls_cacertdir, + ldap_err2string(ldap_errno)); } } - if( strcmp( TLS_DEFAULT_VERIFY, inst->tls_require_cert ) != 0 ) { - DEBUG("rlm_ldap: setting TLS Require Cert to %s", - inst->tls_require_cert); + if (strcmp(TLS_DEFAULT_VERIFY, inst->tls_require_cert ) != 0 ) { + DEBUG(" [%s] setting TLS Require Cert to %s", inst->xlat_name, + inst->tls_require_cert); } #ifdef HAVE_LDAP_INT_TLS_CONFIG - - if ( ldap_int_tls_config( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, - (inst->tls_require_cert) ) - != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: could not set " - "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s", - inst->tls_require_cert); + if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, + (inst->tls_require_cert)) != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] could not set ", + "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s: %s", + inst->xlat_name, + inst->tls_require_cert, + ldap_err2string(ldap_errno)); } - #endif - if(inst->tls_certfile != NULL) { - DEBUG("rlm_ldap: setting TLS Cert File to %s", inst->tls_certfile); + if (inst->tls_certfile != NULL) { + DEBUG(" [%s] setting TLS Cert File to %s", inst->xlat_name, inst->tls_certfile); - if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CERTFILE, - (void *) inst->tls_certfile ) - != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: could not set " - "LDAP_OPT_X_TLS_CERTFILE option to %s", - inst->tls_certfile); + if (ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, + (void *) inst->tls_certfile) + != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] could not set " + "LDAP_OPT_X_TLS_CERTFILE option to %s: %s", + inst->xlat_name, + inst->tls_certfile, + ldap_err2string(ldap_errno)); } } - if(inst->tls_keyfile != NULL) { - DEBUG("rlm_ldap: setting TLS Key File to %s", inst->tls_keyfile); + if (inst->tls_keyfile != NULL) { + DEBUG(" [%s] setting TLS Key File to %s", inst->xlat_name, + inst->tls_keyfile); if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_KEYFILE, - (void *) inst->tls_keyfile ) - != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: could not set " - "LDAP_OPT_X_TLS_KEYFILE option to %s", - inst->tls_keyfile); + (void *) inst->tls_keyfile ) + != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] could not set " + "LDAP_OPT_X_TLS_KEYFILE option to %s: %s", + inst->xlat_name, + inst->tls_keyfile, ldap_err2string(ldap_errno)); } } - if(inst->tls_randfile != NULL) { - DEBUG("rlm_ldap: setting TLS Key File to %s", inst->tls_randfile); + if (inst->tls_randfile != NULL) { + DEBUG(" [%s] setting TLS Key File to %s", inst->xlat_name, + inst->tls_randfile); - if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_RANDOM_FILE, - (void *) inst->tls_randfile ) - != LDAP_OPT_SUCCESS) { - radlog(L_ERR, "rlm_ldap: could not set " - "LDAP_OPT_X_TLS_RANDOM_FILE option to %s", - inst->tls_randfile); + if (ldap_set_option(NULL, LDAP_OPT_X_TLS_RANDOM_FILE, + (void *) inst->tls_randfile) + != LDAP_OPT_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); + radlog(L_ERR, " [%s] could not set " + "LDAP_OPT_X_TLS_RANDOM_FILE option to %s: %s", + inst->xlat_name, + inst->tls_randfile, ldap_err2string(ldap_errno)); } } + if (inst->start_tls) { - DEBUG("rlm_ldap: starting TLS"); + DEBUG(" [%s] starting TLS", inst->xlat_name); rc = ldap_start_tls_s(ld, NULL, NULL); if (rc != LDAP_SUCCESS) { - DEBUG("rlm_ldap: ldap_start_tls_s()"); - ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); - radlog(L_ERR, "rlm_ldap: could not start TLS %s", ldap_err2string(ldap_errno)); + DEBUG(" [%s] ldap_start_tls_s()", inst->xlat_name); + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, + &ldap_errno); + radlog(L_ERR, " [%s] could not start TLS %s", inst->xlat_name, + ldap_err2string(ldap_errno)); *result = RLM_MODULE_FAIL; ldap_unbind_s(ld); return (NULL); @@ -2089,11 +2420,13 @@ ldap_connect(void *instance, const char *dn, const char *password, int auth, int #endif /* HAVE_LDAP_START_TLS */ if (inst->is_url){ - DEBUG("rlm_ldap: bind as %s/%s to %s", dn, password, inst->server); - } - else{ - DEBUG("rlm_ldap: bind as %s/%s to %s:%d", dn, password, inst->server, inst->port); + DEBUG(" [%s] bind as %s/%s to %s", inst->xlat_name, + dn, password, inst->server); + } else { + DEBUG(" [%s] bind as %s/%s to %s:%d", inst->xlat_name, + dn, password, inst->server, inst->port); } + msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE); if (msgid == -1) { ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); @@ -2101,10 +2434,10 @@ ldap_connect(void *instance, const char *dn, const char *password, int auth, int ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err); } if (inst->is_url) { - radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s", + radlog(L_ERR, " [%s] %s bind to %s failed: %s", inst->xlat_name, dn, inst->server, ldap_err2string(ldap_errno)); } else { - radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s", + radlog(L_ERR, " [%s] %s bind to %s:%d failed: %s", inst->xlat_name, dn, inst->server, inst->port, ldap_err2string(ldap_errno)); } @@ -2112,42 +2445,44 @@ ldap_connect(void *instance, const char *dn, const char *password, int auth, int ldap_unbind_s(ld); return (NULL); } - DEBUG("rlm_ldap: waiting for bind result ..."); + DEBUG(" [%s] waiting for bind result ...", inst->xlat_name); - rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res); + tv.tv_sec = inst->timeout; + tv.tv_usec = 0; + rc = ldap_result(ld, msgid, 1, &tv, &res); - if(rc < 1) { - DEBUG("rlm_ldap: ldap_result()"); + if (rc < 1) { + DEBUG(" [%s] ldap_result()", inst->xlat_name); ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); if(err != NULL){ ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err); } if (inst->is_url) { - radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s", + radlog(L_ERR, " [%s] %s bind to %s failed: %s", inst->xlat_name, dn, inst->server, (rc == 0) ? "timeout" : ldap_err2string(ldap_errno)); } else { - radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s", - dn, inst->server, inst->port, + radlog(L_ERR, " [%s] %s bind to %s:%d failed: %s", inst->xlat_name, + dn, inst->server, inst->port, (rc == 0) ? "timeout" : ldap_err2string(ldap_errno)); } *result = RLM_MODULE_FAIL; ldap_unbind_s(ld); return (NULL); } + ldap_errno = ldap_result2error(ld, res, 1); switch (ldap_errno) { case LDAP_SUCCESS: - DEBUG("rlm_ldap: Bind was successful"); + DEBUG(" [%s] Bind was successful", inst->xlat_name); *result = RLM_MODULE_OK; break; case LDAP_INVALID_CREDENTIALS: if (auth){ - DEBUG("rlm_ldap: Bind failed with invalid credentials"); + DEBUG(" [%s] Bind failed with invalid credentials", inst->xlat_name); *result = RLM_MODULE_REJECT; - } - else { - radlog(L_ERR, "rlm_ldap: LDAP login failed: check identity, password settings in ldap section of radiusd.conf"); + } else { + radlog(L_ERR, " [%s] LDAP login failed: check identity, password settings in ldap section of radiusd.conf", inst->xlat_name); *result = RLM_MODULE_FAIL; } if(err != NULL){ @@ -2155,14 +2490,23 @@ ldap_connect(void *instance, const char *dn, const char *password, int auth, int } break; + case LDAP_CONSTRAINT_VIOLATION: + DEBUG("rlm_ldap: Bind failed with constraint violation"); + *result = RLM_MODULE_REJECT; + if(err != NULL){ + ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err); + } + break; + default: - if (inst->is_url) - radlog(L_ERR,"rlm_ldap: %s bind to %s failed %s", + if (inst->is_url) { + radlog(L_ERR," [%s] %s bind to %s failed %s", inst->xlat_name, dn, inst->server, ldap_err2string(ldap_errno)); - else - radlog(L_ERR,"rlm_ldap: %s bind to %s:%d failed %s", + } else { + radlog(L_ERR," [%s] %s bind to %s:%d failed %s", inst->xlat_name, dn, inst->server, inst->port, ldap_err2string(ldap_errno)); + } *result = RLM_MODULE_FAIL; if(err != NULL){ ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err); @@ -2187,38 +2531,10 @@ ldap_detach(void *instance) ldap_instance *inst = instance; TLDAP_RADIUS *pair, *nextpair; - if (inst->server) - free((char *) inst->server); - if (inst->login) - free((char *) inst->login); - if (inst->password) - free((char *) inst->password); - if (inst->basedn) - free((char *) inst->basedn); - if (inst->dictionary_mapping) - free(inst->dictionary_mapping); - if (inst->filter) - free((char *) inst->filter); - if (inst->base_filter) - free((char *) inst->base_filter); - if (inst->passwd_hdr) - free((char *) inst->passwd_hdr); - if (inst->passwd_attr) - free((char *) inst->passwd_attr); - if (inst->groupname_attr) - free((char *) inst->groupname_attr); - if (inst->groupmemb_filt) - free((char *) inst->groupmemb_filt); - if (inst->groupmemb_attr) - free((char *) inst->groupmemb_attr); - if (inst->access_attr) - free((char *) inst->access_attr); - if (inst->profile_attr) - free((char *) inst->profile_attr); - if (inst->conns){ - int i=0; + if (inst->conns) { + int i; - for(;inum_conns;i++){ + for (i = 0;i < inst->num_conns; i++) { if (inst->conns[i].ld){ ldap_unbind_s(inst->conns[i].ld); } @@ -2228,10 +2544,10 @@ ldap_detach(void *instance) } #ifdef NOVELL - if (inst->apc_conns){ + if (inst->apc_conns){ int i; - for(i = 0; i < inst->num_conns; i++){ + for (i = 0; i < inst->num_conns; i++) { if (inst->apc_conns[i].ld){ ldap_unbind_s(inst->apc_conns[i].ld); } @@ -2273,6 +2589,7 @@ ldap_detach(void *instance) return 0; } + #ifdef FIELDCPY static void fieldcpy(char *string, char **uptr) @@ -2304,29 +2621,57 @@ fieldcpy(char *string, char **uptr) return; } #endif + +/* + * Copied from src/lib/token.c + */ +static const FR_NAME_NUMBER tokens[] = { + { "=~", T_OP_REG_EQ, }, /* order is important! */ + { "!~", T_OP_REG_NE, }, + { "{", T_LCBRACE, }, + { "}", T_RCBRACE, }, + { "(", T_LBRACE, }, + { ")", T_RBRACE, }, + { ",", T_COMMA, }, + { "+=", T_OP_ADD, }, + { "-=", T_OP_SUB, }, + { ":=", T_OP_SET, }, + { "=*", T_OP_CMP_TRUE, }, + { "!*", T_OP_CMP_FALSE, }, + { "==", T_OP_CMP_EQ, }, + { "=", T_OP_EQ, }, + { "!=", T_OP_NE, }, + { ">=", T_OP_GE, }, + { ">", T_OP_GT, }, + { "<=", T_OP_LE, }, + { "<", T_OP_LT, }, + { NULL, 0} +}; + /***************************************************************************** * Get RADIUS attributes from LDAP object * ( according to draft-adoba-radius-05.txt * ) * *****************************************************************************/ - -static VALUE_PAIR * -ldap_pairget(LDAP * ld, LDAPMessage * entry, - TLDAP_RADIUS * item_map, VALUE_PAIR **pairs,char is_check) +static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry, + TLDAP_RADIUS *item_map, + VALUE_PAIR **pairs, int is_check, + ldap_instance *inst) { char **vals; int vals_count; int vals_idx; - char *ptr; - char *value; + const char *ptr; + const char *value; TLDAP_RADIUS *element; - LRAD_TOKEN token, operator; + FR_TOKEN token, operator; int is_generic_attribute; char buf[MAX_STRING_LEN]; VALUE_PAIR *pairlist = NULL; VALUE_PAIR *newpair = NULL; char do_xlat = FALSE; + char print_buffer[2048]; /* * check if there is a mapping from this LDAP attribute @@ -2362,15 +2707,15 @@ ldap_pairget(LDAP * ld, LDAPMessage * entry, /* * This is a generic attribute. */ - LRAD_TOKEN dummy; /* makes pairread happy */ + FR_TOKEN dummy; /* makes pairread happy */ /* not sure if using pairread here is ok ... */ if ( (newpair = pairread(&value, &dummy)) != NULL) { - DEBUG("rlm_ldap: extracted attribute %s from generic item %s", + DEBUG(" [%s] extracted attribute %s from generic item %s", inst->xlat_name, newpair->name, vals[vals_idx]); pairadd(&pairlist, newpair); } else { - radlog(L_ERR, "rlm_ldap: parsing %s failed: %s", + radlog(L_ERR, " [%s] parsing %s failed: %s", inst->xlat_name, element->attr, vals[vals_idx]); } } else { @@ -2381,7 +2726,9 @@ ldap_pairget(LDAP * ld, LDAPMessage * entry, operator = gettoken(&ptr, buf, sizeof(buf)); if (operator < T_EQSTART || operator > T_EQEND) { /* no leading operator found */ - if (is_check) + if (element->operator != T_OP_INVALID) + operator = element->operator; + else if (is_check) operator = T_OP_CMP_EQ; else operator = T_OP_EQ; @@ -2418,12 +2765,10 @@ ldap_pairget(LDAP * ld, LDAPMessage * entry, } } if (value[0] == '\0') { - DEBUG("rlm_ldap: Attribute %s has no value", element->attr); + DEBUG(" [%s] Attribute %s has no value", inst->xlat_name, element->attr); continue; } - DEBUG("rlm_ldap: Adding %s as %s, value %s & op=%d", element->attr, element->radius_attr, value, operator); - /* * Create the pair. */ @@ -2431,21 +2776,27 @@ ldap_pairget(LDAP * ld, LDAPMessage * entry, do_xlat ? NULL : value, operator); if (newpair == NULL) { - radlog(L_ERR, "rlm_ldap: Failed to create the pair: %s", librad_errstr); + radlog(L_ERR, " [%s] Failed to create the pair: %s", inst->xlat_name, fr_strerror()); continue; } + if (do_xlat) { newpair->flags.do_xlat = 1; - strNcpy(newpair->strvalue, buf, - sizeof(newpair->strvalue)); + strlcpy(newpair->vp_strvalue, buf, + sizeof(newpair->vp_strvalue)); newpair->length = 0; } + vp_prints(print_buffer, sizeof(print_buffer), + newpair); + DEBUG(" [%s] %s -> %s", inst->xlat_name, + element->attr, print_buffer); + /* * Add the pair into the packet. */ if (!vals_idx){ - pairdelete(pairs, newpair->attribute); + pairdelete(pairs, newpair->attribute, newpair->vendor); } pairadd(&pairlist, newpair); } @@ -2457,11 +2808,12 @@ ldap_pairget(LDAP * ld, LDAPMessage * entry, } /* globally exported name */ -module_t rlm_ldap = { +module_t rlm_ldap = { + RLM_MODULE_INIT, "LDAP", RLM_TYPE_THREAD_SAFE, /* type: reserved */ - NULL, /* initialization */ ldap_instantiate, /* instantiation */ + ldap_detach, /* detach */ { ldap_authenticate, /* authentication */ ldap_authorize, /* authorization */ @@ -2471,11 +2823,9 @@ module_t rlm_ldap = { NULL, /* pre-proxy */ NULL, /* post-proxy */ #ifdef NOVELL - ldap_postauth /* post-auth */ + ldap_postauth /* post-auth */ #else NULL #endif }, - ldap_detach, /* detach */ - NULL, /* destroy */ };