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=cca03b46c608d60c0c6910e06193db31aa4a8a12;hpb=daba5a37057745dc43c82e3f1e0b3e0f9b32e231;p=freeradius.git diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index cca03b4..fabe118 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -15,37 +15,22 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * Copyright 2004 The FreeRADIUS Server Project. + * Copyright 2004,2006 The FreeRADIUS Server Project. */ -static const char rcsid[] = "$Id$"; -#include +#include +RCSID("$Id$") -#include -#include -#include -#include +#include +#include +#include -#include -#include -#include #include -#include #include -#include #include #include -#include -#include -#include - -#include -#include -#include -#include - #ifndef HAVE_PTHREAD_H /* * This is a lot simpler than putting ifdef's around @@ -56,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 @@ -103,11 +90,23 @@ int nmasldap_get_password( char *pwd ); #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; - LRAD_TOKEN operator; + FR_TOKEN operator; struct TLDAP_RADIUS* next; }; typedef struct TLDAP_RADIUS TLDAP_RADIUS; @@ -126,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; @@ -137,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; @@ -145,9 +146,7 @@ typedef struct { char *default_profile; char *profile_attr; char *access_attr; - char *passwd_hdr; char *passwd_attr; - int auto_header; char *dictionary_mapping; char *groupname_attr; char *groupmemb_filt; @@ -161,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; @@ -171,11 +171,39 @@ typedef struct { int edir_account_policy_check; #endif 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 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"}, @@ -209,10 +237,10 @@ static const CONF_PARSER module_config[] = { */ /* wait forever on network activity */ {"net_timeout", PW_TYPE_INTEGER, - offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"}, + offsetof(ldap_instance,net_timeout), NULL, "10"}, /* wait forever for search results */ {"timeout", PW_TYPE_INTEGER, - offsetof(ldap_instance,timeout.tv_sec), NULL, "20"}, + 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"}, @@ -257,12 +285,8 @@ static const CONF_PARSER module_config[] = { /* * Getting passwords from the database */ - {"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}, - {"auto_header", PW_TYPE_BOOLEAN, - offsetof(ldap_instance,auto_header), NULL, "no"}, /* * Access limitations @@ -272,6 +296,10 @@ static const CONF_PARSER module_config[] = { 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 @@ -309,6 +337,8 @@ static const CONF_PARSER module_config[] = { #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} }; @@ -319,19 +349,20 @@ static const CONF_PARSER module_config[] = { #ifdef FIELDCPY static void fieldcpy(char *, char **); #endif -static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,int); +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); + 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 */ @@ -341,7 +372,8 @@ static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance) /* 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; } } @@ -349,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 /************************************************************************* * @@ -382,6 +429,8 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) 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); @@ -405,8 +454,6 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) #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; @@ -417,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)); @@ -432,7 +492,7 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) 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); @@ -458,10 +518,18 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) * in "authorize", but not "authenticate". */ if (inst->set_auth_type) { - DICT_VALUE *dv = dict_valbyname(PW_AUTH_TYPE, xlat_name); + 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 we're not listed in the \"authenticate\" section."); + 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 */ } } /* else no need to look up the value */ @@ -472,19 +540,23 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) * instance 'V1' of the LDAP module has processed this * request. */ - dict_addattr("LDAP-Instance", 0, PW_TYPE_STRING, -1, flags); + 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("eDir-APC", 0, PW_TYPE_INTEGER, -1, flags); + dict_addattr("eDir-APC", -1, 0, PW_TYPE_STRING, flags); + /* + * eDir-Auth-Option allows for a different NMAS Authentication method to be used instead of password + */ + dict_addattr("eDir-Auth-Option", -1, 0, PW_TYPE_STRING, flags); #endif if (inst->num_conns <= 0){ @@ -561,6 +633,9 @@ 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."); @@ -570,7 +645,11 @@ ldap_instantiate(CONF_SECTION * conf, void **instance) 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) @@ -597,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); @@ -628,7 +710,7 @@ read_mappings(ldap_instance* inst) char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN]; char radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN]; int linenumber; - LRAD_TOKEN operator; + FR_TOKEN operator; char opstring[MAX_LINE_LEN]; /* open the mappings file for reading */ @@ -638,7 +720,8 @@ 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 */ } @@ -681,8 +764,6 @@ read_mappings(ldap_instance* inst) if (token_count == 3) { operator = T_OP_INVALID; /* use defaults */ } else { - char *ptr; - ptr = opstring; operator = gettoken(&ptr, buf, sizeof(buf)); if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) { @@ -741,11 +822,13 @@ static int perform_search(void *instance, LDAP_CONN *conn, 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){ @@ -757,14 +840,16 @@ static int perform_search(void *instance, LDAP_CONN *conn, } 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); @@ -772,19 +857,22 @@ retry: conn->bound = 1; conn->failed_conns = 0; } - DEBUG2("rlm_ldap: performing search in %s, with filter %s", + + 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, &(inst->timeout), result)) { + 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); @@ -794,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: @@ -810,21 +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", + 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", + 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); } @@ -835,15 +928,17 @@ 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]) { /* * Encode unsafe characters. */ - if (strchr("*=\\,()", *in)) { + if (((len == 0) && + ((in[0] == ' ') || (in[0] == '#'))) || + (strchr(",+\"\\<>;*=()", *in))) { static const char hex[] = "0123456789abcdef"; /* @@ -905,7 +1000,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, request_pairs = &req->config_items; - DEBUG("rlm_ldap: Entering ldap_groupcmp()"); + DEBUG(" [%s] Entering ldap_groupcmp()", inst->xlat_name); if (check->vp_strvalue == NULL || check->length == 0){ DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name"); @@ -922,7 +1017,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, 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, @@ -931,28 +1026,28 @@ static int ldap_groupcmp(void *instance, REQUEST *req, 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 @@ -980,7 +1075,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, (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"); + radlog(L_ERR, " [%s] All ldap connections are in use", inst->xlat_name); return 1; } @@ -989,11 +1084,11 @@ static int ldap_groupcmp(void *instance, REQUEST *req, DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s", (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"); @@ -1012,26 +1107,26 @@ static int ldap_groupcmp(void *instance, REQUEST *req, 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->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; + int i = 0; char found = 0; for (;i < ldap_count_values(vals);i++){ @@ -1048,7 +1143,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, 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 { @@ -1068,18 +1163,18 @@ static int ldap_groupcmp(void *instance, REQUEST *req, if (found == 0){ DEBUG("rlm_ldap::groupcmp: Group %s not found or user not a member", (char *)check->vp_strvalue); - ldap_release_conn(conn_id,inst->conns); + 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->vp_strvalue); - ldap_release_conn(conn_id,inst->conns); + ldap_release_conn(conn_id,inst); return 0; } @@ -1088,12 +1183,12 @@ static int ldap_groupcmp(void *instance, REQUEST *req, * ldap_xlat() * Do an xlat on an LDAP URL */ -static int ldap_xlat(void *instance, REQUEST *request, char *fmt, +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,24 +1197,24 @@ static int ldap_xlat(void *instance, REQUEST *request, char *fmt, 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]) || ! 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; } @@ -1127,47 +1222,47 @@ static int ldap_xlat(void *instance, REQUEST *request, char *fmt, 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."); + 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 @@ -1175,9 +1270,9 @@ static int ldap_xlat(void *instance, REQUEST *request, char *fmt, 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; } @@ -1186,9 +1281,9 @@ static int ldap_xlat(void *instance, REQUEST *request, char *fmt, /* * For auto-header discovery. */ -static const LRAD_NAME_NUMBER header_names[] = { - { "{clear}", PW_USER_PASSWORD }, - { "{cleartext}", PW_USER_PASSWORD }, +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 }, @@ -1229,12 +1324,11 @@ static int ldap_authorize(void *instance, REQUEST * request) char module_fmsg[MAX_STRING_LEN]; LDAP_CONN *conn; int conn_id = -1; - - DEBUG("rlm_ldap: - authorize"); + int added_known_password = 0; 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; @@ -1244,48 +1338,48 @@ static int ldap_authorize(void *instance, REQUEST * request) * Check for valid input, zero length names not permitted */ if (request->username->vp_strvalue == 0) { - radlog(L_ERR, "rlm_ldap: zero length username not permitted\n"); + DEBUG2("zero length username not permitted\n"); return RLM_MODULE_INVALID; } - DEBUG("rlm_ldap: performing user authorization for %s", + 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; } /* @@ -1300,37 +1394,37 @@ static int 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->vp_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; } } @@ -1341,11 +1435,11 @@ static int 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->vp_strvalue; if (profile && strlen(profile)){ @@ -1353,7 +1447,7 @@ static int ldap_authorize(void *instance, REQUEST * request) 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); @@ -1361,7 +1455,7 @@ static int 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); @@ -1372,7 +1466,7 @@ static int 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"); } } @@ -1386,13 +1480,13 @@ static int 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); @@ -1400,7 +1494,7 @@ static int 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); @@ -1411,7 +1505,7 @@ static int 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); @@ -1425,7 +1519,7 @@ static int ldap_authorize(void *instance, REQUEST * request) char **passwd_vals; char *value = NULL; int i; - + /* * Read the password from the DB, and * add it to the request. @@ -1440,57 +1534,25 @@ static int ldap_authorize(void *instance, REQUEST * request) passwd_vals[i] != NULL; i++) { int attr = PW_USER_PASSWORD; - + if (strlen(passwd_vals[i]) == 0) continue; - - value = passwd_vals[i]; - if (inst->auto_header) { - char *p; - char autobuf[16]; - - p = strchr(value, '}'); - if (!p) continue; - if ((p - value + 1) >= sizeof(autobuf)) - continue; /* paranoia */ - memcpy(autobuf, value, p - value + 1); - autobuf[p - value + 1] = '\0'; - - attr = lrad_str2int(header_names, - autobuf, 0); - if (!attr) continue; - value = p + 1; - goto create_attr; - - } else if (inst->passwd_hdr && - strlen(inst->passwd_hdr)) { - if (strncasecmp(value, - inst->passwd_hdr, - strlen(inst->passwd_hdr)) == 0) { - value += strlen(inst->passwd_hdr); - } else { - DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0], request->username->vp_strvalue); - } - } + value = passwd_vals[i]; if (!value) continue; - + create_attr: - passwd_item = paircreate(attr, PW_TYPE_STRING); - if (!passwd_item) { - 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; - } - strNcpy(passwd_item->vp_strvalue, value, + 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); - pairadd(&request->config_items,passwd_item); - DEBUG("rlm_ldap: Added %s = %s in check items", + 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 @@ -1501,47 +1563,27 @@ static int 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_USER_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->config_items,PW_LDAP_USERDN); + 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->vp_strvalue); - } - if (passwd_val){ - if ((passwd_item = paircreate(PW_USER_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_len = strlen(passwd_val); - strncpy(passwd_item->vp_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); + 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; #ifdef NOVELL { @@ -1560,32 +1602,16 @@ static int 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->vp_strvalue, inst->xlat_name); + 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); - pairadd(&request->config_items, vp_inst); /* * 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_INTEGER)) == 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->vp_strvalue, "1"); @@ -1594,30 +1620,53 @@ static int ldap_authorize(void *instance, REQUEST * request) strcpy(vp_apc->vp_strvalue, "2"); } vp_apc->length = 1; - pairadd(&request->config_items, vp_apc); } } #endif - DEBUG("rlm_ldap: Added the eDirectory password %s in check items as %s",passwd_item->vp_strvalue,passwd_item->name); + 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); @@ -1627,10 +1676,10 @@ static int 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); @@ -1654,15 +1703,28 @@ static int ldap_authorize(void *instance, REQUEST * request) 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 @@ -1671,17 +1733,18 @@ static int 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)) { - pairadd(check_pairs, pairmake("Auth-Type", inst->xlat_name, T_OP_EQ)); - DEBUG("rlm_ldap: Setting Auth-Type = %s", inst->xlat_name); + (request->password->attribute == PW_USER_PASSWORD) && + !added_known_password) { + 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", + 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; } @@ -1711,33 +1774,31 @@ static int 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; @@ -1755,48 +1816,48 @@ static int ldap_authenticate(void *instance, REQUEST * request) } - DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"", + RDEBUG("login attempt by \"%s\" with password \"%s\"", request->username->vp_strvalue, request->password->vp_strvalue); while ((vp_user_dn = pairfind(request->config_items, - PW_LDAP_USERDN)) == NULL) { + 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); + 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); @@ -1804,52 +1865,179 @@ static int ldap_authenticate(void *instance, REQUEST * request) 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->vp_strvalue, 1, &res, NULL); #else - - ld_user = ldap_connect(instance, user_dn, request->password->vp_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->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", + RDEBUG("user %s authenticated succesfully", request->username->vp_strvalue); ldap_unbind_s(ld_user); inst->failed_conns = 0; @@ -1908,7 +2096,7 @@ static int ldap_postauth(void *instance, REQUEST * request) 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); + vp_pwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); strcpy(password, vp_pwd->vp_strvalue); if (strlen(password) > 0) { if (password[0] != 'a') { @@ -1922,27 +2110,27 @@ static int ldap_postauth(void *instance, REQUEST * request) 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); + vp_pwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); if (vp_pwd == NULL) { - DEBUG("rlm_ldap: User's Universal Password not in config items list."); + RDEBUG("User's Universal Password not in config items list."); return RLM_MODULE_FAIL; } 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); + + vp_fdn = pairfind(request->config_items, da->attr); if (vp_fdn == NULL) { - DEBUG("rlm_ldap: User's FQDN not in config items list."); + 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; } @@ -1954,22 +2142,22 @@ static int ldap_postauth(void *instance, REQUEST * request) */ 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->vp_strvalue, password, 0, &res, &error_msg)) == NULL) { - radlog(L_ERR, "rlm_ldap: eDirectory account policy check failed."); - + radlog(L_ERR, " [%s] eDirectory account policy check failed.", inst->xlat_name); + if (error_msg != NULL) { - DEBUG("rlm_ldap: %s", error_msg); + RDEBUG("%s", error_msg); pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ)); ldap_memfree((void *)error_msg); } - + vp_apc->vp_strvalue[0] = '3'; - ldap_release_conn(conn_id, inst->apc_conns); + ldap_release_apc_conn(conn_id, inst); return RLM_MODULE_REJECT; } conn->bound = 1; @@ -1978,19 +2166,19 @@ static int ldap_postauth(void *instance, REQUEST * request) 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); + RDEBUG("%s", error_msg); pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ)); ldap_memfree((void *)error_msg); } vp_apc->vp_strvalue[0] = '3'; - ldap_release_conn(conn_id, inst->apc_conns); + ldap_release_apc_conn(conn_id, inst); return RLM_MODULE_REJECT; } vp_apc->vp_strvalue[0] = '3'; - ldap_release_conn(conn_id, inst->apc_conns); + ldap_release_apc_conn(conn_id, inst); return RLM_MODULE_OK; } } @@ -1998,6 +2186,18 @@ static int ldap_postauth(void *instance, REQUEST * request) } #endif +#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) { @@ -2006,78 +2206,142 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, 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); + 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); } } + tv.tv_sec = inst->net_timeout; + tv.tv_usec = 0; 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); + (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)); + } + + /* + * 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) { - radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit); + 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"); + 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); + 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); + 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); + 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); - + 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); + 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", + DEBUG(" [%s] setting TLS Require Cert to %s", inst->xlat_name, inst->tls_require_cert); } @@ -2085,58 +2349,68 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, #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); + 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); + 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); + 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", + 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); + 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", + 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); + 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()"); + DEBUG(" [%s] ldap_start_tls_s()", inst->xlat_name); ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); - radlog(L_ERR, "rlm_ldap: could not start TLS %s", + radlog(L_ERR, " [%s] could not start TLS %s", inst->xlat_name, ldap_err2string(ldap_errno)); *result = RLM_MODULE_FAIL; ldap_unbind_s(ld); @@ -2146,10 +2420,10 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, #endif /* HAVE_LDAP_START_TLS */ if (inst->is_url){ - DEBUG("rlm_ldap: bind as %s/%s to %s", + DEBUG(" [%s] bind as %s/%s to %s", inst->xlat_name, dn, password, inst->server); } else { - DEBUG("rlm_ldap: bind as %s/%s to %s:%d", + DEBUG(" [%s] bind as %s/%s to %s:%d", inst->xlat_name, dn, password, inst->server, inst->port); } @@ -2160,10 +2434,10 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, 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)); } @@ -2171,21 +2445,23 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, 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()"); + 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", + 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)); } @@ -2197,16 +2473,16 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, 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"); + 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){ @@ -2214,12 +2490,20 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password, } 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", + 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)); } @@ -2247,38 +2531,9 @@ 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; - + for (i = 0;i < inst->num_conns; i++) { if (inst->conns[i].ld){ ldap_unbind_s(inst->conns[i].ld); @@ -2289,7 +2544,7 @@ ldap_detach(void *instance) } #ifdef NOVELL - if (inst->apc_conns){ + if (inst->apc_conns){ int i; for (i = 0; i < inst->num_conns; i++) { @@ -2370,7 +2625,7 @@ fieldcpy(char *string, char **uptr) /* * Copied from src/lib/token.c */ -static const LRAD_NAME_NUMBER tokens[] = { +static const FR_NAME_NUMBER tokens[] = { { "=~", T_OP_REG_EQ, }, /* order is important! */ { "!~", T_OP_REG_NE, }, { "{", T_LCBRACE, }, @@ -2401,20 +2656,22 @@ static const LRAD_NAME_NUMBER tokens[] = { *****************************************************************************/ static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry, TLDAP_RADIUS *item_map, - VALUE_PAIR **pairs, int is_check) + 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 @@ -2450,15 +2707,15 @@ static VALUE_PAIR *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 { @@ -2508,15 +2765,10 @@ static VALUE_PAIR *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 LDAP attribute %s as RADIUS attribute %s %s %s", - element->attr, element->radius_attr, - lrad_int2str(tokens, operator, "?"), - value); - /* * Create the pair. */ @@ -2524,21 +2776,27 @@ static VALUE_PAIR *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->vp_strvalue, buf, + 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); }