New version of the module.
authorpam <pam>
Thu, 11 Jan 2001 15:54:49 +0000 (15:54 +0000)
committerpam <pam>
Thu, 11 Jan 2001 15:54:49 +0000 (15:54 +0000)
o Instantiation support (no more global variables)
o uses both GroupOfNames and GroupOfUniqueNames objects
o Removed default configuration hack (now that module failover code is done)
o Non-threaded version uses global module lock (RLM_TYPE_THREAD_UNSAFE)
o Changed to standard C formating (8-space tabs and C comments)
o New documentation in radiusd/doc/README.rlm_ldap
o Faster group membership verification (offloads work to LDAP server)
o "dialupAccess" attribute (which controls user authorization) now configurable
  from radiusd.conf
o Does not use LDAP cache, due to threading problems.

src/modules/rlm_ldap/INSTALL [deleted file]
src/modules/rlm_ldap/rlm_ldap.c

diff --git a/src/modules/rlm_ldap/INSTALL b/src/modules/rlm_ldap/INSTALL
deleted file mode 100644 (file)
index 6ce8da0..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-### LDAP module INSTALL ###
-This module depends on OpenLDAP v2.0 SDK libraries. As 2.0 branch is still considered unstable pre-release, you should obtain either current code snapshot or check out it sources from CVS. For details on obtaining source of OpenLDAP look at <http://www.openldap.org>. OpenLDAP SDK in turn depends on OpenSSL crypto libraries and Cyrus-SASL libraries.
-
-### Configuration ###
-
-Add following section to the radius.conf to control the rlm_ldap module:
----------->8----------------->8--------------------->8---------------
-module ldap {
-
-#      server: space separated list of host[:port]
-#      default: settings for your system, as set in etc/openldap/ldap.conf
-       server   = localhost
-
-#      net_timeout: # of seconds to wait for response of the server 
-#                      (network failures)
-#      default: forever
-#
-       net_timeout = 3
-
-#      timeout: # seconds to wait for LDAP query to finish
-#      default: forever
-#
-       timeout = 3
-
-#      cache_size: size in KB of LDAP cache
-#      default: cache size limited only by entry TTL
-#
-
-#      cache_ttl: time in seconds result of LDAP query is deemed valid
-#      default: 30
-
-#      identity: DN under which LDAP searches are done
-#      password: pasword which authenticate this DN
-#      default: anonymous bind, no password required
-#      NOTE: searches are done now over unencrypted connection!
-#
-#      identity = "cn=admin,o=My Org,c=US"
-#      password = mypass
-
-#      basedn = <Base of LDAP searches>
-#
-       basedn   = "o=My Org,c=US"
-
-#      filter: LDAP search filter, to locate user object using radius login name
-       filter   = "(uid=%u)"
-
-#      access_group: membership in this group controls radius access for user
-#      default: all users
-       access_group = "cn=RemoteUsers,o=My Org,c=US"
-
-}
index 1ef1ee4..4dd6eed 100644 (file)
 /*
- * rlm_ldap.c  LDAP authorization and authentication module.  
- *             This module is based on LDAP patch to Cistron radiusd, which in 
- *             turn was based mostly on a Mysql+Cistron patch from oyarzun@wilmington.net
- *
- * Version:    $Id$
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Copyright 2000  The FreeRADIUS server project
- * Copyright 2000  Adrian Pavlykevych <pam@polynet.lviv.ua>
- * Copyright 2000  Alan DeKok <aland@ox.org>
+ * rlm_ldap.c LDAP authorization and authentication module.
+ * 
+ * 
+ * This module is based on LDAP patch to Cistron radiusd, which in turn was
+ * based mostly on a Mysql+Cistron patch from oyarzun@wilmington.net
+ * 
+ * 17 Jan 2000: - OpenLDAP SDK porting, basic TLS support, LDAP authorization,
+ * fault tolerance with multiple LDAP server support done by Adrian
+ * Pavlykevych <pam@polynet.lviv.ua> 24 May 2000: - Converting to new
+ * configuration file format, futher improvements in fault tolerance,
+ * threaded operation Adrian Pavlykevych <pam@polynet.lviv.ua> 12 Dec 2000: -
+ * Added preliminary support for multiple instances - moved all instance
+ * configuration into dynamicly allocated structure - Removed connection
+ * maintenance thread and all attempts for multihreading the module itself.
+ * OpenLDAP SDK is not thread safe when used with shared LDAP connection. -
+ * Added configuration option for defining LDAP attribute of user object,
+ * which controls remote access.
  */
-
 static const char rcsid[] = "$Id$";
 
 #include "autoconf.h"
-#include "libradius.h"
 
+#include       <sys/types.h>
 #include       <sys/socket.h>
-
-#ifdef HAVE_NETINET_IN_H
+#include       <sys/time.h>
 #include       <netinet/in.h>
-#endif
 
 #include       <stdio.h>
 #include       <stdlib.h>
 #include       <netdb.h>
 #include       <pwd.h>
+#include       <time.h>
 #include       <ctype.h>
 #include       <string.h>
 
 #include       <lber.h>
 #include        <ldap.h>
 
+#include       <errno.h>
+#include       <unistd.h>
+#include       <pthread.h>
+
 #include       "radiusd.h"
 #include       "conffile.h"
 #include       "modules.h"
 
-#define DIALUP_ACCESS 1
+
 #define MAX_AUTH_QUERY_LEN      256
 #define TIMELIMIT 5
 
 typedef struct {
-  char* attr;
-  char* radius_attr;
-} TLDAP_RADIUS;
-
-static char    *make_filter(char *, char *);
-
-static char            *dn_base(char *);
-static VALUE_PAIR      *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *);
-static LDAP            *rlm_ldap_connect(const char *, const char *, int, int *);
+       const char     *attr;
+       const char     *radius_attr;
+}               TLDAP_RADIUS;
 
+static char    *make_filter(char *, char *);
+#ifdef FIELDCPY
+static void     fieldcpy(char *, char **);
+#endif
+static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *);
+static LDAP    *ldap_connect(void *instance, const char *, const char *, int, int *);
 
 #define MAX_SERVER_LINE 1024
 /*
- *     These should really be in a module-specific data structure,
- *     which is passed to the module with every request.
+ * These should really be in a module-specific data structure, which is
+ * passed to the module with every request.
  */
