Port patch from branch_1_1 to the HEAD
[freeradius.git] / src / modules / rlm_ldap / rlm_ldap.c
index ef2ea55..eda5414 100644 (file)
@@ -19,7 +19,7 @@
  */
 static const char rcsid[] = "$Id$";
 
-#include "autoconf.h"
+#include <freeradius-devel/autoconf.h>
 
 #include       <sys/types.h>
 #include       <sys/socket.h>
@@ -41,10 +41,10 @@ static const char rcsid[] = "$Id$";
 #include       <unistd.h>
 #include       <pthread.h>
 
-#include       "radiusd.h"
-#include       "conffile.h"
-#include       "modules.h"
-#include       "rad_assert.h"
+#include       <freeradius-devel/radiusd.h>
+#include       <freeradius-devel/conffile.h>
+#include       <freeradius-devel/modules.h>
+#include       <freeradius-devel/rad_assert.h>
 
 #ifndef HAVE_PTHREAD_H
 /*
@@ -168,8 +168,9 @@ 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;
 
 /* The default setting for TLS Certificate Verification */
@@ -178,15 +179,15 @@ typedef struct {
 static CONF_PARSER tls_config[] = {
        {"start_tls", PW_TYPE_BOOLEAN,
         offsetof(ldap_instance,start_tls), NULL, "no"},
-       {"cacertfile", PW_TYPE_STRING_PTR,
+       {"cacertfile", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
-       {"cacertdir", PW_TYPE_STRING_PTR,
+       {"cacertdir", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
-       {"certfile", PW_TYPE_STRING_PTR,
+       {"certfile", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_certfile), NULL, NULL},
-       {"keyfile", PW_TYPE_STRING_PTR,
+       {"keyfile", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_keyfile), NULL, NULL},
-       {"randfile", PW_TYPE_STRING_PTR,
+       {"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},
@@ -225,19 +226,19 @@ static const CONF_PARSER module_config[] = {
 
        {"start_tls", PW_TYPE_BOOLEAN,
         offsetof(ldap_instance,start_tls), NULL, "no"},
-       {"tls_cacertfile", PW_TYPE_STRING_PTR,
+       {"tls_cacertfile", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
-       {"tls_cacertdir", PW_TYPE_STRING_PTR,
+       {"tls_cacertdir", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
-       {"tls_certfile", PW_TYPE_STRING_PTR,
+       {"tls_certfile", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_certfile), NULL, NULL},
-       {"tls_keyfile", PW_TYPE_STRING_PTR,
+       {"tls_keyfile", PW_TYPE_FILENAME,
         offsetof(ldap_instance,tls_keyfile), NULL, NULL},
-       {"tls_randfile", PW_TYPE_STRING_PTR,
+       {"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, tls_config, NULL },
+       { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
 
        /*
         *      DN's and filters.
@@ -284,7 +285,7 @@ static const CONF_PARSER module_config[] = {
         offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
 
        /* file with mapping between LDAP and RADIUS attributes */
-       {"dictionary_mapping", PW_TYPE_STRING_PTR,
+       {"dictionary_mapping", PW_TYPE_FILENAME,
         offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"},
 
        /*
@@ -307,6 +308,7 @@ static const CONF_PARSER module_config[] = {
         offsetof(ldap_instance,edir_account_policy_check), NULL, "yes"},
 #endif
 
+       {"set_auth_type", PW_TYPE_BOOLEAN, offsetof(ldap_instance,set_auth_type), NULL, "yes"},
        {NULL, -1, 0, NULL, NULL}
 };
 
@@ -319,7 +321,7 @@ static void     fieldcpy(char *, char **);
 #endif
 static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,int);
 static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
-static int ldap_xlat(void *,REQUEST *, char *, char *,int, RADIUS_ESCAPE_STRING);
+static int 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);
 
@@ -330,8 +332,13 @@ static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance)
 
        for(i=0;i<inst->num_conns;i++){
                DEBUG("rlm_ldap: ldap_get_conn: Checking Id: %d",i);
-               if ((conns[i].locked == 0) &&
-                   (pthread_mutex_trylock(&conns[i].mutex) == 0)) {
+               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);
@@ -368,7 +375,7 @@ ldap_instantiate(CONF_SECTION * conf, void **instance)
        int att_map[3] = {0,0,0};
        TLDAP_RADIUS *pair;
        ATTR_FLAGS flags;
-       char *xlat_name;
+       const char *xlat_name;
 
        inst = rad_malloc(sizeof *inst);
        if (!inst) {
@@ -421,19 +428,20 @@ ldap_instantiate(CONF_SECTION * conf, void **instance)
                /*
                 * Allocate room for <instance>-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);
                dattr = dict_attrbyname(group_name);
                if (dattr == NULL){
                        radlog(L_ERR, "rlm_ldap: Failed to create attribute %s",group_name);
+                       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);
@@ -443,6 +451,19 @@ ldap_instantiate(CONF_SECTION * conf, void **instance)
        DEBUG("rlm_ldap: Registering ldap_xlat with xlat_name %s",xlat_name);
        xlat_register(xlat_name,ldap_xlat,inst);
 
+       /*
+        *      Over-ride set_auth_type if there's no Auth-Type of our name.
+        *      This automagically catches the case where LDAP is listed
+        *      in "authorize", but not "authenticate".
+        */
+       if (inst->set_auth_type) {
+               DICT_VALUE *dv = dict_valbyname(PW_AUTH_TYPE, xlat_name);
+               if (!dv) {
+                       DEBUG2("rlm_ldap: Over-riding set_auth_type, as we're not listed in the \"authenticate\" section.");
+                       inst->set_auth_type = 0;
+               }
+       } /* else no need to look up the value */
+
 #ifdef NOVELL
        /*
         *      (LDAP_Instance, V1) attribute-value pair in the config
@@ -666,9 +687,6 @@ read_mappings(ldap_instance* inst)
                        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);
-                               free(pair->attr);
-                               free(pair->radius_attr);
-                               free(pair);
                                continue;
                        }
                }
@@ -822,24 +840,38 @@ static int ldap_escape_func(char *out, int outlen, const char *in)
 
        while (in[0]) {
                /*
-                *  Only one byte left.
+                *      Encode unsafe characters.
                 */
-               if (outlen <= 1) {
-                       break;
-               }
+               if (strchr("*=\\,()", *in)) {
+                       static const char hex[] = "0123456789abcdef";
 
-               if (strchr("*", *in)) {
+                       /*
+                        *      Only 3 or less bytes available.
+                        */
+                       if (outlen <= 3) {
+                               break;
+                       }
+
+                       *(out++) = '\\';
+                       *(out++) = hex[((*in) >> 4) & 0x0f];
+                       *(out++) = hex[(*in) & 0x0f];
+                       outlen -= 3;
+                       len += 3;
                        in++;
-                       outlen--;
                        continue;
                }
 
                /*
-                *      Else it's a nice character.
+                *      Only one byte left.
+                */
+               if (outlen <= 1) {
+                       break;
+               }
+
+               /*
+                *      Allowed character.
                 */
-               *out = *in;
-               out++;
-               in++;
+               *(out++) = *(in++);
                outlen--;
                len++;
        }
@@ -850,9 +882,10 @@ static int ldap_escape_func(char *out, int outlen, const char *in)
 /*
  *     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];
@@ -873,7 +906,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
 
        DEBUG("rlm_ldap: Entering ldap_groupcmp()");
 
-       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;
         }
@@ -936,14 +969,14 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
                 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);
+                        (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");
@@ -953,7 +986,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
        if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
                                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);
                return 0;
@@ -972,7 +1005,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
                 *      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;
        }
 
@@ -981,7 +1014,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
                radlog(L_ERR, "rlm_ldap: Add ldap connections are in use");
                return 1;
        }
-       if ((res = perform_search(inst, conn, vp_user_dn->strvalue,
+       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");
@@ -1006,7 +1039,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
                                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){
@@ -1023,7 +1056,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
                                        break;
                                }
                        } else {
-                               if (strcmp(vals[i],(char *)check->strvalue) == 0){
+                               if (strcmp(vals[i],(char *)check->vp_strvalue) == 0){
                                        found = 1;
                                        break;
                                }
@@ -1033,7 +1066,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
                ldap_msgfree(result);
                if (found == 0){
                        DEBUG("rlm_ldap::groupcmp: Group %s not found or user not a member",
-                               (char *)check->strvalue);
+                               (char *)check->vp_strvalue);
                        ldap_release_conn(conn_id,inst->conns);
                        return 1;
                }
@@ -1044,7 +1077,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
                        return 1;
        }
 
-       DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue);
+       DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->vp_strvalue);
        ldap_release_conn(conn_id,inst->conns);
 
         return 0;
@@ -1055,7 +1088,7 @@ static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
  * Do an xlat on an LDAP URL
  */
 static int ldap_xlat(void *instance, REQUEST *request, char *fmt,
-                    char *out, int freespace, RADIUS_ESCAPE_STRING func)
+                    char *out, size_t freespace, RADIUS_ESCAPE_STRING func)
 {
        char url[MAX_FILTER_STR_LEN];
        int res;
@@ -1209,12 +1242,12 @@ static int ldap_authorize(void *instance, REQUEST * request)
        /*
         * Check for valid input, zero length names not permitted
         */
-       if (request->username->strvalue == 0) {
+       if (request->username->vp_strvalue == 0) {
                radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
                return RLM_MODULE_INVALID;
        }
        DEBUG("rlm_ldap: performing user authorization for %s",
-              request->username->strvalue);
+              request->username->vp_strvalue);
 
        if (!radius_xlat(filter, sizeof(filter), inst->filter,
                         request, ldap_escape_func)) {
@@ -1266,7 +1299,7 @@ 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->strvalue, inst->access_attr);
+                               DEBUG("rlm_ldap: 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");
@@ -1313,7 +1346,7 @@ static int ldap_authorize(void *instance, REQUEST * request)
 
                strNcpy(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,
@@ -1420,7 +1453,7 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                        if (!p) continue;
                                        if ((p - value + 1) >= sizeof(autobuf))
                                                continue; /* paranoia */
-                                       memcpy(autobuf, p, p - value + 1);
+                                       memcpy(autobuf, value, p - value + 1);
                                        autobuf[p - value + 1] = '\0';
                                
                                        attr = lrad_str2int(header_names,
@@ -1436,7 +1469,7 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                                        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->strvalue);
+                                               DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0], request->username->vp_strvalue);
                                        }
                                }
                                if (!value) continue;
@@ -1450,13 +1483,13 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                        ldap_release_conn(conn_id,inst->conns);
                                        return RLM_MODULE_FAIL;
                                }
-                               strNcpy(passwd_item->strvalue, value,
-                                       sizeof(passwd_item->strvalue));
-                               passwd_item->length = strlen(passwd_item->strvalue);
+                               strNcpy(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",
                                      passwd_item->name,
-                                     passwd_item->strvalue);
+                                     passwd_item->vp_strvalue);
                        }
                        ldap_value_free(passwd_vals);
 #ifdef NOVELL_UNIVERSAL_PASSWORD
@@ -1480,7 +1513,7 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                memset(universal_password, 0, universal_password_len);
 
                                vp_user_dn = pairfind(request->config_items,PW_LDAP_USERDN);
-                               res = nmasldap_get_password(conn->ld,vp_user_dn->strvalue,&universal_password_len,universal_password);
+                               res = nmasldap_get_password(conn->ld,vp_user_dn->vp_strvalue,&universal_password_len,universal_password);
 
                                if (res == 0){
                                        passwd_val = universal_password;
@@ -1491,7 +1524,7 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                                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);
+                                                       DEBUG("rlm_ldap: Password header not found in password %s for user %s ",passwd_val,request->username->vp_strvalue);
                                        }
 
                                        if (passwd_val){
@@ -1505,7 +1538,7 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                                }
 
                                                passwd_len = strlen(passwd_val);
-                                               strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
+                                               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);
 
@@ -1534,8 +1567,8 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                                                        free(universal_password);
                                                                        return RLM_MODULE_FAIL;
                                                                }
-                                                               strcpy(vp_inst->strvalue, inst->xlat_name);
-                                                               vp_inst->length = strlen(vp_inst->strvalue);
+                                                               strcpy(vp_inst->vp_strvalue, inst->xlat_name);
+                                                               vp_inst->length = strlen(vp_inst->vp_strvalue);
                                                                pairadd(&request->config_items, vp_inst);
 
                                                                /*
@@ -1554,10 +1587,10 @@ static int ldap_authorize(void *instance, REQUEST * request)
 
                                                                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);
@@ -1565,7 +1598,7 @@ static int ldap_authorize(void *instance, REQUEST * request)
                                                }
 #endif
 
-                                               DEBUG("rlm_ldap: Added the eDirectory password %s in check items as %s",passwd_item->strvalue,passwd_item->name);
+                                               DEBUG("rlm_ldap: Added the eDirectory password %s in check items as %s",passwd_item->vp_strvalue,passwd_item->name);
                                        }
                                }
                                else {
@@ -1605,7 +1638,7 @@ static int 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;
@@ -1617,7 +1650,7 @@ static int 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.");
@@ -1632,16 +1665,18 @@ static int ldap_authorize(void *instance, REQUEST * request)
 
        /*
         * Module should default to LDAP authentication if no Auth-Type
-        * specified
+        * specified.  Note that we do this ONLY if configured, AND we
+        * set the Auth-Type to our module name, which allows multiple
+        * ldap instances to work.
         */
-       if ((pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) &&
+       if (inst->set_auth_type &&
+           (pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) &&
            request->password &&
            (request->password->attribute == PW_USER_PASSWORD))
-               pairadd(check_pairs, pairmake("Auth-Type", "LDAP", T_OP_EQ));
-
+               pairadd(check_pairs, pairmake("Auth-Type", inst->xlat_name, T_OP_EQ));
 
        DEBUG("rlm_ldap: user %s authorized to use remote access",
-             request->username->strvalue);
+             request->username->vp_strvalue);
        ldap_msgfree(result);
        ldap_release_conn(conn_id,inst->conns);
 
@@ -1660,15 +1695,18 @@ static int ldap_authenticate(void *instance, REQUEST * request)
        LDAP           *ld_user;
        LDAPMessage    *result, *msg;
        ldap_instance  *inst = instance;
-       char           *user_dn, *attrs[] = {"uid", NULL}, *err = NULL;
+       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];
        LDAP_CONN       *conn;
        int             conn_id = -1;
+#ifdef NOVELL
+       char            *err = NULL;
+#endif
 
        DEBUG("rlm_ldap: - authenticate");
 
@@ -1715,7 +1753,7 @@ static int ldap_authenticate(void *instance, REQUEST * request)
 
 
        DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"",
-              request->username->strvalue, request->password->strvalue);
+              request->username->vp_strvalue, request->password->vp_strvalue);
 
        while ((vp_user_dn = pairfind(request->config_items,
                                      PW_LDAP_USERDN)) == NULL) {
@@ -1761,16 +1799,16 @@ static int ldap_authenticate(void *instance, REQUEST * request)
                ldap_msgfree(result);
        }
 
-       user_dn = vp_user_dn->strvalue;
+       user_dn = vp_user_dn->vp_strvalue;
 
        DEBUG("rlm_ldap: 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,
+       ld_user = ldap_connect(instance, user_dn, request->password->vp_strvalue,
                        1, &res, &err);
 
        if(err != NULL){
@@ -1789,8 +1827,8 @@ static int ldap_authenticate(void *instance, REQUEST * request)
                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';
        }
 #endif
 
@@ -1809,7 +1847,7 @@ static int ldap_authenticate(void *instance, REQUEST * request)
        }
 
        DEBUG("rlm_ldap: user %s authenticated succesfully",
-             request->username->strvalue);
+             request->username->vp_strvalue);
        ldap_unbind_s(ld_user);
        inst->failed_conns = 0;
 
@@ -1846,12 +1884,12 @@ static int 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':
@@ -1860,18 +1898,15 @@ static int ldap_postauth(void *instance, REQUEST * request)
                        break;
                case '2':
                        {
-                               int err, conn_id = -1, i;
+                               int err, conn_id = -1;
                                char *error_msg = NULL;
-                               LDAP *ld;
                                VALUE_PAIR *vp_fdn, *vp_pwd;
                                DICT_ATTR *da;
-                               ldap_instance   *inst = instance;
-                               LDAP_CONN       *conn;
 
                                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);
+                                 strcpy(password, vp_pwd->vp_strvalue);
                                  if (strlen(password) > 0) {
                                          if (password[0] != 'a') {
                                                  password[0] = 'a';
@@ -1889,7 +1924,7 @@ static int ldap_postauth(void *instance, REQUEST * request)
                                                DEBUG("rlm_ldap: 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) {
@@ -1921,7 +1956,7 @@ static int ldap_postauth(void *instance, REQUEST * request)
                                                DEBUG2("rlm_ldap: closing existing LDAP connection");
                                                ldap_unbind_s(conn->ld);
                                        }
-                                       if ((conn->ld = ldap_connect(instance, (char *)vp_fdn->strvalue, password, 0, &res, &error_msg)) == NULL) {
+                                       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.");
                                                
                                                if (error_msg != NULL) {
@@ -1930,12 +1965,12 @@ static int ldap_postauth(void *instance, REQUEST * request)
                                                        ldap_memfree((void *)error_msg);
                                                }
                                                
-                                               vp_apc->strvalue[0] = '3';
+                                               vp_apc->vp_strvalue[0] = '3';
                                                ldap_release_conn(conn_id, inst->apc_conns);
                                                return RLM_MODULE_REJECT;
                                        }
                                        conn->bound = 1;
-                               } else if((err = ldap_simple_bind_s(conn->ld, (char *)vp_fdn->strvalue, password)) != LDAP_SUCCESS) {
+                               } 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;
@@ -1947,11 +1982,11 @@ static int ldap_postauth(void *instance, REQUEST * request)
                                                pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ));
                                                ldap_memfree((void *)error_msg);
                                        }
-                                       vp_apc->strvalue[0] = '3';
+                                       vp_apc->vp_strvalue[0] = '3';
                                        ldap_release_conn(conn_id, inst->apc_conns);
                                        return RLM_MODULE_REJECT;
                                }
-                               vp_apc->strvalue[0] = '3';
+                               vp_apc->vp_strvalue[0] = '3';
                                ldap_release_conn(conn_id, inst->apc_conns);
                                return RLM_MODULE_OK;
                        }
@@ -2044,7 +2079,7 @@ static LDAP *ldap_connect(void *instance, const char *dn, const char *password,
        }
 
 
-#ifdef HAVE_INT_TLS_CONFIG
+#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 "
@@ -2369,12 +2404,14 @@ static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
        int             vals_count;
        int             vals_idx;
        char           *ptr;
+       char           *value;
        TLDAP_RADIUS   *element;
-       LRAD_TOKEN      token;
+       LRAD_TOKEN      token, operator;
        int             is_generic_attribute;
-       char            value[256];
+       char            buf[MAX_STRING_LEN];
        VALUE_PAIR     *pairlist = NULL;
        VALUE_PAIR     *newpair = NULL;
+       char            do_xlat = FALSE;
 
        /*
         *      check if there is a mapping from this LDAP attribute
@@ -2396,22 +2433,24 @@ static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
                        is_generic_attribute = 1;
                else
                        is_generic_attribute = 0;
-               
+
                /*
                 *      Find out how many values there are for the
                 *      attribute and extract all of them.
                 */
                vals_count = ldap_count_values(vals);
-               
+
                for (vals_idx = 0; vals_idx < vals_count; vals_idx++) {
-                       ptr = vals[vals_idx];
-                       
+                       value = vals[vals_idx];
+
                        if (is_generic_attribute) {
-                               /* this is a generic attribute */
+                               /*
+                                *      This is a generic attribute.
+                                */
                                LRAD_TOKEN dummy; /* makes pairread happy */
-                               
+
                                /* not sure if using pairread here is ok ... */
-                               if ( (newpair = pairread(&ptr, &dummy)) != NULL) {
+                               if ( (newpair = pairread(&value, &dummy)) != NULL) {
                                        DEBUG("rlm_ldap: extracted attribute %s from generic item %s",
                                              newpair->name, vals[vals_idx]);
                                        pairadd(&pairlist, newpair);
@@ -2420,32 +2459,80 @@ static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
                                               element->attr, vals[vals_idx]);
                                }
                        } else {
-                               /* this is a one-to-one-mapped attribute */
-                               token = gettoken(&ptr, value, sizeof(value) - 1);
-                               if (token < T_EQSTART || token > T_EQEND) {
-                                       if (is_check) {
-                                               token = T_OP_CMP_EQ;
-                                       } else {
-                                               token = T_OP_EQ;
-                                       }
-                                       
-                                       if (element->operator != T_OP_INVALID) {
-                                               token = element->operator;
-                                       }
+                               /*
+                                *      This is a one-to-one-mapped attribute
+                                */
+                               ptr = value;
+                               operator = gettoken(&ptr, buf, sizeof(buf));
+                               if (operator < T_EQSTART || operator > T_EQEND) {
+                                       /* no leading operator found */
+                                       if (element->operator != T_OP_INVALID)
+                                               operator = element->operator;
+                                       else if (is_check)
+                                               operator = T_OP_CMP_EQ;
+                                       else
+                                               operator = T_OP_EQ;
                                } else {
-                                       gettoken(&ptr, value, sizeof(value) - 1);
+                                       /* the value is after the operator */
+                                       value = ptr;
                                }
-                               if (value[0] == 0) {
+
+                               /*
+                                *      Do xlat if the *entire* string
+                                *      is quoted.
+                                */
+                               if ((value[0] == '\'' || value[0] == '"' ||
+                                    value[0] == '`') &&
+                                   (value[0] == value[strlen(value)-1])) {
+                                       ptr = value;
+                                       token = gettoken(&ptr, buf, sizeof(buf));
+                                       switch (token) {
+                                       /* take the unquoted string */
+                                       case T_SINGLE_QUOTED_STRING:
+                                       case T_DOUBLE_QUOTED_STRING:
+                                               value = buf;
+                                               break;
+
+                                       /* the value will be xlat'ed later */
+                                       case T_BACK_QUOTED_STRING:
+                                               value = NULL;
+                                               do_xlat = TRUE;
+                                               break;
+
+                                       /* keep the original string */
+                                       default:
+                                               break;
+                                       }
+                               }
+                               if (value[0] == '\0') {
                                        DEBUG("rlm_ldap: Attribute %s has no value", element->attr);
-                                       break;
+                                       continue;
                                }
 
                                DEBUG("rlm_ldap: Adding LDAP attribute %s as RADIUS attribute %s %s %s",
-                                     element->attr,
-                                     element->radius_attr,
-                                     lrad_int2str(tokens, token, "?"), value);
-                               if ((newpair = pairmake(element->radius_attr, value, token)) == NULL)
+                                     element->attr, element->radius_attr,
+                                     lrad_int2str(tokens, operator, "?"),
+                                     value);
+
+                               /*
+                                *      Create the pair.
+                                */
+                               newpair = pairmake(element->radius_attr,
+                                                  value, operator);
+                               if (newpair == NULL) {
+                                       radlog(L_ERR, "rlm_ldap: Failed to create the pair: %s", librad_errstr);
                                        continue;
+                               }
+                               if (do_xlat) {
+                                       newpair->flags.do_xlat = 1;
+                                       strNcpy(newpair->vp_strvalue, buf,
+                                               sizeof(newpair->vp_strvalue));
+                                       newpair->length = 0;
+                               }
+
+                               /*
+                                *      Add the pair into the packet.
+                                */
                                if (!vals_idx){
                                        pairdelete(pairs, newpair->attribute);
                                }
@@ -2460,10 +2547,11 @@ static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
 
 /* globally exported name */
 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         */
@@ -2478,6 +2566,4 @@ module_t rlm_ldap = {
                NULL
 #endif
        },
-       ldap_detach,            /* detach                */
-       NULL,                   /* destroy               */
 };