-static char    *ldap_server = NULL;
-static int     ldap_port = 389;
-static int     ldap_timelimit = TIMELIMIT;
-/* wait forever on network activity */
-static struct timeval ldap_net_timeout = { -1, 0 };
-/* wait forever for search results */
-static struct timeval ldap_timeout = { -1, 0 };
+
 static struct timeval *timeout = NULL;
-static int     ldap_cache_size = 0; /* cache size limited only by TTL */
-static int     ldap_cache_ttl = 30 ;/* cache objects TTL 30 secs */    
-static int     ldap_debug = 0; /* 0x0005; */
-static int     ldap_tls_mode = LDAP_OPT_X_TLS_TRY;
-static char    *ldap_login    = NULL;
-static char    *ldap_password = NULL;
-static char    *ldap_filter   = NULL;
-static char    *ldap_basedn   = NULL;
-static char    *group_basedn  = NULL;
-static char    *ldap_radius_group = NULL;
-
-static LDAP    *ld = NULL;
+
+typedef struct {
+       char           *server;
+       int             port;
+       int             timelimit;
+       struct timeval  net_timeout;
+       struct timeval  timeout;
+       int             debug;
+       int             tls_mode;
+       char           *login;
+       char           *password;
+       char           *filter;
+       char           *basedn;
+       char           *access_group;
+       char           *access_attr;
+       LDAP           *ld;
+       int             bound;
+}               ldap_instance;
+
+static ldap_instance config;
 
 static CONF_PARSER module_config[] = {
-  { "server",          PW_TYPE_STRING_PTR, &ldap_server,             NULL },
-  { "port",            PW_TYPE_INTEGER,    &ldap_port,               "389" },
-  { "net_timeout",     PW_TYPE_INTEGER,    &ldap_net_timeout.tv_sec, "-1" },
-  { "timeout",         PW_TYPE_INTEGER,    &ldap_timeout.tv_sec,     "-1" },
-
-  { "identity",                PW_TYPE_STRING_PTR, &ldap_login,              NULL },
-  { "password",                PW_TYPE_STRING_PTR, &ldap_password,           NULL },
-  { "basedn",          PW_TYPE_STRING_PTR, &ldap_basedn,             NULL },
-  { "filter",          PW_TYPE_STRING_PTR, &ldap_filter,             NULL },
-  { "access_group",    PW_TYPE_STRING_PTR, &ldap_radius_group,       NULL },
-
-  { "cache_size",      PW_TYPE_INTEGER,    &ldap_cache_size,         "0" },
-  { "cache_ttl",       PW_TYPE_INTEGER,    &ldap_cache_ttl,          "30" },
-  
-  { NULL, -1, NULL, NULL }
+       {"server", PW_TYPE_STRING_PTR, &config.server, NULL},
+       {"port", PW_TYPE_INTEGER, &config.port, "389"},
+       /* wait forever on network activity */
+       {"net_timeout", PW_TYPE_INTEGER, &config.net_timeout.tv_sec, "-1"},
+       /* wait forever for search results */
+       {"timeout", PW_TYPE_INTEGER, &config.timeout.tv_sec, "-1"},
+       /* allow server unlimited time for search (server-side limit) */
+       {"timelimit", PW_TYPE_INTEGER, &config.timelimit, "-1"},
+
+       {"identity", PW_TYPE_STRING_PTR, &config.login, NULL},
+       {"password", PW_TYPE_STRING_PTR, &config.password, NULL},
+       {"basedn", PW_TYPE_STRING_PTR, &config.basedn, NULL},
+       {"filter", PW_TYPE_STRING_PTR, &config.filter, NULL},
+       {"access_group", PW_TYPE_STRING_PTR, &config.access_group, NULL},
+       /* LDAP attribute name that controls remote access */
+       {"access_attr", PW_TYPE_STRING_PTR, &config.access_attr, NULL},
+       /* cache size limited only by TTL */
+       /* cache objects TTL 30 secs */
+
+       {NULL, -1, NULL, NULL}
 };
 
-/* LDAP attribute name that controls remote access */
-#define LDAP_RADIUSACCESS "dialupAccess"
-
-/*
- *     Fallback to default settings if no basic attributes defined in
- *     object
- *
- *     (An ugly hack to be replaced by profiles and policies,
- *     or by new configuration file support...)
- */
-#define DEFAULT_CONF
-
-#ifdef DEFAULT_CONF
-#define DEFAULT_SERVICE_TYPE "Framed-User"
-#define DEFAULT_FRAMED_PROTOCOL "PPP"
-#define DEFAULT_FRAMED_MTU "576"
-#define DEFAULT_FRAMED_COMPRESSION "Van-Jacobson-TCP-IP"
-#define DEFAULT_IDLE_TIMEOUT "240"
-#define DEFAULT_SIMULTANEOUS_USE "1"
-#endif
-
 #define ld_valid                ld_options.ldo_valid
 #define LDAP_VALID_SESSION      0x2
 #define LDAP_VALID(ld)  ( (ld)->ld_valid == LDAP_VALID_SESSION )
 
 /*
- *      Mappings of LDAP radius* attributes to RADIUS attributes
- *
- *     Hmm... these should really be read in from the configuration file
+ * Mappings of LDAP radius* attributes to RADIUS attributes
+ * 
+ * Hmm... these should really be read in from the configuration file
  */
 static TLDAP_RADIUS check_item_map[] = {
-        { "radiusAuthType", "Auth-Type" },
-        { "npSessionsAllowed", "Simultaneous-Use" },
-        {NULL, NULL}
+       {"radiusAuthType", "Auth-Type"},
+       {"npSessionsAllowed", "Simultaneous-Use"},
+       {NULL, NULL}
 };
 static TLDAP_RADIUS reply_item_map[] = {
-       { "radiusServiceType", "Service-Type" },
-       { "radiusFramedProtocol", "Framed-Protocol" },
-       { "radiusFramedIPAddress", "Framed-IP-Address" },
-       { "radiusFramedIPNetmask", "Framed-IP-Netmask" },
-       { "radiusFramedRoute", "Framed-Route" },
-       { "radiusFramedRouting", "Framed-Routing" },
-       { "radiusFilterId", "Filter-Id" },
-       { "radiusFramedMTU", "Framed-MTU" },
-       { "radiusFramedCompression", "Framed-Compression" },
-       { "radiusLoginIPHost", "Login-IP-Host" },
-       { "radiusLoginService", "Login-Service" },
-       { "radiusLoginTCPPort", "Login-TCP-Port" },
-       { "radiusCallbackNumber", "Callback-Number" },
-       { "radiusCallbackId", "Callback-Id" },
-       { "radiusFramedRoute", "Framed-Route" },
-       { "radiusFramedIPXNetwork", "Framed-IPX-Network" },
-       { "radiusClass", "Class" },
-       { "radiusSessionTimeout", "Session-Timeout" },
-       { "radiusIdleTimeout", "Idle-Timeout" },
-       { "radiusTerminationAction", "Termination-Action" },
-       { "radiusCalledStationId", "Called-Station-Id" },
-       { "radiusCallingStationId", "Calling-Station-Id" },
-       { "radiusLoginLATService", "Login-LAT-Service" },
-       { "radiusLoginLATNode", "Login-LAT-Node" },
-       { "radiusLoginLATGroup", "Login-LAT-Group" },
-       { "radiusFramedAppleTalkLink", "Framed-AppleTalk-Link" },
-       { "radiusFramedAppleTalkNetwork", "Framed-AppleTalk-Network" },
-       { "radiusFramedAppleTalkZone", "Framed-AppleTalk-Zone" },
-       { "radiusPortLimit", "Port-Limit" },
-       { "radiusLoginLATPort", "Login-LAT-Port" },
-        {NULL, NULL}
+       {"radiusServiceType", "Service-Type"},
+       {"radiusFramedProtocol", "Framed-Protocol"},
+       {"radiusFramedIPAddress", "Framed-IP-Address"},
+       {"radiusFramedIPNetmask", "Framed-IP-Netmask"},
+       {"radiusFramedRoute", "Framed-Route"},
+       {"radiusFramedRouting", "Framed-Routing"},
+       {"radiusFilterId", "Filter-Id"},
+       {"radiusFramedMTU", "Framed-MTU"},
+       {"radiusFramedCompression", "Framed-Compression"},
+       {"radiusLoginIPHost", "Login-IP-Host"},
+       {"radiusLoginService", "Login-Service"},
+       {"radiusLoginTCPPort", "Login-TCP-Port"},
+       {"radiusCallbackNumber", "Callback-Number"},
+       {"radiusCallbackId", "Callback-Id"},
+       {"radiusFramedRoute", "Framed-Route"},
+       {"radiusFramedIPXNetwork", "Framed-IPX-Network"},
+       {"radiusClass", "Class"},
+       {"radiusSessionTimeout", "Session-Timeout"},
+       {"radiusIdleTimeout", "Idle-Timeout"},
+       {"radiusTerminationAction", "Termination-Action"},
+       {"radiusCalledStationId", "Called-Station-Id"},
+       {"radiusCallingStationId", "Calling-Station-Id"},
+       {"radiusLoginLATService", "Login-LAT-Service"},
+       {"radiusLoginLATNode", "Login-LAT-Node"},
+       {"radiusLoginLATGroup", "Login-LAT-Group"},
+       {"radiusFramedAppleTalkLink", "Framed-AppleTalk-Link"},
+       {"radiusFramedAppleTalkNetwork", "Framed-AppleTalk-Network"},
+       {"radiusFramedAppleTalkZone", "Framed-AppleTalk-Zone"},
+       {"radiusPortLimit", "Port-Limit"},
+       {"radiusLoginLATPort", "Login-LAT-Port"},
+       {NULL, NULL}
 };
 
 /*************************************************************************
@@ -183,92 +165,93 @@ static TLDAP_RADIUS reply_item_map[] = {
  *     Function: rlm_ldap_instantiate
  *
  *     Purpose: Uses section of radiusd config file passed as parameter
- *              to create an instance ofthe module.
- *     Note:    Currently multiple instances are not supported, lots of
- *              data structures restructuring should be done to support it 
+ *              to create an instance of the module.
  *
  *************************************************************************/
-static int rlm_ldap_instantiate(CONF_SECTION *conf, void **instance)
+static int 
+ldap_instantiate(CONF_SECTION * conf, void **instance)
 {
-       int res;
-       int i;
-
-       cf_section_parse(conf, module_config);
-       
-       if(ldap_radius_group != NULL)
-               group_basedn = dn_base(ldap_radius_group);
-       if(ldap_net_timeout.tv_sec != -1)
-               timeout = &ldap_net_timeout;
-       if(ldap_timeout.tv_sec != -1 )
-               timeout = &ldap_timeout;
-       
-       if(timeout != NULL)
-               DEBUG("timeout: %ld.%ld", timeout->tv_sec,timeout->tv_usec);
-       
-       if ((ld = rlm_ldap_connect(ldap_login, ldap_password, 0, &res)) == NULL) {
-               DEBUG("rlm_ldap: Could not connect to LDAP");
+       ldap_instance  *inst;
+
+       inst = malloc(sizeof *inst);
+       if (!inst) {
+               radlog(L_ERR | L_CONS, "rlm_ldap: Out of memory\n");
+               return -1;
+       }
+       if (cf_section_parse(conf, module_config) < 0) {
+               free(inst);
                return -1;
        }
+       inst->server = config.server;
+       inst->port = config.port;
+       inst->timeout.tv_sec = config.timeout.tv_sec;
+       inst->timeout.tv_usec = 0;
+       inst->net_timeout.tv_sec = config.net_timeout.tv_sec;
+       inst->net_timeout.tv_usec = 0;
+       inst->timelimit = config.timelimit;
+       inst->debug = config.debug;
+       inst->tls_mode = LDAP_OPT_X_TLS_TRY;
+       inst->login = config.login;
+       inst->password = config.password;
+       inst->filter = config.filter;
+       inst->basedn = config.basedn;
+       inst->access_group = config.access_group;
+       inst->access_attr = config.access_attr;
+       inst->bound = 0;
+
+       *instance = inst;
 
-       //DEBUG("rlm_ldap: Disabling LDAP cache");
-  //ldap_disable_cache(ld);
-  return 0;
+       return 0;
 }
 
-
-static int perform_search(char *ldap_basedn, char *filter, char **attrs, LDAPMessage **result)
+static int 
+perform_search(void *instance, char *search_basedn, int scope, char *filter, char **attrs, LDAPMessage ** result)
 {
-  
-       int msgid;
-       int res = RLM_MODULE_OK;
-       int rc;
-       
-       ld = rlm_ldap_connect(ldap_login, ldap_password, 0, &res);
-       
-       
-       DEBUG("rlm_ldap: performing search with filter '%s'", filter);
-       msgid = ldap_search(ld,ldap_basedn,LDAP_SCOPE_SUBTREE,filter,attrs,0);
-       DEBUG("rlm_ldap: ok, search done, continuing...");
-       
-       if(msgid == -1) {
-               radlog(L_ERR,"rlm_ldap: ldap_search() API failed\n");
-               return RLM_MODULE_FAIL;
+       int             msgid;
+       int             res = RLM_MODULE_OK;
+       int             rc;
+       ldap_instance  *inst = instance;
+
+       if (!inst->bound) {
+               DEBUG2("rlm_ldap: attempting LDAP reconnection");
+               if ((inst->ld = ldap_connect(instance, inst->login, inst->password, 0, &res)) == NULL) {
+                       radlog(L_ERR, "rlm_ldap: (re)connection attempt failed");
+                       return (RLM_MODULE_FAIL);
+               }
+               inst->bound = 1;
        }
-       
-       
-       rc = ldap_result(ld, msgid, 1, timeout, result);
-       
-       DEBUG("rlm_ldap: ok, got a result, continuing...");
-       if(rc < 1) {
-               DEBUG("rlm_ldap: result is less than desirable. :\(");
-               ldap_perror( ld, "rlm_ldap: ldap_result()" );
-               radlog(L_ERR,"rlm_ldap: ldap_result() failed - %s\n", strerror(errno));
-               return RLM_MODULE_FAIL;
+       DEBUG2("rlm_ldap: performing search in %s, with filter %s", search_basedn, filter);
+       msgid = ldap_search(inst->ld, search_basedn, scope, filter, attrs, 0);
+       if (msgid == -1) {
+               radlog(L_ERR, "rlm_ldap: ldap_search() API failed\n");
+               inst->bound = 0;
+               return (RLM_MODULE_FAIL);
        }
-       
-       DEBUG("rlm_ldap: result is valid");
-       switch(ldap_result2error(ld, *result, 0)) {
+       rc = ldap_result(inst->ld, msgid, 1, timeout, result);
+
+       if (rc < 1) {
+               ldap_perror(inst->ld, "rlm_ldap: ldap_result()");
+               radlog(L_ERR, "rlm_ldap: ldap_result() failed - %s\n", strerror(errno));
+               return (RLM_MODULE_FAIL);
+       }
+       switch (ldap_result2error(inst->ld, *result, 0)) {
        case LDAP_SUCCESS:
                break;
-               
+
        case LDAP_TIMELIMIT_EXCEEDED:
                radlog(L_ERR, "rlm_ldap: Warning timelimit exceeded, using partial results\n");
                break;
-               
+
        default:
                DEBUG("rlm_ldap: ldap_search() failed");
-               ldap_msgfree(*result);
-               return RLM_MODULE_FAIL;
+               inst->bound = 0;
+               return (RLM_MODULE_FAIL);
        }
-       
-       if ((ldap_count_entries(ld, *result)) != 1) {
-               DEBUG("rlm_ldap: user object not found or got ambiguous search result");
-               ldap_msgfree(*result);
+
+       if ((ldap_count_entries(inst->ld, *result)) != 1) {
+               DEBUG("rlm_ldap: object not found or got ambiguous search result");
                res = RLM_MODULE_NOTFOUND;
-       } else {
-               DEBUG("rlm_ldap: single result returned. good.");
        }
-       
        return res;
 }
 
@@ -276,308 +259,251 @@ static int perform_search(char *ldap_basedn, char *filter, char **attrs, LDAPMes
  *
  *      Function: rlm_ldap_authorize
  *
- *      Purpose: Check if user is authorized for remote access 
+ *      Purpose: Check if user is authorized for remote access
  *
- *****************************************************************************/
-static int rlm_ldap_authorize(void *instance, REQUEST *request)
+ ******************************************************************************/
+static int 
+ldap_authorize(void *instance, REQUEST * request)
 {
-       LDAPMessage *result, *msg, *gr_result, *gr_msg;
-       char *filter, *name, *user_dn;
-       const char *attrs[]     = { "*", NULL };
-       const *group_attrs[] = { "member", NULL };
-       char **vals;
-       VALUE_PAIR      *check_tmp;
-       VALUE_PAIR      *reply_tmp;
-       int  i;
-       int      res;
-       VALUE_PAIR **check_pairs, **reply_pairs;
-       
+       LDAPMessage    *result, *msg, *gr_result;
+       ldap_instance  *inst = instance;
+       char           *filter, *name, *user_dn;
+       char           *attrs[] = {"*", NULL};
+       VALUE_PAIR     *check_tmp;
+       VALUE_PAIR     *reply_tmp;
+       int             res;
+       VALUE_PAIR    **check_pairs, **reply_pairs;
+       char          **vals;
+
        check_pairs = &request->config_items;
        reply_pairs = &request->reply->vps;
-       
-       DEBUG("rlm_ldap: authorize");
+
+       DEBUG("rlm_ldap: authorize");
        name = request->username->strvalue;
-       
+
        /*
-        *      Check for valid input, zero length names not permitted
+        * Check for valid input, zero length names not permitted
         */
        if (name[0] == 0) {
                radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
                return RLM_MODULE_INVALID;
        }
-       
-/*  Unfortunately LDAP queries are case insensitive, so in order to provide
-    unique names for simultaneous logins verification, we need to lowercase
-    USERNAME attribute value
-*/
-       for(i=0; name[i] != 0; i++) 
-               name[i] = tolower(name[i]);
-       
        DEBUG("rlm_ldap: performing user authorization for %s", name);
-       
-       filter = make_filter(ldap_filter, name);
-       
-       res = perform_search(ldap_basedn, filter, attrs, &result);
-       
-       
-       if ((msg = ldap_first_entry(ld,result)) == NULL) {
+
+       filter = make_filter(inst->filter, name);
+
+       if ((res = perform_search(instance, inst->basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
+               DEBUG("rlm_ldap: search failed");
+               ldap_msgfree(result);
+               return (res);
+       }
+       if ((msg = ldap_first_entry(inst->ld, result)) == NULL) {
                DEBUG("rlm_ldap: ldap_first_entry() failed");
                ldap_msgfree(result);
                return RLM_MODULE_FAIL;
        }
-       
-       if ((user_dn = ldap_get_dn(ld,msg)) == NULL) {
+       if ((user_dn = ldap_get_dn(inst->ld, msg)) == NULL) {
                DEBUG("rlm_ldap: ldap_get_dn() failed");
                ldap_msgfree(result);
                return RLM_MODULE_FAIL;
        }
-       
-       /*
-        *      Remote access is controlled by LDAP_RADIUSACCESS
-        *      attribute of user object
-        */
-       if((vals = ldap_get_values(ld, msg, LDAP_RADIUSACCESS)) != NULL ) {
-               if(!strncmp(vals[0],"FALSE",5)) {
-                       DEBUG("rlm_ldap: dialup access disabled");
+       /* Remote access is controled by attribute of the user object */
+       if (inst->access_attr) {
+               if ((vals = ldap_get_values(inst->ld, msg, inst->access_attr)) != NULL) {
+                       DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", name, inst->access_attr);
+                       if (!strncmp(vals[0], "FALSE", 5)) {
+                               DEBUG("rlm_ldap: dialup access disabled");
+                               ldap_msgfree(result);
+                               return RLM_MODULE_USERLOCK;
+                       }
+               } else {
+                       DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr);
                        ldap_msgfree(result);
-                       return RLM_MODULE_REJECT;
+                       return RLM_MODULE_USERLOCK;
                }
-       } else {
-               DEBUG("rlm_ldap: no %s attribute - access denied by default", LDAP_RADIUSACCESS);
-               ldap_msgfree(result);
-               return RLM_MODULE_REJECT;
        }
-       
-       /*
-        *      Remote access controlled by group membership attribute
-        *      of user object
-        */
-       if(ldap_radius_group != NULL) {
-               int found = 0;
-               
-               DEBUG("rlm_ldap: checking user membership in dialup-enabling group %s", ldap_radius_group);
-               if((res = perform_search(group_basedn, ldap_radius_group, group_attrs, &gr_result)))
-                       return(res);
-               
-               if ((gr_msg = ldap_first_entry(ld, gr_result)) == NULL) {
-                       DEBUG("rlm_ldap: ldap_first_entry() failed");
-                       ldap_msgfree(result);
-                       return RLM_MODULE_FAIL;
-               }
-               
-               if ((vals = ldap_get_values(ld, gr_msg, "member")) != NULL ) {
-                       int valno;
-                       for(valno = 0;
-                           (vals[valno] != NULL) 
-                                   && !(found = !strncmp(vals[valno],user_dn,strlen(user_dn)));
-                           valno++) {
-                       }
-                       ldap_value_free(vals);
-               }
-               
+       /* Remote access controled by group membership of the user object */
+       if (inst->access_group != NULL) {
+               DEBUG("rlm_ldap: checking user membership in dialup-enabling group %s", inst->access_group);
+               /*
+                * uniquemember appears in Netscape Directory Server's groups
+                * since we have objectclass groupOfNames and
+                * groupOfUniqueNames
+                */
+               filter = make_filter("(| (& (objectClass=GroupOfNames) (member=%u)) (& (objectClass=GroupOfUniqueNames) (uniquemember=%u)))", user_dn);
+               res = perform_search(instance, inst->access_group, LDAP_SCOPE_BASE, filter, NULL, &gr_result);
                ldap_msgfree(gr_result);
-               
-               if (!found) {
-                       DEBUG("rlm_ldap: user does not belong to dialup-enabling group");
-                       ldap_msgfree(result);
-                       return RLM_MODULE_REJECT;
+
+
+               if (res != RLM_MODULE_OK) {
+                       if (res == RLM_MODULE_NOTFOUND)
+                               return (RLM_MODULE_USERLOCK);
+                       else
+                               return (res);
                }
        }
-       
-       
-       DEBUG("rlm_ldap: looking for check items in directory..."); 
-       if ((check_tmp = ldap_pairget(ld, msg, check_item_map)) != (VALUE_PAIR *)0) {
+       DEBUG("rlm_ldap: looking for check items in directory...");
+       if ((check_tmp = ldap_pairget(inst->ld, msg, check_item_map)) != NULL)
                pairadd(check_pairs, check_tmp);
-       }
-       
+
+
        /*
-        *      Module should default to LDAP authentication if no
-        *      Auth-Type specified
-        *
-        *      FIXME: This should be a configuration parameter.
+        * Module should default to LDAP authentication if no Auth-Type
+        * specified
         */
-       if(pairfind(*check_pairs, PW_AUTHTYPE) == NULL){
+       if (pairfind(*check_pairs, PW_AUTHTYPE) == NULL)
                pairadd(check_pairs, pairmake("Auth-Type", "LDAP", T_OP_CMP_EQ));
-       }
 
-       /* 
-        *      Adding new attribute containing DN for LDAP object
-        *      associated with given username
+       /*
+        * Adding new attribute containing DN for LDAP object associated with
+        * given username
         */
        pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
-       
-       DEBUG("rlm_ldap: looking for reply items in directory..."); 
-       if((reply_tmp = ldap_pairget(ld,msg, reply_item_map)) != (VALUE_PAIR *)0) {
+
+       DEBUG("rlm_ldap: looking for reply items in directory...");
+
+       if ((reply_tmp = ldap_pairget(inst->ld, msg, reply_item_map)) != NULL)
                pairadd(reply_pairs, reply_tmp);
-       }
-       
-#ifdef DEFAULT_CONF
-       if(pairfind(*reply_pairs, PW_SERVICE_TYPE) == NULL){
-               pairadd(reply_pairs, pairmake("Service-Type", DEFAULT_SERVICE_TYPE, T_OP_EQ));
-       }
-       if(pairfind(*reply_pairs, PW_FRAMED_PROTOCOL) == NULL){
-               pairadd(reply_pairs, pairmake("Framed-Protocol", DEFAULT_FRAMED_PROTOCOL, T_OP_EQ));
-       }
-       if(pairfind(*reply_pairs, PW_FRAMED_MTU) == NULL){
-               pairadd(reply_pairs, pairmake("Framed-MTU", DEFAULT_FRAMED_MTU, T_OP_EQ));
-       }
-       if(pairfind(*reply_pairs, PW_FRAMED_COMPRESSION) == NULL){
-               pairadd(reply_pairs, pairmake("Framed-Compression", DEFAULT_FRAMED_COMPRESSION, T_OP_EQ));
-       }
-       if(pairfind(*reply_pairs, PW_IDLE_TIMEOUT) == NULL){
-               pairadd(reply_pairs, pairmake("Idle-Timeout", DEFAULT_IDLE_TIMEOUT, T_OP_EQ));       
-       }
-       if(pairfind(*check_pairs, PW_SIMULTANEOUS_USE) == NULL){
-               pairadd(check_pairs, pairmake("Simultaneous-Use", DEFAULT_SIMULTANEOUS_USE, T_OP_EQ));       
-       }
-#endif
-       
+
        DEBUG("rlm_ldap: user %s authorized to use remote access", name);
        ldap_msgfree(result);
        return RLM_MODULE_OK;
 }
 
-/******************************************************************************
+/*****************************************************************************
  *
  *     Function: rlm_ldap_authenticate
  *
- *     Purpose: Check the user's password against ldap database 
+ *     Purpose: Check the user's password against ldap database
  *
  *****************************************************************************/
-static int rlm_ldap_authenticate(void *instance, REQUEST *request)
+static int 
+ldap_authenticate(void *instance, REQUEST * request)
 {
-       LDAP *ld_user;
-       LDAPMessage *result, *msg;
-       char *filter, *passwd, *user_dn, *name;
-       const char *attrs[] = { "uid", NULL };
-       int  res;
-       VALUE_PAIR *vp_user_dn;
-       
-       DEBUG("rlm_ldap: authenticate");
-
+       LDAP           *ld_user;
+       LDAPMessage    *result, *msg;
+       ldap_instance  *inst = instance;
+       char           *filter, *passwd, *user_dn, *name, *attrs[] = {"uid", NULL};
+       int             res;
+       VALUE_PAIR     *vp_user_dn;
+
+       DEBUG("rlm_ldap: - authenticate");
        /*
-        *      Ensure that we're being passed a plain-text password,
-        *      and not anything else.
+        * Ensure that we're being passed a plain-text password, and not
+        * anything else.
         */
        if (request->password->attribute != PW_PASSWORD) {
                radlog(L_AUTH, "rlm_ldap: Attribute \"Password\" is required for authentication.  Cannot use \"%s\".", request->password->name);
                return RLM_MODULE_INVALID;
        }
-       
        name = request->username->strvalue;
        passwd = request->password->strvalue;
-       
-       if (request->password->length == 0) {
+
+       if (strlen(passwd) == 0) {
                radlog(L_ERR, "rlm_ldap: empty password supplied");
                return RLM_MODULE_INVALID;
        }
-       
        DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"", name, passwd);
-       filter = make_filter(ldap_filter, name);
-       
-       if((vp_user_dn = pairfind(request->packet->vps, LDAP_USERDN)) == NULL){
-               if((res = perform_search(ldap_basedn, filter, attrs, &result)))
-                       return(res);
-               
-               if ((msg = ldap_first_entry(ld,result)) == NULL) {
+       filter = make_filter(inst->filter, name);
+
+       if ((vp_user_dn = pairfind(request->packet->vps, LDAP_USERDN)) == NULL) {
+               if ((res = perform_search(instance, inst->basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
+                       DEBUG("rlm_ldap: search did not return ok value", name);
+                       return (res);
+               }
+               if ((msg = ldap_first_entry(inst->ld, result)) == NULL) {
                        ldap_msgfree(result);
-                       
                        return RLM_MODULE_FAIL;
                }
-               
-               if ((user_dn = ldap_get_dn(ld,msg)) == NULL) {
+               if ((user_dn = ldap_get_dn(inst->ld, msg)) == NULL) {
                        DEBUG("rlm_ldap: ldap_get_dn() failed");
                        ldap_msgfree(result);
-                       
                        return RLM_MODULE_FAIL;
                }
-               pairadd(&request->packet->vps,pairmake("Ldap-UserDn",user_dn,T_OP_EQ));
+               pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
                ldap_msgfree(result);
-               
-       } else {        
+       } else {
                user_dn = vp_user_dn->strvalue;
        }
-       
+
        DEBUG("rlm_ldap: user DN: %s", user_dn);
-       
-       if ((ld_user = rlm_ldap_connect(user_dn, passwd, 1, &res)) == NULL)
-               return res;
-       
+
+       ld_user = ldap_connect(instance, user_dn, passwd, 1, &res);
+
+       if (ld_user == NULL)
+               return (res);
+
        DEBUG("rlm_ldap: user %s authenticated succesfully", name);
        ldap_unbind_s(ld_user);
        return RLM_MODULE_OK;
 }
 
-static LDAP *rlm_ldap_connect(const char *dn, const char *password, int auth, int *result)
+static LDAP    *
+ldap_connect(void *instance, const char *dn, const char *password, int auth, int *result)
 {
-       LDAP *ld;
-       int msgid, rc;
-       LDAPMessage  *res;
-       
-       DEBUG("rlm_ldap: (re)connect, authentication %d", auth);
-       if ((ld = ldap_init(ldap_server,ldap_port)) == NULL){
-               radlog(L_ERR, "rlm_ldap: ldap_init() failed");      
+       ldap_instance  *inst = instance;
+       LDAP           *ld;
+       int             msgid, rc;
+       LDAPMessage    *res;
+
+       DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth);
+       if ((ld = ldap_init(inst->server, inst->port)) == NULL) {
+               radlog(L_ERR, "rlm_ldap: ldap_init() failed");
                *result = RLM_MODULE_FAIL;
-               return(NULL);
+               return (NULL);
        }
-       
-       if (timeout != NULL && ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)timeout) != LDAP_OPT_SUCCESS) {
-               radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", timeout->tv_sec, timeout->tv_usec);
+       if (inst->net_timeout.tv_sec != -1 && 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);
        }
-       
-       if (ldap_timelimit != -1 && ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &ldap_timelimit) != LDAP_OPT_SUCCESS ){
-               radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", ldap_timelimit );
+       if (inst->timelimit != -1 && 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);
        }
-       
-       if(ldap_debug && ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_debug ) != LDAP_OPT_SUCCESS ) {
-               radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", ldap_debug);
+       if (inst->debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->debug)) != LDAP_OPT_SUCCESS) {
+               radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->debug);
        }
 #ifdef HAVE_TLS
-       if (ldap_tls_mode && ldap_set_option(ld, LDAP_OPT_X_TLS,(void *) &ldap_tls_mode) != LDAP_OPT_SUCCESS ){
+       if (inst->tls_mode && ldap_set_option(ld, LDAP_OPT_X_TLS, (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) {
                radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_X_TLS_TRY");
        }
 #endif
-       
-       if (!auth)
-               if (ldap_enable_cache(ld, ldap_cache_ttl, ldap_cache_size) != LDAP_SUCCESS)
-                       radlog(L_ERR,"rlm_ldap: ldap_enable_cache failed");
-       
+
+       DEBUG("rlm_ldap: connect as %s/%s", dn, password);
        msgid = ldap_bind(ld, dn, password, LDAP_AUTH_SIMPLE);
-       if(msgid == -1) {
-               ldap_perror(ld, "rlm_ldap: rlm_ldap_connect()" );
+       if (msgid == -1) {
+               ldap_perror(ld, "rlm_ldap: ldap_connect()");
                *result = RLM_MODULE_FAIL;
-               ldap_unbind_s(ld);
-               return(NULL);
+               ldap_unbind_s(inst->ld);
+               return (NULL);
        }
-       
-       DEBUG("rlm_ldap: rlm_ldap_connect() waiting for bind result ...");
-       
-       rc = ldap_result(ld, msgid, 1, timeout, &res);
-       if(rc < 1){
-               ldap_perror( ld, "rlm_ldap: ldap_result()" );
+       DEBUG("rlm_ldap: ldap_connect() waiting for bind result ...");
+
+       if (inst->timeout.tv_sec < 0)
+               rc = ldap_result(ld, msgid, 1, NULL, &res);
+       else
+               rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res);
+
+       if (rc < 1) {
+               ldap_perror(ld, "rlm_ldap: ldap_result()");
                *result = RLM_MODULE_FAIL;
                ldap_unbind_s(ld);
-               return(NULL);
+               return (NULL);
        }
-       DEBUG("rlm_ldap: rlm_ldap_connect() bind finished, let's check the results");
-       switch(ldap_result2error(ld, res, 1)) {
+       DEBUG("rlm_ldap: ldap_connect() bind finished");
+       switch (ldap_result2error(ld, res, 1)) {
        case LDAP_SUCCESS:
                *result = RLM_MODULE_OK;
                break;
-               
+
        case LDAP_INVALID_CREDENTIALS:
-               if(auth){
+               if (auth) {
                        *result = RLM_MODULE_REJECT;
                        break;
                }
        default:
-               ldap_perror( ld, "rlm_ldap: ldap_result()" );
-               radlog(L_ERR,"rlm_ldap: ldap_result() failed - %s\n", strerror(errno));
                DEBUG("rlm_ldap: LDAP FAILURE");
                *result = RLM_MODULE_FAIL;
-       } 
-
-       if(*result != RLM_MODULE_OK) {
+       }
+       if (*result != RLM_MODULE_OK) {
                ldap_unbind_s(ld);
                ld = NULL;
        }
@@ -585,36 +511,33 @@ static LDAP *rlm_ldap_connect(const char *dn, const char *password, int auth, in
 }
 
 /*****************************************************************************
- * 
+ *
  *     Detach from the LDAP server and cleanup internal state.
- *     
- *****************************************************************************/
-static int rlm_ldap_detach(void *instance)
-{
-       ldap_unbind_s(ld);
-       return 0;
-}
-
-/*****************************************************************************
- * 
- * This function takes DN as parameter and returns RDN and BASEDN for search.
- * Has anyone better idea about getting object attributes based on its DN?
  *
  *****************************************************************************/
-static char *dn_base(char *dn)
+static int 
+ldap_detach(void *instance)
 {
-       char *ptr;
-       
-       if((ptr = (char *)strchr(dn, ',')) == NULL) {
-               DEBUG("Invalid DN syntax: no ',' in the string %s, maibe it's a CN? Returning default base", dn);  
-               return(ldap_basedn);
-       }
-       ptr[0]='\0';
-       if(++ptr == NULL) {
-               DEBUG("Invalid DN syntax: ',' is the last symbol in the string");  
-               return(NULL);
-       }
-       return(ptr);
+       ldap_instance  *inst = instance;
+
+       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->access_group)
+               free((char *) inst->access_group);
+       if (inst->filter)
+               free((char *) inst->filter);
+       if (inst->ld)
+               ldap_unbind_s(inst->ld);
+
+       free(inst);
+
+       return 0;
 }
 
 /*****************************************************************************
@@ -622,53 +545,55 @@ static char *dn_base(char *dn)
  *
  *     %u   User name
  *
- *     FIXME: Why is this function even here?  What's wrong with radius_xlat2?
- *
  *****************************************************************************/
-static char *make_filter(char *str, char *name)
+static char    *
+make_filter(char *str, char *name)
 {
-       static char buf[MAX_AUTH_QUERY_LEN];
-       int i = 0, c;
-       char *p;
-       
-       for(p = str; *p; p++) {
+       static char     buf[MAX_AUTH_QUERY_LEN];
+       int             i = 0, c;
+       char           *p;
+
+       for (p = str; *p; p++) {
                c = *p;
                if (c != '%' && c != '\\') {
                        buf[i++] = *p;
                        continue;
                }
-               if (*++p == 0) break;
-               if (c == '%') switch(*p) {
-               case '%':
-                       buf[i++] = *p;
-                       break;
-               case 'u': /* User name */
-                       if (name != NULL)
-                               strcpy(buf + i, name);
-                       else
-                               strcpy(buf + i, " ");
-                       i += strlen(buf + i);
-                       break;
-               default:
-                       buf[i++] = '%';
-                       buf[i++] = *p;
-                       break;
-               }
-               if (c == '\\') switch(*p) {
-               case 'n':
-                       buf[i++] = '\n';
-                       break;
-               case 'r':
-                       buf[i++] = '\r';
+               if (*++p == 0)
                        break;
-               case 't':
-                       buf[i++] = '\t';
-                       break;
-               default:
-                       buf[i++] = '\\';
-                       buf[i++] = *p;
-                       break;
-               }
+               if (c == '%')
+                       switch (*p) {
+                       case '%':
+                               buf[i++] = *p;
+                               break;
+                       case 'u':       /* User name */
+                               if (name != NULL)
+                                       strcpy(buf + i, name);
+                               else
+                                       strcpy(buf + i, " ");
+                               i += strlen(buf + i);
+                               break;
+                       default:
+                               buf[i++] = '%';
+                               buf[i++] = *p;
+                               break;
+                       }
+               if (c == '\\')
+                       switch (*p) {
+                       case 'n':
+                               buf[i++] = '\n';
+                               break;
+                       case 'r':
+                               buf[i++] = '\r';
+                               break;
+                       case 't':
+                               buf[i++] = '\t';
+                               break;
+                       default:
+                               buf[i++] = '\\';
+                               buf[i++] = *p;
+                               break;
+                       }
        }
        if (i >= MAX_AUTH_QUERY_LEN)
                i = MAX_AUTH_QUERY_LEN - 1;
@@ -676,44 +601,74 @@ static char *make_filter(char *str, char *name)
        return buf;
 }
 
+#ifdef FIELDCPY
+static void 
+fieldcpy(char *string, char **uptr)
+{
+       char           *ptr;
+
+       ptr = *uptr;
+       while (*ptr == ' ' || *ptr == '\t') {
+               ptr++;
+       }
+       if (*ptr == '"') {
+               ptr++;
+               while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
+                       *string++ = *ptr++;
+               }
+               *string = '\0';
+               if (*ptr == '"') {
+                       ptr++;
+               }
+               *uptr = ptr;
+               return;
+       }
+       while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
+              *ptr != '=' && *ptr != ',') {
+               *string++ = *ptr++;
+       }
+       *string = '\0';
+       *uptr = ptr;
+       return;
+}
+#endif
 /*****************************************************************************
  *     Get RADIUS attributes from LDAP object
- *     ( according to draft-adoba-radius-05.txt 
+ *     ( according to draft-adoba-radius-05.txt
  *       <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
  *
  *****************************************************************************/
 
-static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
-                               TLDAP_RADIUS *item_map)
+static VALUE_PAIR *
+ldap_pairget(LDAP * ld, LDAPMessage * entry,
+            TLDAP_RADIUS * item_map)
 {
-       BerElement *berptr;
-       char *attr;
-       char **vals;
-       char *ptr;
-       TLDAP_RADIUS *element;
-       int token;
-       char value[64];
-       VALUE_PAIR *pairlist;
-       VALUE_PAIR *newpair = NULL;
+       BerElement     *berptr;
+       char           *attr;
+       char          **vals;
+       char           *ptr;
+       TLDAP_RADIUS   *element;
+       int             token;
+       char            value[64];
+       VALUE_PAIR     *pairlist;
+       VALUE_PAIR     *newpair = NULL;
        pairlist = NULL;
-
        if ((attr = ldap_first_attribute(ld, entry, &berptr)) == NULL) {
                DEBUG("rlm_ldap: Object has no attributes");
                return NULL;
        }
-       
        do {
-               for(element=item_map; element->attr != NULL; element++) {
-                       if(!strncasecmp(attr,element->attr,strlen(element->attr))) {
-                               if(((vals = ldap_get_values(ld, entry, attr)) == NULL) ||
-                                  (ldap_count_values(vals) > 1)) {
+               for (element = item_map; element->attr != NULL; element++) {
+                       if (!strncasecmp(attr, element->attr, strlen(element->attr))) {
+                               if (((vals = ldap_get_values(ld, entry, attr)) == NULL) ||
+                                   (ldap_count_values(vals) > 1)) {
                                        DEBUG("rlm_ldap: Attribute %s has multiple values", attr);
                                        break;
                                }
                                ptr = vals[0];
                                token = gettoken(&ptr, value, sizeof(value));
                                if (token < T_EQSTART || token > T_EQEND) {
-                                       token = T_OP_EQ;        
+                                       token = T_OP_EQ;
                                } else {
                                        gettoken(&ptr, value, sizeof(value));
                                }
@@ -722,29 +677,29 @@ static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
                                        break;
                                }
                                DEBUG("rlm_ldap: Adding %s as %s, value %s & op=%d", attr, element->radius_attr, value, token);
-                               if((newpair = pairmake(element->radius_attr, value, token)) == NULL)
+                               if ((newpair = pairmake(element->radius_attr, value, token)) == NULL)
                                        continue;
                                pairadd(&pairlist, newpair);
                                ldap_value_free(vals);
                        }
                }
        } while ((attr = ldap_next_attribute(ld, entry, berptr)) != NULL);
-       
+
        ber_free(berptr, 0);
-       return(pairlist);
+       return (pairlist);
 }
 
 /* globally exported name */
-module_t rlm_ldap = {
+module_t        rlm_ldap = {
        "LDAP",
-       RLM_TYPE_THREAD_UNSAFE,         /* type: not thread safe */
-       NULL,                           /* initialization */
-       rlm_ldap_instantiate,           /* instantiation */
-       rlm_ldap_authorize,             /* authorization */
-       rlm_ldap_authenticate,          /* authentication */
-       NULL,                           /* preaccounting */
-       NULL,                           /* accounting */
-       NULL,                           /* checksimul */
-       rlm_ldap_detach,                /* detach */
-       NULL,                           /* destroy */
+       RLM_TYPE_THREAD_UNSAFE, /* type: reserved        */
+       NULL,                   /* initialization        */
+       ldap_instantiate,       /* instantiation         */
+       ldap_authorize,         /* authorization         */
+       ldap_authenticate,      /* authentication        */
+       NULL,                   /* preaccounting         */
+       NULL,                   /* accounting            */
+       NULL,                   /* checksimul            */
+       ldap_detach,            /* detach                */
+       NULL,                   /* destroy               */
 };